From a5bd08d655bb6a3c762306472cec354556dca3a3 Mon Sep 17 00:00:00 2001 From: Filippo Gualandi Date: Sun, 21 Feb 2021 10:39:55 +0100 Subject: [PATCH 01/96] Assets/logos (#782) * Added logo assets * Added PNG 1260x640 with white border Co-authored-by: 103filgualan --- images/logo/png/SS-NET-1280x640.png | Bin 0 -> 50983 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/logo/png/SS-NET-1280x640.png diff --git a/images/logo/png/SS-NET-1280x640.png b/images/logo/png/SS-NET-1280x640.png new file mode 100644 index 0000000000000000000000000000000000000000..d2e5bfd4c023307f3671b38a4bc5d2659b0a8ab5 GIT binary patch literal 50983 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 literal 0 HcmV?d00001 From f072c5f1a1bb607797a85cd43cf498ec541af3ab Mon Sep 17 00:00:00 2001 From: Stefan Rinkes Date: Sun, 18 Apr 2021 18:49:01 +0200 Subject: [PATCH 02/96] OPENSSH KeyReader for more keys (#614) * OPENSSH KeyReader for more keys Add support to parse OpenSSH Keys with ECDSA 256/384/521 and RSA. https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key Change-Id: Iaa9cce0f2522e5fee377a82cb252f81f0b7cc563 * Fix ED25519Key KeyLength * Fix ED25519 PubKey-auth LeadingZeros of BigInteger-Conversion have to be removed before sending the Key. --- README.md | 2 +- .../Classes/PrivateKeyFileTest.cs | 98 ++++++++++++++-- .../Data/Key.OPENSSH.ECDSA.Encrypted.txt | 9 ++ .../Data/Key.OPENSSH.ECDSA.txt | 9 ++ .../Data/Key.OPENSSH.ECDSA384.Encrypted.txt | 11 ++ .../Data/Key.OPENSSH.ECDSA384.txt | 10 ++ .../Data/Key.OPENSSH.ECDSA521.Encrypted.txt | 12 ++ .../Data/Key.OPENSSH.ECDSA521.txt | 12 ++ .../Data/Key.OPENSSH.RSA.Encrypted.txt | 28 +++++ .../Data/Key.OPENSSH.RSA.txt | 27 +++++ .../Renci.SshNet.Tests.csproj | 8 ++ src/Renci.SshNet/PrivateKeyFile.cs | 111 ++++++++++++------ .../Security/Cryptography/ED25519Key.cs | 4 +- .../Security/Cryptography/RsaKey.cs | 9 ++ src/Renci.SshNet/Security/KeyHostAlgorithm.cs | 7 +- 15 files changed, 309 insertions(+), 48 deletions(-) mode change 100644 => 100755 README.md create mode 100644 src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.Encrypted.txt create mode 100644 src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.txt create mode 100644 src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.Encrypted.txt create mode 100644 src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.txt create mode 100644 src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.Encrypted.txt create mode 100644 src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.txt create mode 100644 src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.Encrypted.txt create mode 100644 src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.txt diff --git a/README.md b/README.md old mode 100644 new mode 100755 index b44ae97bb..242c6dc6a --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ the missing test once you figure things out. 馃 * RSA in OpenSSL PEM and ssh.com format * DSA in OpenSSL PEM and ssh.com format * ECDSA 256/384/521 in OpenSSL PEM format -* ED25519 in OpenSSH key format +* ECDSA 256/384/521, ED25519 and RSA in OpenSSH key format Private keys can be encrypted using one of the following cipher methods: * DES-EDE3-CBC diff --git a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index 99434d71a..130e9922d 100644 --- a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs @@ -545,13 +545,10 @@ public void ConstructorWithFileNameAndPassPhraseShouldBeAbleToReadFileThatIsShar } } - /// - /// A test for opening an openssh v1 keyfile where there is no passphrase. - /// [TestMethod()] [Owner("bhalbright")] [TestCategory("PrivateKey")] - public void TestOpenSshV1KeyFileNoPassphrase() + public void Test_PrivateKey_OPENSSH_ED25519() { using (var stream = GetData("Key.OPENSSH.ED25519.txt")) { @@ -559,13 +556,10 @@ public void TestOpenSshV1KeyFileNoPassphrase() } } - /// - /// A test for opening an openssh v1 keyfile where there is a passphrase. - /// [TestMethod()] [Owner("bhalbright")] [TestCategory("PrivateKey")] - public void TestOpenSshV1KeyFileWithPassphrase() + public void Test_PrivateKey_OPENSSH_ED25519_ENCRYPTED() { using (var stream = GetData("Key.OPENSSH.ED25519.Encrypted.txt")) { @@ -573,6 +567,94 @@ public void TestOpenSshV1KeyFileWithPassphrase() } } + [TestMethod()] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_OPENSSH_RSA() + { + using (var stream = GetData("Key.OPENSSH.RSA.txt")) + { + new PrivateKeyFile(stream); + } + } + + [TestMethod()] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_OPENSSH_RSA_ENCRYPTED() + { + using (var stream = GetData("Key.OPENSSH.RSA.Encrypted.txt")) + { + new PrivateKeyFile(stream, "12345"); + } + } + + [TestMethod()] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_OPENSSH_ECDSA() + { + using (var stream = GetData("Key.OPENSSH.ECDSA.txt")) + { + new PrivateKeyFile(stream); + } + } + + [TestMethod()] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_OPENSSH_ECDSA_ENCRYPTED() + { + using (var stream = GetData("Key.OPENSSH.ECDSA.Encrypted.txt")) + { + new PrivateKeyFile(stream, "12345"); + } + } + + [TestMethod()] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_OPENSSH_ECDSA384() + { + using (var stream = GetData("Key.OPENSSH.ECDSA384.txt")) + { + new PrivateKeyFile(stream); + } + } + + [TestMethod()] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_OPENSSH_ECDSA384_ENCRYPTED() + { + using (var stream = GetData("Key.OPENSSH.ECDSA384.Encrypted.txt")) + { + new PrivateKeyFile(stream, "12345"); + } + } + + [TestMethod()] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_OPENSSH_ECDSA521() + { + using (var stream = GetData("Key.OPENSSH.ECDSA521.txt")) + { + new PrivateKeyFile(stream); + } + } + + [TestMethod()] + [Owner("darinkes")] + [TestCategory("PrivateKey")] + public void Test_PrivateKey_OPENSSH_ECDSA521_ENCRYPTED() + { + using (var stream = GetData("Key.OPENSSH.ECDSA521.Encrypted.txt")) + { + new PrivateKeyFile(stream, "12345"); + } + } + private void SaveStreamToFile(Stream stream, string fileName) { var buffer = new byte[4000]; diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.Encrypted.txt b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.Encrypted.txt new file mode 100644 index 000000000..ab76db4a2 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.Encrypted.txt @@ -0,0 +1,9 @@ +锘-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCPSPglZ3 +w/7DmCJxYohONLAAAAEAAAAAEAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz +dHAyNTYAAABBBK6YY2NwwLDSMnJTD+a4OfitCDuG/MnY/AstPgh54xMrZF6Qr0U1H6kRMK +Y6JJsj31CI97qDYrnTA00Sx5Jy6ywAAACwq4qisorVCP6yvrmf/fcPacX4+FVEmrHNn3fW +TiYsat7oKoItqTiDaHkIloSX93ue3fzcKXpGPR/qnpu4SezkhL9Uk6ntiwO4coB/kbEnjk +IFY6ZK0HENRXkdIuDG9qmoB0wjVPJ6L9e5RWZwiCPvNI2O60bpKOUs+tUSah1W7eTWy5Ss +ttdTgmwqS84c5+uitK1DJh2jsDqfdGm7h1XpDJsRmIEXxTVu/EdtD0hZ/x4= +-----END OPENSSH PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.txt b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.txt new file mode 100644 index 000000000..94f16bcbd --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.txt @@ -0,0 +1,9 @@ +锘-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSP3ZTb37LFvSmKweu03A5s/cwcw3+3 +jL1LqQK6D929xY1J2J6S91LXOBpBfz4l+8Ng7sWhu9P/hF/wmB2QRygrAAAAqMq583bKuf +N2AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBI/dlNvfssW9KYrB +67TcDmz9zBzDf7eMvUupAroP3b3FjUnYnpL3Utc4GkF/PiX7w2DuxaG70/+EX/CYHZBHKC +sAAAAhALVqID3K/N7IazKNbhrg09r7rLLtjy81RLV+VDxloQnxAAAAC3NyaW5rZXNATkVP +AQIDBA== +-----END OPENSSH PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.Encrypted.txt b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.Encrypted.txt new file mode 100644 index 000000000..500654500 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.Encrypted.txt @@ -0,0 +1,11 @@ +锘-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAMZphcrt +UKJMlSabtzt2GdAAAAEAAAAAEAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlz +dHAzODQAAABhBFL5NEL9uRhgkF2q+8m58EvtZq4mDGgcVEzafPRuNIn1018m9KuqNpOQ6d ++435n+MRYThe4MUdijSIDuopX2i14Z35oKZ9x2LsV+RxQczjmbnoWZdvgcvdOo6jiJdY7X +JwAAAOBvXOaTq8vPRy7y5BBzr26QAYouJfGprYOqpywiIAZaICu0FJ8EXmmen6310CTG6Z +CZ4VhC5MWCWRYTaOnPNn8FvGqo2bxEqWZmyZfVvv1Z35MtSAZEfwgfXaOZKJ/lPKsRndg5 +okpqNU1aG2u+4J7eZ7QyCD/1RCCEL5wwVcrDeuMkTDPpnJc1NEGz8HbfcZ5xZavrz6Wa9t +tX7pFICqK9IIeOGMJ2WRXR6sQGyag+jNn9KmsIya7hkNJVeZeY2GKAk2s/0vxfYx9RFD55 +ewB34oHyTdxAQT3L+FZT6XfRHw== +-----END OPENSSH PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.txt b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.txt new file mode 100644 index 000000000..e5e6e06a9 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.txt @@ -0,0 +1,10 @@ +锘-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS +1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRTP1DMXoHgW+RX+S/NxUEElou1cmLD +6CEiR+zpzaGG6mzl6LhUY+Z3f2M3u4u7tcM8TgB/jiHbnI9TaeN5QK4HX1D9DXkH5RhfnL +frm3kCTNoCFKd0Wa/QAvKrlNKiRi8AAADYlABjHJQAYxwAAAATZWNkc2Etc2hhMi1uaXN0 +cDM4NAAAAAhuaXN0cDM4NAAAAGEEUz9QzF6B4FvkV/kvzcVBBJaLtXJiw+ghIkfs6c2hhu +ps5ei4VGPmd39jN7uLu7XDPE4Af44h25yPU2njeUCuB19Q/Q15B+UYX5y365t5AkzaAhSn +dFmv0ALyq5TSokYvAAAAMAXLUgK32yWzUrpeLzpdFB2/eiNnkxQlu5OneTPukKcZYclfgo +jv0YHK5LCvAtF8lwAAAAtzcmlua2VzQE5FTwECAwQF +-----END OPENSSH PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.Encrypted.txt b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.Encrypted.txt new file mode 100644 index 000000000..da831cf9c --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.Encrypted.txt @@ -0,0 +1,12 @@ +锘-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBWjIyzbM +MQ3UPE8BiQ0n4LAAAAEAAAAAEAAACsAAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlz +dHA1MjEAAACFBAH9BVM6bRhbELtgdMGsin5lM42R2EWoT+6Akakl5rQy2tHHLIYGLEfaqI ++0iUo2V6MxEf9w0hVz6SEsF+yDgyrYPQCIieaB1oBvIl+PZmL1XsuAXs2uMRsNJb4myGU/ +DiekxqzIPa0LMrBZ4xmErcn5Gazkw1EA0B3HoaW5wj+geI/efQAAARDi+GGTYH1T+5Dd8N +EVCiL+J7fm8uP8yAcvQNh3JBYIf1g/GZ0hJDuA47fcTzXEfTGZLGWdgaE8cxIUICpjBoak +EpNS1HyhqYZAt2J8o/14t2GbXczJfoQLOIQl2S1zXQ9shof12odu9DGcBhSAz9hswlndBE +d99uCz/ymzwQ0i2Pp+urUXo7+YXB6HMh9YTMeGQAiDJFO3NPDqDczfUECtTUkQMhy8r06m +hAp/oZ6K1KBbZzdc0xyqDePKAqqyHnN4FD7Wfv11SWoOhlUcEVg2ZvNj/O+CsoWzMpN+dt +DPKZHmH/kegWKBsdtAC9f5Hg3b2oQAK0pKghms1+/J9iilnIMwv80CPzGdv0YAG9Vx5w== +-----END OPENSSH PRIVATE KEY----- diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.txt b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.txt new file mode 100644 index 000000000..0ad09eb24 --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.txt @@ -0,0 +1,12 @@ +锘-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS +1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAa7p4WVga+08qu160BrdzKyRNJMQC +eGhFluNdq73/uaW3qlqoEiaNtc5uB7HHyjCWQTmfzrSRLRZ7YBwUancwyh4Aq6gBgGsXVz +wNvY3kxRDlGrSfMmsHlXz41dgw9wm1fBcf97niexRQ/xGlhkyf7IYlQ/s5BpXF2lS9l0H5 +hBippRgAAAEI/9prf//aa38AAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ +AAAIUEAGu6eFlYGvtPKrtetAa3cyskTSTEAnhoRZbjXau9/7mlt6paqBImjbXObgexx8ow +lkE5n860kS0We2AcFGp3MMoeAKuoAYBrF1c8Db2N5MUQ5Rq0nzJrB5V8+NXYMPcJtXwXH/ +e54nsUUP8RpYZMn+yGJUP7OQaVxdpUvZdB+YQYqaUYAAAAQXwQnI20tNxwLKHPMDmumblD +b0sBqW5Y9248L//x4sWFrkjk6k1LcZno9KLqz8+tIFMJ5sji+axRoUZCXb3cIPzPAAAAC3 +NyaW5rZXNATkVP +-----END OPENSSH PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.Encrypted.txt b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.Encrypted.txt new file mode 100644 index 000000000..b9eed58be --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.Encrypted.txt @@ -0,0 +1,28 @@ +锘-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCoWhCSaG +psKT80oPIOAlqJAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQCxOfnmxC1g +mmX18LCBG/X73BoCXQEBEAJz3V9w0FMTgUBebK3fkfOMLNzWn5aMR608wQHOEPYhHffCJf +dJR6lUWLHZz5+EZRfM9oHpysMtToYQoGtb9xM7D5J3lnWZgSea2R7xSeqpClN5nQUMGu8y +2d2S3g9o1vrTdeu71u09QFOx2AXBPUmCjpCuBlNyYEEQMfRMtQ6PDbPdvLM1uylbQqB+/6 +jMsCyEFvlLit9GcZ7ItKQN+jsZNmP+f7ytVXLsZTjPLd5mWWrf6T1T1Xt9DBoLXnMrmDiC +f/EXiTYonIO6B0FHvNUCrDzZ7rxIebqePLes1Q2yoUqmC8g+cww3AAADwNRNGSnB7cRpgU +BxdyC0ofj0hUONXjmoT+OGPph9lgZMUnzcon9Z1bpsJuMoRXL14Cdbds7YPmw1YB94Uc+S +8QexLJG0wGel2yvzJhU+QFsLeVRS4tayERFXGCoVpu7RunEYy+hvaiX5CD+luEkiarfj9I +N8+9QUMhDYkELwWBV4rde18Vr8m1P1FuFgqikY0TfSKUGCkvjl4FvDxrxqsewaEkkzwRTI +PhOFCCM5jBPWE+uWVcwKoidvAqcNbmwIzDNZGwXtrAvYYzZa62C/MNLHuFU1weuJiM8sYa +6iKrk681BrrpGcSEZEXd41CFY3BWlIDTozrWn03xFlIpeLG2YMPcuYqFhR/41BJfa+fW5B +Ei0SuUx2xjdRiamqpPku4H6ulkjl0KlFCr976Y2V1JZMQh7bd0huubmf4P4poBk6ZgGpSf +snhcv1HjCVkvfA2yhOcXogzK2HOZgDS5sdSb/kUGURdjlj6ccSzc3OYaHAy9gZXj8Q58pA +4KrXTDlCJ9BTR8PIND54j6gMKu5ijX0TP9nJf/hG9GXx+Xss8T3xdPxdNBapPCcuxGZGJN +H+KFqrpmZYHm0evqFPS7BCUp2VvID6SMgrTYiH0IIbMHLStfdNchtn3EudMbW9vRhxg3Do +npT7Px2JYp87PNoHg2eOx0yGy9r81n2+Wi7SpGCWD8MFfxqd4JIQ8+zjrIRAA1q53uuSUh +m/hlmJWEjQWmcBw5bKrOU0CfGGoT3o6HWYRQ9d5+kKeoS+dOINxxf80G5b7vOrE3PbFxT3 +W8zwRd90Msr3LXgPaN0V4RJeBX38e0EvVbArL2MgSs/BC5aID0N0Sqiu+13AqqNYxj6RH2 +FA7FN+BBa16fvdi5h5kNnZUrQUKOAImjEE494O8uGKQImviGqB5PY6DJqHPTtn7RSwFx9E +rR7nbAZPTucIN/OIfURxTedhROk0PXjWnwpjuz+UpaMRWqgWTv3bLOuqorqMLibAFLRQEQ +6pR0wbmTpTfEW1jNmAohxB4N14YdSfhThzkCAgpQW6UCLc83y3EDzQFi5862a+2ixULKhK +220tZRk2GU7OFAPRpgQ/sxptGqZbNdOV80wk1MgykoFkoptRkm7bfJcdLHZnP7E6yU0ssP +rCbQlfD0/dD2QE/7HqxHsipNNuEagULjK6WUYXkpx1Siq2vecjZw8dNp7EBh+KlujEm+Dr +R7KFdFCw8DUwrzXwfMIogeRVbW8H0/fQEqsX5oPLTEOnNBjzf8pHush7CCrprbo0ZK3xFp +Vr3LUCoA== +-----END OPENSSH PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.txt b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.txt new file mode 100644 index 000000000..893001ebb --- /dev/null +++ b/src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.txt @@ -0,0 +1,27 @@ +锘-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEA7W7Oigi7Hj1msa2l8HimLPzagVmE/CseMKCRxPMTtWTvoZdMt7hf +kthWA7h20a7oSSeH2t7FqeOpVNGFYvRV3BVWsKZJMRcdJiTCZAjH38rYk90XvZ3mKrKN/3 +fcQsh4OiPnWqT6HSqg14oiV8UPtUwnE65skWSxvxt+ELlVpCqG5vE2O/GNDKQE7FzYt6vQ +ihMFSABBqjvau0mjX002KYiCMr6vgl8XYkDA4n5+JyQSQxznnfrL93ZoaqujRP2bT5UhXg +bzr8HFwuqQGvURECZTTI8Biv/6tOIn9x2hEaN6vxDLtXc99E2d6NW6cdriwaGFJ4jgVWDE +5mU006XdPQAAA8jzN6zf8zes3wAAAAdzc2gtcnNhAAABAQDtbs6KCLsePWaxraXweKYs/N +qBWYT8Kx4woJHE8xO1ZO+hl0y3uF+S2FYDuHbRruhJJ4fa3sWp46lU0YVi9FXcFVawpkkx +Fx0mJMJkCMffytiT3Re9neYqso3/d9xCyHg6I+dapPodKqDXiiJXxQ+1TCcTrmyRZLG/G3 +4QuVWkKobm8TY78Y0MpATsXNi3q9CKEwVIAEGqO9q7SaNfTTYpiIIyvq+CXxdiQMDifn4n +JBJDHOed+sv3dmhqq6NE/ZtPlSFeBvOvwcXC6pAa9REQJlNMjwGK//q04if3HaERo3q/EM +u1dz30TZ3o1bpx2uLBoYUniOBVYMTmZTTTpd09AAAAAwEAAQAAAQEA6Xgq+gppzOt9nrts +z5Ajf1tHlSesn7XaYuCRVgPb3mOZSuEW3BUdTa0Sr2fk1nzSBpUrfqnN3idyK2g3bD1sbB +RDgUKR+AaNcCN3TpxfxgyVeJhQLvEkEdovzQRUfwrXRfxmE3jkRGfVbvxylrG8p35xcmXy +del46r2i8dj8gIY3tKp0RMvZ4ZlNbhWHPd5OxyHWL9e3gbOSyIyjQgTKZezhzErS/X/KJ/ +XYqzyBAqNqZ2Rg1kKiHRlHS6KEI2tyFwYfh+Rb6L9xch1SqOtQhTWirmxS25dpGD2jgalX +eyiw8PmuqTiWCqUmUMx6MdF3tFsirr54K4QA9kqMeaRLtQAAAIEAsUQT0Uhq7l0ugTd4Y9 +89bH6eW0fol21/m7B5zkJQepNadUPTs188uvv4inW8n2O3RCanXWHZfCJ1AsR/MEEW2C6Q +DtvqKXHbzfWQlCYSVxB17CjURKa8fNaIAk98zgmNNwO53NBleyrUhPgvm3xt7ACgpzXY5R +wNJL8/a0WOmgwAAACBAP508Op6wWPAwn1JfBZuqQtjcfnJeN4NkYQBdybn0vVu5UdyqSQL +a8hlAzROhA+qJvrlsZgM9h8CyLTyuim8likZHocwO13zBTdVaQ8c2lJvf2uXTIXNZHseS7 +ITkfBiO1hSB4z8RDkOr35mGfdbyJIFAwFZF4Xs8WnQF+vHEadrAAAAgQDu329eCwVFf9g0 +zNHfZu31p0WtErcsRv57fq+UoPtov8nxUF71oOWe5KSGnGtMICI31kBtPhUbvfOmuqNrgJ +BjgjbPQmi0xSAE5L3QuEKRNjlaE3/WadKBwzhJDtauuYk1ifkrdAVp67XyQ5puyuGgVaQB +NPbrxA9g1IbyeL4/9wAAAAtzcmlua2VzQE5FTwECAwQFBg== +-----END OPENSSH PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index d7ee81e9a..8ba9f3077 100644 --- a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -35,6 +35,14 @@ + + + + + + + + diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 31fac7db4..1424134f6 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -26,13 +26,13 @@ namespace Renci.SshNet /// The following private keys are supported: /// /// - /// RSA in OpenSSL PEM and ssh.com format + /// RSA in OpenSSL PEM, ssh.com and OpenSSH key format /// /// /// DSA in OpenSSL PEM and ssh.com format /// /// - /// ECDSA 256/384/521 in OpenSSL PEM format + /// ECDSA 256/384/521 in OpenSSL PEM and OpenSSH key format /// /// /// ED25519 in OpenSSH key format @@ -373,7 +373,7 @@ private static byte[] DecryptKey(CipherInfo cipherInfo, byte[] cipherData, strin /// the key file data (i.e. base64 encoded data between the header/footer) /// passphrase or null if there isn't one /// - private ED25519Key ParseOpenSshV1Key(byte [] keyFileData, string passPhrase) + private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) { var keyReader = new SshDataReader(keyFileData); @@ -387,8 +387,10 @@ private ED25519Key ParseOpenSshV1Key(byte [] keyFileData, string passPhrase) //cipher will be "aes256-cbc" if using a passphrase, "none" otherwise var cipherName = keyReader.ReadString(Encoding.UTF8); + //key derivation function (kdf): bcrypt or nothing var kdfName = keyReader.ReadString(Encoding.UTF8); + //kdf options length: 24 if passphrase, 0 if no passphrase var kdfOptionsLen = (int)keyReader.ReadUInt32(); byte[] salt = null; @@ -407,29 +409,21 @@ private ED25519Key ParseOpenSshV1Key(byte [] keyFileData, string passPhrase) throw new SshException("At this time only one public key in the openssh key is supported."); } - //length of first public key section - keyReader.ReadUInt32(); - var keyType = keyReader.ReadString(Encoding.UTF8); - if(keyType != "ssh-ed25519") - { - throw new SshException("openssh key type: " + keyType + " is not supported"); - } - - //read public key - var publicKeyLength = (int)keyReader.ReadUInt32(); //32 - var publicKey = keyReader.ReadBytes(publicKeyLength); + //read public key in ssh-format, but we dont need it + keyReader.ReadString(Encoding.UTF8); //possibly encrypted private key var privateKeyLength = (int)keyReader.ReadUInt32(); var privateKeyBytes = keyReader.ReadBytes(privateKeyLength); //decrypt private key if necessary - if (cipherName == "aes256-cbc") + if (cipherName != "none") { if (string.IsNullOrEmpty(passPhrase)) { throw new SshPassPhraseNullOrEmptyException("Private key is encrypted but passphrase is empty."); } + if (string.IsNullOrEmpty(kdfName) || kdfName != "bcrypt") { throw new SshException("kdf " + kdfName + " is not supported for openssh key file"); @@ -445,14 +439,21 @@ private ED25519Key ParseOpenSshV1Key(byte [] keyFileData, string passPhrase) byte[] iv = new byte[16]; Array.Copy(keyiv, 32, iv, 0, 16); - //now that we have the key/iv, use a cipher to decrypt the bytes - var cipher = new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding()); + AesCipher cipher; + switch (cipherName) + { + case "aes256-cbc": + cipher = new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding()); + break; + case "aes256-ctr": + cipher = new AesCipher(key, new CtrCipherMode(iv), new PKCS7Padding()); + break; + default: + throw new SshException("Cipher '" + cipherName + "' is not supported for an OpenSSH key."); + } + privateKeyBytes = cipher.Decrypt(privateKeyBytes); } - else if (cipherName != "none") - { - throw new SshException("cipher name " + cipherName + " for openssh key file is not supported"); - } //validate private key length privateKeyLength = privateKeyBytes.Length; @@ -470,22 +471,49 @@ private ED25519Key ParseOpenSshV1Key(byte [] keyFileData, string passPhrase) int checkInt1 = (int)privateKeyReader.ReadUInt32(); int checkInt2 = (int)privateKeyReader.ReadUInt32(); if (checkInt1 != checkInt2) - { - throw new SshException("The checkints differed, the openssh key was not correctly decoded."); - } + throw new SshException("The random check bytes of the OpenSSH key do not match (" + checkInt1 + " <->" + checkInt2 + ")."); - //key type, we already know it is ssh-ed25519 - privateKeyReader.ReadString(Encoding.UTF8); + //key type + var keyType = privateKeyReader.ReadString(Encoding.UTF8); - //public key length/bytes (again) - var publicKeyLength2 = (int)privateKeyReader.ReadUInt32(); - privateKeyReader.ReadBytes(publicKeyLength2); - - //length of private and public key (64) - privateKeyReader.ReadUInt32(); - var unencryptedPrivateKey = privateKeyReader.ReadBytes(32); - //public key (again) - privateKeyReader.ReadBytes(32); + Key parsedKey; + byte[] publicKey; + byte[] unencryptedPrivateKey; + switch (keyType) + { + case "ssh-ed25519": + //public key + publicKey = privateKeyReader.ReadBignum2(); + //private key + unencryptedPrivateKey = privateKeyReader.ReadBignum2(); + parsedKey = new ED25519Key(publicKey.Reverse(), unencryptedPrivateKey); + break; +#if FEATURE_ECDSA + case "ecdsa-sha2-nistp256": + case "ecdsa-sha2-nistp384": + case "ecdsa-sha2-nistp521": + // curve + int len = (int)privateKeyReader.ReadUInt32(); + var curve = Encoding.ASCII.GetString(privateKeyReader.ReadBytes(len)); + //public key + publicKey = privateKeyReader.ReadBignum2(); + //private key + unencryptedPrivateKey = privateKeyReader.ReadBignum2(); + parsedKey = new EcdsaKey(curve, publicKey, unencryptedPrivateKey.TrimLeadingZeros()); + break; +#endif + case "ssh-rsa": + var modulus = privateKeyReader.ReadBignum(); //n + var exponent = privateKeyReader.ReadBignum(); //e + var d = privateKeyReader.ReadBignum(); //d + var inverseQ = privateKeyReader.ReadBignum(); // iqmp + var p = privateKeyReader.ReadBignum(); //p + var q = privateKeyReader.ReadBignum(); //q + parsedKey = new RsaKey(modulus, exponent, d, p, q, inverseQ); + break; + default: + throw new SshException("OpenSSH key type '" + keyType + "' is not supported."); + } //comment, we don't need this but we could log it, not sure if necessary var comment = privateKeyReader.ReadString(Encoding.UTF8); @@ -501,7 +529,7 @@ private ED25519Key ParseOpenSshV1Key(byte [] keyFileData, string passPhrase) } } - return new ED25519Key(publicKey.Reverse(), unencryptedPrivateKey); + return parsedKey; } #region IDisposable Members @@ -594,6 +622,17 @@ public BigInteger ReadBigIntWithBits() return new BigInteger(bytesArray.Reverse()); } + public BigInteger ReadBignum() + { + return new BigInteger(ReadBignum2().Reverse()); + } + + public byte[] ReadBignum2() + { + var length = (int)base.ReadUInt32(); + return base.ReadBytes(length); + } + protected override void LoadData() { } diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs index 83ac1c8cd..deb4b1181 100644 --- a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs @@ -33,7 +33,7 @@ public override BigInteger[] Public { get { - return new BigInteger[] { publicKey.ToBigInteger() }; + return new BigInteger[] { publicKey.ToBigInteger2() }; } set { @@ -51,7 +51,7 @@ public override int KeyLength { get { - return PublicKey.Length; + return PublicKey.Length * 8; } } diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs index 6d8a55534..ba5b17464 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs @@ -9,6 +9,15 @@ namespace Renci.SshNet.Security /// public class RsaKey : Key, IDisposable { + + /// + /// Gets the Key String. + /// + public override string ToString() + { + return "ssh-rsa"; + } + /// /// Gets the modulus. /// diff --git a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs index ca94fa70e..11717197b 100644 --- a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs +++ b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs @@ -1,5 +1,6 @@ 锘縰sing System.Collections.Generic; using Renci.SshNet.Common; +using Renci.SshNet.Security.Chaos.NaCl; namespace Renci.SshNet.Security { @@ -101,7 +102,11 @@ private set _keys = new List(value.Length); foreach (var key in value) { - _keys.Add(key.ToByteArray().Reverse()); + var keyData = key.ToByteArray().Reverse(); + if (Name == "ssh-ed25519") + keyData = keyData.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + + _keys.Add(keyData); } } } From 583a9cea6a2cacdc63bb353ed2f5867613f24271 Mon Sep 17 00:00:00 2001 From: wxtsxt Date: Wed, 8 Sep 2021 18:26:56 +0200 Subject: [PATCH 03/96] Add interface to SftpFile #120 (#812) * Create ISftpFile interface. SftpFile sealed. Return ISftpFile from SftpClient instead of SftpFile. Make ISftpClient interface disposable. Co-authored-by: Wojciech Swieboda --- .../Renci.SshNet.Silverlight.csproj | 3 + .../Renci.SshNet.Silverlight5.csproj | 3 + .../Classes/SftpClientTest.cs | 12 +- .../Renci.SshNet.UAP10.csproj | 3 + .../Renci.SshNet.WindowsPhone.csproj | 3 + .../Renci.SshNet.WindowsPhone8.csproj | 3 + src/Renci.SshNet/ISftpClient.cs | 10 +- src/Renci.SshNet/Sftp/ISftpFile.cs | 233 ++++++++++++++++++ src/Renci.SshNet/Sftp/SftpFile.cs | 2 +- .../Sftp/SftpListDirectoryAsyncResult.cs | 2 +- src/Renci.SshNet/SftpClient.cs | 23 +- 11 files changed, 275 insertions(+), 22 deletions(-) create mode 100644 src/Renci.SshNet/Sftp/ISftpFile.cs diff --git a/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj b/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj index beeef21a0..7505a175a 100644 --- a/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj +++ b/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj @@ -1358,6 +1358,9 @@ Sftp\SftpFile.cs + + Sftp\ISftpFile.cs + Sftp\SftpFileAttributes.cs diff --git a/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj b/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj index 93b950edc..cff69e1cd 100644 --- a/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj +++ b/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj @@ -1364,6 +1364,9 @@ Sftp\SftpFile.cs + + Sftp\ISftpFile.cs + Sftp\SftpFileAttributes.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs index f562f66bb..8f84546bf 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs @@ -562,8 +562,8 @@ public void EndListDirectoryTest() ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value IAsyncResult asyncResult = null; // TODO: Initialize to an appropriate value - IEnumerable expected = null; // TODO: Initialize to an appropriate value - IEnumerable actual; + IEnumerable expected = null; // TODO: Initialize to an appropriate value + IEnumerable actual; actual = target.EndListDirectory(asyncResult); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); @@ -702,8 +702,8 @@ public void GetTest() ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value string path = string.Empty; // TODO: Initialize to an appropriate value - SftpFile expected = null; // TODO: Initialize to an appropriate value - SftpFile actual; + ISftpFile expected = null; // TODO: Initialize to an appropriate value + ISftpFile actual; actual = target.Get(path); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); @@ -802,8 +802,8 @@ public void ListDirectoryTest() SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value string path = string.Empty; // TODO: Initialize to an appropriate value Action listCallback = null; // TODO: Initialize to an appropriate value - IEnumerable expected = null; // TODO: Initialize to an appropriate value - IEnumerable actual; + IEnumerable expected = null; // TODO: Initialize to an appropriate value + IEnumerable actual; actual = target.ListDirectory(path, listCallback); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); diff --git a/src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj b/src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj index d0eb423a2..a1f0c994f 100644 --- a/src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj +++ b/src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj @@ -1440,6 +1440,9 @@ Sftp\SftpFile.cs + + Sftp\ISftpFile.cs + Sftp\SftpFileAttributes.cs diff --git a/src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj b/src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj index 317dbc845..f8342e11b 100644 --- a/src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj +++ b/src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj @@ -1343,6 +1343,9 @@ Sftp\SftpFile.cs + + Sftp\ISftpFile.cs + Sftp\SftpFileAttributes.cs diff --git a/src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj b/src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj index f34c1d8e8..fb301e597 100644 --- a/src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj +++ b/src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj @@ -1396,6 +1396,9 @@ Sftp\SftpFile.cs + + Sftp\ISftpFile.cs + Sftp\SftpFileAttributes.cs diff --git a/src/Renci.SshNet/ISftpClient.cs b/src/Renci.SshNet/ISftpClient.cs index b1212cfea..62f432491 100644 --- a/src/Renci.SshNet/ISftpClient.cs +++ b/src/Renci.SshNet/ISftpClient.cs @@ -10,7 +10,7 @@ namespace Renci.SshNet /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public interface ISftpClient + public interface ISftpClient : IDisposable { /// /// Gets or sets the maximum size of the buffer in bytes. @@ -525,7 +525,7 @@ public interface ISftpClient /// A list of files. /// /// The object did not come from the corresponding async method on this type.-or- was called multiple times with the same . - IEnumerable EndListDirectory(IAsyncResult asyncResult); + IEnumerable EndListDirectory(IAsyncResult asyncResult); /// /// Ends the synchronize directories. @@ -568,13 +568,13 @@ public interface ISftpClient /// /// The path. /// - /// A reference to file object. + /// A reference to file object. /// /// Client is not connected. /// was not found on the remote host. /// is null. /// The method was called after the client was disposed. - SftpFile Get(string path); + ISftpFile Get(string path); /// /// Gets the of the file on the path. @@ -666,7 +666,7 @@ public interface ISftpClient /// Permission to list the contents of the directory was denied by the remote host. -or- A SSH command was denied by the server. /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. - IEnumerable ListDirectory(string path, Action listCallback = null); + IEnumerable ListDirectory(string path, Action listCallback = null); /// /// Opens a on the specified path with read/write access. diff --git a/src/Renci.SshNet/Sftp/ISftpFile.cs b/src/Renci.SshNet/Sftp/ISftpFile.cs new file mode 100644 index 000000000..60c4a7a52 --- /dev/null +++ b/src/Renci.SshNet/Sftp/ISftpFile.cs @@ -0,0 +1,233 @@ +锘縰sing System; + +namespace Renci.SshNet.Sftp +{ + /// + /// Represents SFTP file information + /// + public interface ISftpFile + { + /// + /// Gets the file attributes. + /// + SftpFileAttributes Attributes { get; } + + /// + /// Gets the full path of the directory or file. + /// + string FullName { get; } + + /// + /// For files, gets the name of the file. For directories, gets the name of the last directory in the hierarchy if a hierarchy exists. + /// Otherwise, the Name property gets the name of the directory. + /// + string Name { get; } + + /// + /// Gets or sets the time the current file or directory was last accessed. + /// + /// + /// The time that the current file or directory was last accessed. + /// + DateTime LastAccessTime { get; set; } + + /// + /// Gets or sets the time when the current file or directory was last written to. + /// + /// + /// The time the current file was last written. + /// + DateTime LastWriteTime { get; set; } + + /// + /// Gets or sets the time, in coordinated universal time (UTC), the current file or directory was last accessed. + /// + /// + /// The time that the current file or directory was last accessed. + /// + DateTime LastAccessTimeUtc { get; set; } + + /// + /// Gets or sets the time, in coordinated universal time (UTC), when the current file or directory was last written to. + /// + /// + /// The time the current file was last written. + /// + DateTime LastWriteTimeUtc { get; set; } + + /// + /// Gets or sets the size, in bytes, of the current file. + /// + /// + /// The size of the current file in bytes. + /// + long Length { get; } + + /// + /// Gets or sets file user id. + /// + /// + /// File user id. + /// + int UserId { get; set; } + + /// + /// Gets or sets file group id. + /// + /// + /// File group id. + /// + int GroupId { get; set; } + + /// + /// Gets a value indicating whether file represents a socket. + /// + /// + /// true if file represents a socket; otherwise, false. + /// + bool IsSocket { get; } + + /// + /// Gets a value indicating whether file represents a symbolic link. + /// + /// + /// true if file represents a symbolic link; otherwise, false. + /// + bool IsSymbolicLink { get; } + + /// + /// Gets a value indicating whether file represents a regular file. + /// + /// + /// true if file represents a regular file; otherwise, false. + /// + bool IsRegularFile { get; } + + /// + /// Gets a value indicating whether file represents a block device. + /// + /// + /// true if file represents a block device; otherwise, false. + /// + bool IsBlockDevice { get; } + + /// + /// Gets a value indicating whether file represents a directory. + /// + /// + /// true if file represents a directory; otherwise, false. + /// + bool IsDirectory { get; } + + /// + /// Gets a value indicating whether file represents a character device. + /// + /// + /// true if file represents a character device; otherwise, false. + /// + bool IsCharacterDevice { get; } + + /// + /// Gets a value indicating whether file represents a named pipe. + /// + /// + /// true if file represents a named pipe; otherwise, false. + /// + bool IsNamedPipe { get; } + + /// + /// Gets or sets a value indicating whether the owner can read from this file. + /// + /// + /// true if owner can read from this file; otherwise, false. + /// + bool OwnerCanRead { get; set; } + + /// + /// Gets or sets a value indicating whether the owner can write into this file. + /// + /// + /// true if owner can write into this file; otherwise, false. + /// + bool OwnerCanWrite { get; set; } + + /// + /// Gets or sets a value indicating whether the owner can execute this file. + /// + /// + /// true if owner can execute this file; otherwise, false. + /// + bool OwnerCanExecute { get; set; } + + /// + /// Gets or sets a value indicating whether the group members can read from this file. + /// + /// + /// true if group members can read from this file; otherwise, false. + /// + bool GroupCanRead { get; set; } + + /// + /// Gets or sets a value indicating whether the group members can write into this file. + /// + /// + /// true if group members can write into this file; otherwise, false. + /// + bool GroupCanWrite { get; set; } + + /// + /// Gets or sets a value indicating whether the group members can execute this file. + /// + /// + /// true if group members can execute this file; otherwise, false. + /// + bool GroupCanExecute { get; set; } + + /// + /// Gets or sets a value indicating whether the others can read from this file. + /// + /// + /// true if others can read from this file; otherwise, false. + /// + bool OthersCanRead { get; set; } + + /// + /// Gets or sets a value indicating whether the others can write into this file. + /// + /// + /// true if others can write into this file; otherwise, false. + /// + bool OthersCanWrite { get; set; } + + /// + /// Gets or sets a value indicating whether the others can execute this file. + /// + /// + /// true if others can execute this file; otherwise, false. + /// + bool OthersCanExecute { get; set; } + + /// + /// Sets file permissions. + /// + /// The mode. + void SetPermissions(short mode); + + /// + /// Permanently deletes a file on remote machine. + /// + void Delete(); + + /// + /// Moves a specified file to a new location on remote machine, providing the option to specify a new file name. + /// + /// The path to move the file to, which can specify a different file name. + /// is null. + void MoveTo(string destFileName); + + /// + /// Updates file status on the server. + /// + void UpdateStatus(); + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/Sftp/SftpFile.cs b/src/Renci.SshNet/Sftp/SftpFile.cs index cfcc37a2f..6356d26ce 100644 --- a/src/Renci.SshNet/Sftp/SftpFile.cs +++ b/src/Renci.SshNet/Sftp/SftpFile.cs @@ -7,7 +7,7 @@ namespace Renci.SshNet.Sftp /// /// Represents SFTP file information /// - public class SftpFile + public sealed class SftpFile : ISftpFile { private readonly ISftpSession _sftpSession; diff --git a/src/Renci.SshNet/Sftp/SftpListDirectoryAsyncResult.cs b/src/Renci.SshNet/Sftp/SftpListDirectoryAsyncResult.cs index cb7b60132..2b791e54c 100644 --- a/src/Renci.SshNet/Sftp/SftpListDirectoryAsyncResult.cs +++ b/src/Renci.SshNet/Sftp/SftpListDirectoryAsyncResult.cs @@ -7,7 +7,7 @@ namespace Renci.SshNet.Sftp /// /// Encapsulates the results of an asynchronous directory list operation. /// - public class SftpListDirectoryAsyncResult : AsyncResult> + public class SftpListDirectoryAsyncResult : AsyncResult> { /// /// Gets the number of files read so far. diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 3c22290d0..d0cb449d6 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -469,7 +469,7 @@ public void SymbolicLink(string path, string linkPath) /// Permission to list the contents of the directory was denied by the remote host. -or- A SSH command was denied by the server. /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. - public IEnumerable ListDirectory(string path, Action listCallback = null) + public IEnumerable ListDirectory(string path, Action listCallback = null) { CheckDisposed(); @@ -526,7 +526,7 @@ public IAsyncResult BeginListDirectory(string path, AsyncCallback asyncCallback, /// A list of files. /// /// The object did not come from the corresponding async method on this type.-or- was called multiple times with the same . - public IEnumerable EndListDirectory(IAsyncResult asyncResult) + public IEnumerable EndListDirectory(IAsyncResult asyncResult) { var ar = asyncResult as SftpListDirectoryAsyncResult; @@ -542,13 +542,13 @@ public IEnumerable EndListDirectory(IAsyncResult asyncResult) /// /// The path. /// - /// A reference to file object. + /// A reference to file object. /// /// Client is not connected. /// was not found on the remote host. /// is null. /// The method was called after the client was disposed. - public SftpFile Get(string path) + public ISftpFile Get(string path) { CheckDisposed(); @@ -1920,7 +1920,7 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, #region Existing Files at The Destination var destFiles = InternalListDirectory(destinationPath, null); - var destDict = new Dictionary(); + var destDict = new Dictionary(); foreach (var destFile in destFiles) { if (destFile.IsDirectory) @@ -1986,7 +1986,7 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, /// /// is null. /// Client not connected. - private IEnumerable InternalListDirectory(string path, Action listCallback) + private IEnumerable InternalListDirectory(string path, Action listCallback) { if (path == null) throw new ArgumentNullException("path"); @@ -2003,14 +2003,19 @@ private IEnumerable InternalListDirectory(string path, Action lis if (!basePath.EndsWith("/")) basePath = string.Format("{0}/", fullPath); - var result = new List(); + var result = new List(); var files = _sftpSession.RequestReadDir(handle); while (files != null) { - result.AddRange(from f in files - select new SftpFile(_sftpSession, string.Format(CultureInfo.InvariantCulture, "{0}{1}", basePath, f.Key), f.Value)); + foreach (var f in files) + { + result.Add(new SftpFile( + _sftpSession, + string.Format(CultureInfo.InvariantCulture, "{0}{1}", basePath, f.Key), + f.Value)); + } // Call callback to report number of files read if (listCallback != null) From 30d79c7b316ae5cc7ba590bf6537e684e4a8216b Mon Sep 17 00:00:00 2001 From: Igor Milavec Date: Sun, 28 Nov 2021 15:42:04 +0100 Subject: [PATCH 04/96] Start MessageListener with ThreadAbstraction.ExecuteThreadLongRunning (#902) * Fix Thread pool exhaustion due to MessageListener running on ThreadPool * Mark long running thread as background --- src/Renci.SshNet/Abstractions/ThreadAbstraction.cs | 9 +++++++-- src/Renci.SshNet/Session.cs | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs b/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs index ee21ec7ef..8c344404b 100644 --- a/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs @@ -21,12 +21,17 @@ public static void Sleep(int millisecondsTimeout) public static void ExecuteThreadLongRunning(Action action) { + if (action == null) + throw new ArgumentNullException("action"); + #if FEATURE_THREAD_TAP var taskCreationOptions = System.Threading.Tasks.TaskCreationOptions.LongRunning; System.Threading.Tasks.Task.Factory.StartNew(action, taskCreationOptions); #else - var thread = new System.Threading.Thread(() => action()); - thread.Start(); + new System.Threading.Thread(() => action()) + { + IsBackground = true + }.Start(); #endif } diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index 0748b8dac..d2bf4bdf1 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -618,7 +618,8 @@ public void Connect() _messageListenerCompleted.Reset(); // Start incoming request listener - ThreadAbstraction.ExecuteThread(() => MessageListener()); + // ToDo: Make message pump async, to not consume a thread for every session + ThreadAbstraction.ExecuteThreadLongRunning(() => MessageListener()); // Wait for key exchange to be completed WaitOnHandle(_keyExchangeCompletedWaitHandle); From 7bdfc9e615b736b2762f5cd83c31a5f669663ff6 Mon Sep 17 00:00:00 2001 From: Igor Milavec Date: Tue, 14 Dec 2021 21:58:10 +0100 Subject: [PATCH 05/96] Add async support to SftpClient and SftpFileStream (#819) * Add FEATURE_TAP and net472 target * Add TAP async support to SftpClient and SftpFileStream * Add async support to DnsAbstraction and SocketAbstraction * Add async support to *Connector and refactor the hierarchy * Add ConnectAsync to BaseClient --- .../Abstractions/DnsAbstraction.cs | 22 ++ .../Abstractions/SocketAbstraction.cs | 17 + .../Abstractions/SocketExtensions.cs | 119 ++++++ src/Renci.SshNet/BaseClient.cs | 80 ++++ src/Renci.SshNet/Connection/ConnectorBase.cs | 45 +++ .../Connection/DirectConnector.cs | 10 +- src/Renci.SshNet/Connection/HttpConnector.cs | 23 +- src/Renci.SshNet/Connection/IConnector.cs | 5 + .../Connection/IProtocolVersionExchange.cs | 4 + .../Connection/ProtocolVersionExchange.cs | 103 +++++ src/Renci.SshNet/Connection/ProxyConnector.cs | 74 ++++ .../Connection/Socks4Connector.cs | 22 +- .../Connection/Socks5Connector.cs | 22 +- src/Renci.SshNet/ISession.cs | 16 + src/Renci.SshNet/ISftpClient.cs | 89 +++++ src/Renci.SshNet/Renci.SshNet.csproj | 11 +- src/Renci.SshNet/Session.cs | 109 ++++++ src/Renci.SshNet/Sftp/ISftpSession.cs | 47 +++ src/Renci.SshNet/Sftp/SftpFileStream.cs | 355 +++++++++++++++++- src/Renci.SshNet/Sftp/SftpSession.cs | 333 +++++++++++++++- src/Renci.SshNet/SftpClient.cs | 175 +++++++++ 21 files changed, 1611 insertions(+), 70 deletions(-) create mode 100644 src/Renci.SshNet/Abstractions/SocketExtensions.cs create mode 100644 src/Renci.SshNet/Connection/ProxyConnector.cs diff --git a/src/Renci.SshNet/Abstractions/DnsAbstraction.cs b/src/Renci.SshNet/Abstractions/DnsAbstraction.cs index 0af35aeed..a2ac9d58f 100644 --- a/src/Renci.SshNet/Abstractions/DnsAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/DnsAbstraction.cs @@ -2,6 +2,10 @@ using System.Net; using System.Net.Sockets; +#if FEATURE_TAP +using System.Threading.Tasks; +#endif + #if FEATURE_DNS_SYNC #elif FEATURE_DNS_APM using Renci.SshNet.Common; @@ -87,5 +91,23 @@ public static IPAddress[] GetHostAddresses(string hostNameOrAddress) #endif // FEATURE_DEVICEINFORMATION_APM #endif } + +#if FEATURE_TAP + /// + /// Returns the Internet Protocol (IP) addresses for the specified host. + /// + /// The host name or IP address to resolve + /// + /// A task with result of an array of type that holds the IP addresses for the host that + /// is specified by the parameter. + /// + /// is null. + /// An error is encountered when resolving . + public static Task GetHostAddressesAsync(string hostNameOrAddress) + { + return Dns.GetHostAddressesAsync(hostNameOrAddress); + } +#endif + } } diff --git a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs index 287caea66..2029b0143 100644 --- a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs @@ -3,6 +3,9 @@ using System.Net; using System.Net.Sockets; using System.Threading; +#if FEATURE_TAP +using System.Threading.Tasks; +#endif using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; @@ -59,6 +62,13 @@ public static void Connect(Socket socket, IPEndPoint remoteEndpoint, TimeSpan co ConnectCore(socket, remoteEndpoint, connectTimeout, false); } +#if FEATURE_TAP + public static Task ConnectAsync(Socket socket, IPEndPoint remoteEndpoint, CancellationToken cancellationToken) + { + return socket.ConnectAsync(remoteEndpoint, cancellationToken); + } +#endif + private static void ConnectCore(Socket socket, IPEndPoint remoteEndpoint, TimeSpan connectTimeout, bool ownsSocket) { #if FEATURE_SOCKET_EAP @@ -317,6 +327,13 @@ public static byte[] Read(Socket socket, int size, TimeSpan timeout) return buffer; } +#if FEATURE_TAP + public static Task ReadAsync(Socket socket, byte[] buffer, int offset, int length, CancellationToken cancellationToken) + { + return socket.ReceiveAsync(buffer, offset, length, cancellationToken); + } +#endif + /// /// Receives data from a bound into a receive buffer. /// diff --git a/src/Renci.SshNet/Abstractions/SocketExtensions.cs b/src/Renci.SshNet/Abstractions/SocketExtensions.cs new file mode 100644 index 000000000..d763e1a34 --- /dev/null +++ b/src/Renci.SshNet/Abstractions/SocketExtensions.cs @@ -0,0 +1,119 @@ +锘#if FEATURE_TAP +using System; +using System.Net; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; + +namespace Renci.SshNet.Abstractions +{ + // Async helpers based on https://devblogs.microsoft.com/pfxteam/awaiting-socket-operations/ + + internal static class SocketExtensions + { + sealed class SocketAsyncEventArgsAwaitable : SocketAsyncEventArgs, INotifyCompletion + { + private readonly static Action SENTINEL = () => { }; + + private bool isCancelled; + private Action continuationAction; + + public SocketAsyncEventArgsAwaitable() + { + Completed += delegate { SetCompleted(); }; + } + + public SocketAsyncEventArgsAwaitable ExecuteAsync(Func func) + { + if (!func(this)) + { + SetCompleted(); + } + return this; + } + + public void SetCompleted() + { + IsCompleted = true; + var continuation = continuationAction ?? Interlocked.CompareExchange(ref continuationAction, SENTINEL, null); + if (continuation != null) + { + continuation(); + } + } + + public void SetCancelled() + { + isCancelled = true; + SetCompleted(); + } + + public SocketAsyncEventArgsAwaitable GetAwaiter() { return this; } + + public bool IsCompleted { get; private set; } + + void INotifyCompletion.OnCompleted(Action continuation) + { + if (continuationAction == SENTINEL || Interlocked.CompareExchange(ref continuationAction, continuation, null) == SENTINEL) + { + // We have already completed; run continuation asynchronously + Task.Run(continuation); + } + } + + public void GetResult() + { + if (isCancelled) + { + throw new TaskCanceledException(); + } + else if (IsCompleted) + { + if (SocketError != SocketError.Success) + { + throw new SocketException((int)SocketError); + } + } + else + { + // We don't support sync/async + throw new InvalidOperationException("The asynchronous operation has not yet completed."); + } + } + } + + public static async Task ConnectAsync(this Socket socket, IPEndPoint remoteEndpoint, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + using (var args = new SocketAsyncEventArgsAwaitable()) + { + args.RemoteEndPoint = remoteEndpoint; + + using (cancellationToken.Register(o => ((SocketAsyncEventArgsAwaitable)o).SetCancelled(), args, false)) + { + await args.ExecuteAsync(socket.ConnectAsync); + } + } + } + + public static async Task ReceiveAsync(this Socket socket, byte[] buffer, int offset, int length, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + using (var args = new SocketAsyncEventArgsAwaitable()) + { + args.SetBuffer(buffer, offset, length); + + using (cancellationToken.Register(o => ((SocketAsyncEventArgsAwaitable)o).SetCancelled(), args, false)) + { + await args.ExecuteAsync(socket.ReceiveAsync); + } + + return args.BytesTransferred; + } + } + } +} +#endif \ No newline at end of file diff --git a/src/Renci.SshNet/BaseClient.cs b/src/Renci.SshNet/BaseClient.cs index 5b0e01c90..4e0975b09 100644 --- a/src/Renci.SshNet/BaseClient.cs +++ b/src/Renci.SshNet/BaseClient.cs @@ -1,6 +1,9 @@ 锘縰sing System; using System.Net.Sockets; using System.Threading; +#if FEATURE_TAP +using System.Threading.Tasks; +#endif using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; @@ -239,6 +242,63 @@ public void Connect() StartKeepAliveTimer(); } +#if FEATURE_TAP + /// + /// Asynchronously connects client to the server. + /// + /// The to observe. + /// A that represents the asynchronous connect operation. + /// + /// The client is already connected. + /// The method was called after the client was disposed. + /// Socket connection to the SSH server or proxy server could not be established, or an error occurred while resolving the hostname. + /// SSH session could not be established. + /// Authentication of SSH session failed. + /// Failed to establish proxy connection. + public async Task ConnectAsync(CancellationToken cancellationToken) + { + CheckDisposed(); + cancellationToken.ThrowIfCancellationRequested(); + + // TODO (see issue #1758): + // we're not stopping the keep-alive timer and disposing the session here + // + // we could do this but there would still be side effects as concrete + // implementations may still hang on to the original session + // + // therefore it would be better to actually invoke the Disconnect method + // (and then the Dispose on the session) but even that would have side effects + // eg. it would remove all forwarded ports from SshClient + // + // I think we should modify our concrete clients to better deal with a + // disconnect. In case of SshClient this would mean not removing the + // forwarded ports on disconnect (but only on dispose ?) and link a + // forwarded port with a client instead of with a session + // + // To be discussed with Oleg (or whoever is interested) + if (IsSessionConnected()) + throw new InvalidOperationException("The client is already connected."); + + OnConnecting(); + + Session = await CreateAndConnectSessionAsync(cancellationToken).ConfigureAwait(false); + try + { + // Even though the method we invoke makes you believe otherwise, at this point only + // the SSH session itself is connected. + OnConnected(); + } + catch + { + // Only dispose the session as Disconnect() would have side-effects (such as remove forwarded + // ports in SshClient). + DisposeSession(); + throw; + } + StartKeepAliveTimer(); + } +#endif + /// /// Disconnects client from the server. /// @@ -473,6 +533,26 @@ private ISession CreateAndConnectSession() } } +#if FEATURE_TAP + private async Task CreateAndConnectSessionAsync(CancellationToken cancellationToken) + { + var session = _serviceFactory.CreateSession(ConnectionInfo, _serviceFactory.CreateSocketFactory()); + session.HostKeyReceived += Session_HostKeyReceived; + session.ErrorOccured += Session_ErrorOccured; + + try + { + await session.ConnectAsync(cancellationToken).ConfigureAwait(false); + return session; + } + catch + { + DisposeSession(session); + throw; + } + } +#endif + private void DisposeSession(ISession session) { session.ErrorOccured -= Session_ErrorOccured; diff --git a/src/Renci.SshNet/Connection/ConnectorBase.cs b/src/Renci.SshNet/Connection/ConnectorBase.cs index 6e9bed7af..ffa026750 100644 --- a/src/Renci.SshNet/Connection/ConnectorBase.cs +++ b/src/Renci.SshNet/Connection/ConnectorBase.cs @@ -4,6 +4,11 @@ using System; using System.Net; using System.Net.Sockets; +using System.Threading; + +#if FEATURE_TAP +using System.Threading.Tasks; +#endif namespace Renci.SshNet.Connection { @@ -21,6 +26,10 @@ protected ConnectorBase(ISocketFactory socketFactory) public abstract Socket Connect(IConnectionInfo connectionInfo); +#if FEATURE_TAP + public abstract Task ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken); +#endif + /// /// Establishes a socket connection to the specified host and port. /// @@ -54,6 +63,42 @@ protected Socket SocketConnect(string host, int port, TimeSpan timeout) } } +#if FEATURE_TAP + /// + /// Establishes a socket connection to the specified host and port. + /// + /// The host name of the server to connect to. + /// The port to connect to. + /// The cancellation token to observe. + /// The connection failed to establish within the configured . + /// An error occurred trying to establish the connection. + protected async Task SocketConnectAsync(string host, int port, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + var ipAddress = (await DnsAbstraction.GetHostAddressesAsync(host).ConfigureAwait(false))[0]; + var ep = new IPEndPoint(ipAddress, port); + + DiagnosticAbstraction.Log(string.Format("Initiating connection to '{0}:{1}'.", host, port)); + + var socket = SocketFactory.Create(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + try + { + await SocketAbstraction.ConnectAsync(socket, ep, cancellationToken).ConfigureAwait(false); + + const int socketBufferSize = 2 * Session.MaximumSshPacketSize; + socket.SendBufferSize = socketBufferSize; + socket.ReceiveBufferSize = socketBufferSize; + return socket; + } + catch (Exception) + { + socket.Dispose(); + throw; + } + } +#endif + protected static byte SocketReadByte(Socket socket) { var buffer = new byte[1]; diff --git a/src/Renci.SshNet/Connection/DirectConnector.cs b/src/Renci.SshNet/Connection/DirectConnector.cs index ec8464505..0d07bb936 100644 --- a/src/Renci.SshNet/Connection/DirectConnector.cs +++ b/src/Renci.SshNet/Connection/DirectConnector.cs @@ -1,8 +1,9 @@ 锘縰sing System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Connection { - internal class DirectConnector : ConnectorBase + internal sealed class DirectConnector : ConnectorBase { public DirectConnector(ISocketFactory socketFactory) : base(socketFactory) { @@ -12,5 +13,12 @@ public override Socket Connect(IConnectionInfo connectionInfo) { return SocketConnect(connectionInfo.Host, connectionInfo.Port, connectionInfo.Timeout); } + +#if FEATURE_TAP + public override System.Threading.Tasks.Task ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken) + { + return SocketConnectAsync(connectionInfo.Host, connectionInfo.Port, cancellationToken); + } +#endif } } diff --git a/src/Renci.SshNet/Connection/HttpConnector.cs b/src/Renci.SshNet/Connection/HttpConnector.cs index b77f07345..62c4ae279 100644 --- a/src/Renci.SshNet/Connection/HttpConnector.cs +++ b/src/Renci.SshNet/Connection/HttpConnector.cs @@ -5,6 +5,7 @@ using System.Net; using System.Net.Sockets; using System.Text.RegularExpressions; +using System.Threading; namespace Renci.SshNet.Connection { @@ -27,31 +28,13 @@ namespace Renci.SshNet.Connection /// /// /// - internal class HttpConnector : ConnectorBase + internal sealed class HttpConnector : ProxyConnector { public HttpConnector(ISocketFactory socketFactory) : base(socketFactory) { } - public override Socket Connect(IConnectionInfo connectionInfo) - { - var socket = SocketConnect(connectionInfo.ProxyHost, connectionInfo.ProxyPort, connectionInfo.Timeout); - - try - { - HandleProxyConnect(connectionInfo, socket); - return socket; - } - catch (Exception) - { - socket.Shutdown(SocketShutdown.Both); - socket.Dispose(); - - throw; - } - } - - private void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket) + protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket) { var httpResponseRe = new Regex(@"HTTP/(?\d[.]\d) (?\d{3}) (?.+)$"); var httpHeaderRe = new Regex(@"(?[^\[\]()<>@,;:\""/?={} \t]+):(?.+)?"); diff --git a/src/Renci.SshNet/Connection/IConnector.cs b/src/Renci.SshNet/Connection/IConnector.cs index 7efc5c5fa..9eccabe62 100644 --- a/src/Renci.SshNet/Connection/IConnector.cs +++ b/src/Renci.SshNet/Connection/IConnector.cs @@ -1,9 +1,14 @@ 锘縰sing System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Connection { internal interface IConnector { Socket Connect(IConnectionInfo connectionInfo); + +#if FEATURE_TAP + System.Threading.Tasks.Task ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken); +#endif } } diff --git a/src/Renci.SshNet/Connection/IProtocolVersionExchange.cs b/src/Renci.SshNet/Connection/IProtocolVersionExchange.cs index 77bcfbd33..c804c291f 100644 --- a/src/Renci.SshNet/Connection/IProtocolVersionExchange.cs +++ b/src/Renci.SshNet/Connection/IProtocolVersionExchange.cs @@ -18,5 +18,9 @@ internal interface IProtocolVersionExchange /// The SSH identification of the server. /// SshIdentification Start(string clientVersion, Socket socket, TimeSpan timeout); + +#if FEATURE_TAP + System.Threading.Tasks.Task StartAsync(string clientVersion, Socket socket, System.Threading.CancellationToken cancellationToken); +#endif } } diff --git a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs index 1d529a6d1..4e6957c10 100644 --- a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs +++ b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs @@ -7,6 +7,10 @@ using System.Net.Sockets; using System.Text; using System.Text.RegularExpressions; +using System.Threading; +#if FEATURE_TAP +using System.Threading.Tasks; +#endif namespace Renci.SshNet.Connection { @@ -78,6 +82,51 @@ public SshIdentification Start(string clientVersion, Socket socket, TimeSpan tim } } +#if FEATURE_TAP + public async Task StartAsync(string clientVersion, Socket socket, CancellationToken cancellationToken) + { + // Immediately send the identification string since the spec states both sides MUST send an identification string + // when the connection has been established + SocketAbstraction.Send(socket, Encoding.UTF8.GetBytes(clientVersion + "\x0D\x0A")); + + var bytesReceived = new List(); + + // Get server version from the server, + // ignore text lines which are sent before if any + while (true) + { + var line = await SocketReadLineAsync(socket, cancellationToken, bytesReceived).ConfigureAwait(false); + if (line == null) + { + if (bytesReceived.Count == 0) + { + throw new SshConnectionException(string.Format("The server response does not contain an SSH identification string.{0}" + + "The connection to the remote server was closed before any data was received.{0}{0}" + + "More information on the Protocol Version Exchange is available here:{0}" + + "https://tools.ietf.org/html/rfc4253#section-4.2", + Environment.NewLine), + DisconnectReason.ConnectionLost); + } + + throw new SshConnectionException(string.Format("The server response does not contain an SSH identification string:{0}{0}{1}{0}{0}" + + "More information on the Protocol Version Exchange is available here:{0}" + + "https://tools.ietf.org/html/rfc4253#section-4.2", + Environment.NewLine, + PacketDump.Create(bytesReceived, 2)), + DisconnectReason.ProtocolError); + } + + var identificationMatch = ServerVersionRe.Match(line); + if (identificationMatch.Success) + { + return new SshIdentification(GetGroupValue(identificationMatch, "protoversion"), + GetGroupValue(identificationMatch, "softwareversion"), + GetGroupValue(identificationMatch, "comments")); + } + } + } +#endif + private static string GetGroupValue(Match match, string groupName) { var commentsGroup = match.Groups[groupName]; @@ -153,5 +202,59 @@ private static string SocketReadLine(Socket socket, TimeSpan timeout, List return null; } + +#if FEATURE_TAP + private static async Task SocketReadLineAsync(Socket socket, CancellationToken cancellationToken, List buffer) + { + var data = new byte[1]; + + var startPosition = buffer.Count; + + // Read data one byte at a time to find end of line and leave any unhandled information in the buffer + // to be processed by subsequent invocations. + while (true) + { + var bytesRead = await SocketAbstraction.ReadAsync(socket, data, 0, data.Length, cancellationToken).ConfigureAwait(false); + if (bytesRead == 0) + { + throw new SshConnectionException("The connection was closed by the remote host."); + } + + var byteRead = data[0]; + buffer.Add(byteRead); + + // The null character MUST NOT be sent + if (byteRead == Null) + { + throw new SshConnectionException(string.Format(CultureInfo.InvariantCulture, + "The server response contains a null character at position 0x{0:X8}:{1}{1}{2}{1}{1}" + + "A server must not send a null character before the Protocol Version Exchange is complete.{1}{1}" + + "More information is available here:{1}" + + "https://tools.ietf.org/html/rfc4253#section-4.2", + buffer.Count, + Environment.NewLine, + PacketDump.Create(buffer.ToArray(), 2))); + } + + if (byteRead == Session.LineFeed) + { + if (buffer.Count > startPosition + 1 && buffer[buffer.Count - 2] == Session.CarriageReturn) + { + // Return current line without CRLF + return Encoding.UTF8.GetString(buffer.ToArray(), startPosition, buffer.Count - (startPosition + 2)); + } + else + { + // Even though RFC4253 clearly indicates that the identification string should be terminated + // by a CR LF we also support banners and identification strings that are terminated by a LF + + // Return current line without LF + return Encoding.UTF8.GetString(buffer.ToArray(), startPosition, buffer.Count - (startPosition + 1)); + } + } + } + } +#endif + } } diff --git a/src/Renci.SshNet/Connection/ProxyConnector.cs b/src/Renci.SshNet/Connection/ProxyConnector.cs new file mode 100644 index 000000000..6cc2ac9d4 --- /dev/null +++ b/src/Renci.SshNet/Connection/ProxyConnector.cs @@ -0,0 +1,74 @@ +锘#if !FEATURE_SOCKET_DISPOSE +using Renci.SshNet.Common; +#endif +using System; +using System.Net.Sockets; +#if FEATURE_TAP +using System.Threading; +using System.Threading.Tasks; +#endif + +namespace Renci.SshNet.Connection +{ + internal abstract class ProxyConnector : ConnectorBase + { + public ProxyConnector(ISocketFactory socketFactory) : + base(socketFactory) + { + } + + protected abstract void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket); + +#if FEATURE_TAP + // ToDo: Performs async/sync fallback, true async version should be implemented in derived classes + protected virtual Task HandleProxyConnectAsync(IConnectionInfo connectionInfo, Socket socket, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + using (cancellationToken.Register(o => ((Socket)o).Dispose(), socket, false)) + { + HandleProxyConnect(connectionInfo, socket); + } + return Task.CompletedTask; + } +#endif + + public override Socket Connect(IConnectionInfo connectionInfo) + { + var socket = SocketConnect(connectionInfo.ProxyHost, connectionInfo.ProxyPort, connectionInfo.Timeout); + + try + { + HandleProxyConnect(connectionInfo, socket); + return socket; + } + catch (Exception) + { + socket.Shutdown(SocketShutdown.Both); + socket.Dispose(); + + throw; + } + } + +#if FEATURE_TAP + public override async Task ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken) + { + var socket = await SocketConnectAsync(connectionInfo.ProxyHost, connectionInfo.ProxyPort, cancellationToken).ConfigureAwait(false); + + try + { + await HandleProxyConnectAsync(connectionInfo, socket, cancellationToken).ConfigureAwait(false); + return socket; + } + catch (Exception) + { + socket.Shutdown(SocketShutdown.Both); + socket.Dispose(); + + throw; + } + } +#endif + } +} diff --git a/src/Renci.SshNet/Connection/Socks4Connector.cs b/src/Renci.SshNet/Connection/Socks4Connector.cs index 9154240f8..ccf4e1456 100644 --- a/src/Renci.SshNet/Connection/Socks4Connector.cs +++ b/src/Renci.SshNet/Connection/Socks4Connector.cs @@ -12,36 +12,18 @@ namespace Renci.SshNet.Connection /// /// https://www.openssh.com/txt/socks4.protocol /// - internal class Socks4Connector : ConnectorBase + internal sealed class Socks4Connector : ProxyConnector { public Socks4Connector(ISocketFactory socketFactory) : base(socketFactory) { } - public override Socket Connect(IConnectionInfo connectionInfo) - { - var socket = SocketConnect(connectionInfo.ProxyHost, connectionInfo.ProxyPort, connectionInfo.Timeout); - - try - { - HandleProxyConnect(connectionInfo, socket); - return socket; - } - catch (Exception) - { - socket.Shutdown(SocketShutdown.Both); - socket.Dispose(); - - throw; - } - } - /// /// Establishes a connection to the server via a SOCKS5 proxy. /// /// The connection information. /// The . - private void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket) + protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket) { var connectionRequest = CreateSocks4ConnectionRequest(connectionInfo.Host, (ushort)connectionInfo.Port, connectionInfo.ProxyUsername); SocketAbstraction.Send(socket, connectionRequest); diff --git a/src/Renci.SshNet/Connection/Socks5Connector.cs b/src/Renci.SshNet/Connection/Socks5Connector.cs index 720ac5004..e1b6859dc 100644 --- a/src/Renci.SshNet/Connection/Socks5Connector.cs +++ b/src/Renci.SshNet/Connection/Socks5Connector.cs @@ -11,36 +11,18 @@ namespace Renci.SshNet.Connection /// /// https://en.wikipedia.org/wiki/SOCKS#SOCKS5 /// - internal class Socks5Connector : ConnectorBase + internal sealed class Socks5Connector : ProxyConnector { public Socks5Connector(ISocketFactory socketFactory) : base(socketFactory) { } - public override Socket Connect(IConnectionInfo connectionInfo) - { - var socket = SocketConnect(connectionInfo.ProxyHost, connectionInfo.ProxyPort, connectionInfo.Timeout); - - try - { - HandleProxyConnect(connectionInfo, socket); - return socket; - } - catch (Exception) - { - socket.Shutdown(SocketShutdown.Both); - socket.Dispose(); - - throw; - } - } - /// /// Establishes a connection to the server via a SOCKS5 proxy. /// /// The connection information. /// The . - private void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket) + protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket) { var greeting = new byte[] { diff --git a/src/Renci.SshNet/ISession.cs b/src/Renci.SshNet/ISession.cs index cd950da52..cde647a46 100644 --- a/src/Renci.SshNet/ISession.cs +++ b/src/Renci.SshNet/ISession.cs @@ -6,6 +6,9 @@ using Renci.SshNet.Messages; using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Messages.Connection; +#if FEATURE_TAP +using System.Threading.Tasks; +#endif namespace Renci.SshNet { @@ -54,6 +57,19 @@ internal interface ISession : IDisposable /// Failed to establish proxy connection. void Connect(); +#if FEATURE_TAP + /// + /// Asynchronously connects to the server. + /// + /// The to observe. + /// A that represents the asynchronous connect operation. + /// Socket connection to the SSH server or proxy server could not be established, or an error occurred while resolving the hostname. + /// SSH session could not be established. + /// Authentication of SSH session failed. + /// Failed to establish proxy connection. + Task ConnectAsync(CancellationToken cancellationToken); +#endif + /// /// Create a new SSH session channel. /// diff --git a/src/Renci.SshNet/ISftpClient.cs b/src/Renci.SshNet/ISftpClient.cs index 62f432491..dc2d2c899 100644 --- a/src/Renci.SshNet/ISftpClient.cs +++ b/src/Renci.SshNet/ISftpClient.cs @@ -4,6 +4,10 @@ using System.Text; using Renci.SshNet.Sftp; using Renci.SshNet.Common; +#if FEATURE_TAP +using System.Threading; +using System.Threading.Tasks; +#endif namespace Renci.SshNet { @@ -488,6 +492,22 @@ public interface ISftpClient : IDisposable /// The method was called after the client was disposed. void DeleteFile(string path); +#if FEATURE_TAP + /// + /// Asynchronously deletes remote file specified by path. + /// + /// File to be deleted path. + /// The to observe. + /// A that represents the asynchronous delete operation. + /// is null or contains only whitespace characters. + /// Client is not connected. + /// was not found on the remote host. + /// Permission to delete the file was denied by the remote host. -or- A SSH command was denied by the server. + /// A SSH error where is the message from the remote host. + /// The method was called after the client was disposed. + Task DeleteFileAsync(string path, CancellationToken cancellationToken); +#endif + /// /// Downloads remote file specified by the path into the stream. /// @@ -653,6 +673,22 @@ public interface ISftpClient : IDisposable /// The method was called after the client was disposed. SftpFileSytemInformation GetStatus(string path); +#if FEATURE_TAP + /// + /// Asynchronously gets status using statvfs@openssh.com request. + /// + /// The path. + /// The to observe. + /// + /// A that represents the status operation. + /// The task result contains the instance that contains file status information. + /// + /// Client is not connected. + /// is null. + /// The method was called after the client was disposed. + Task GetStatusAsync(string path, CancellationToken cancellationToken); +#endif + /// /// Retrieves list of files in remote directory. /// @@ -668,6 +704,25 @@ public interface ISftpClient : IDisposable /// The method was called after the client was disposed. IEnumerable ListDirectory(string path, Action listCallback = null); +#if FEATURE_TAP + + /// + /// Asynchronously retrieves list of files in remote directory. + /// + /// The path. + /// The to observe. + /// + /// A that represents the asynchronous list operation. + /// The task result contains an enumerable collection of for the files in the directory specified by . + /// + /// is null. + /// Client is not connected. + /// Permission to list the contents of the directory was denied by the remote host. -or- A SSH command was denied by the server. + /// A SSH error where is the message from the remote host. + /// The method was called after the client was disposed. + Task> ListDirectoryAsync(string path, CancellationToken cancellationToken); +#endif + /// /// Opens a on the specified path with read/write access. /// @@ -695,6 +750,24 @@ public interface ISftpClient : IDisposable /// The method was called after the client was disposed. SftpFileStream Open(string path, FileMode mode, FileAccess access); +#if FEATURE_TAP + /// + /// Asynchronously opens a on the specified path, with the specified mode and access. + /// + /// The file to open. + /// A value that specifies whether a file is created if one does not exist, and determines whether the contents of existing files are retained or overwritten. + /// A value that specifies the operations that can be performed on the file. + /// The to observe. + /// + /// A that represents the asynchronous open operation. + /// The task result contains the that provides access to the specified file, with the specified mode and access. + /// + /// is null. + /// Client is not connected. + /// The method was called after the client was disposed. + Task OpenAsync(string path, FileMode mode, FileAccess access, CancellationToken cancellationToken); +#endif + /// /// Opens an existing file for reading. /// @@ -833,6 +906,22 @@ public interface ISftpClient : IDisposable /// The method was called after the client was disposed. void RenameFile(string oldPath, string newPath); +#if FEATURE_TAP + /// + /// Asynchronously renames remote file from old path to new path. + /// + /// Path to the old file location. + /// Path to the new file location. + /// The to observe. + /// A that represents the asynchronous rename operation. + /// is null. -or- or is null. + /// Client is not connected. + /// Permission to rename the file was denied by the remote host. -or- A SSH command was denied by the server. + /// A SSH error where is the message from the remote host. + /// The method was called after the client was disposed. + Task RenameFileAsync(string oldPath, string newPath, CancellationToken cancellationToken); +#endif + /// /// Renames remote file from old path to new path. /// diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index 124ce9d4b..740ec7ee1 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -5,9 +5,9 @@ false Renci.SshNet ../Renci.SshNet.snk - 5 + 6 true - net35;net40;netstandard1.3;netstandard2.0 + net35;net40;net472;netstandard1.3;netstandard2.0 - \ No newline at end of file + From bc99ada7da3f05f50d9379f2644941d91d5bf05a Mon Sep 17 00:00:00 2001 From: Stefan Rinkes Date: Sat, 5 Mar 2022 17:05:02 +0100 Subject: [PATCH 10/96] Agent auth and Keygen (#794) * Allow to set PrivateKeyFile Key directly So you can add your own Key-Classes to SSH.NET * Add ED25519 ctor for just pub key part. * Make ECDSA Key Bits accessible You cant export imported CngKeys. To be able to export them to agent or Key-Files make the private bits also accessible. * Better NETFRAMEWORK vs NETSTANDARD handling * Add Comment Property to Key * Add IPrivateKeySource So Extension can add own PrivateKeyFiles, e.g. PuttyKeyFile. --- src/Renci.SshNet/IPrivateKeySource.cs | 15 ++ src/Renci.SshNet/NetConfClient.cs | 8 +- .../PrivateKeyAuthenticationMethod.cs | 8 +- src/Renci.SshNet/PrivateKeyConnectionInfo.cs | 20 +-- src/Renci.SshNet/PrivateKeyFile.cs | 18 ++- src/Renci.SshNet/ScpClient.cs | 6 +- .../Security/Cryptography/ED25519Key.cs | 9 ++ .../Cryptography/EcdsaDigitalSignature.cs | 12 +- .../Security/Cryptography/EcdsaKey.cs | 131 ++++++++++-------- src/Renci.SshNet/Security/Cryptography/Key.cs | 5 + src/Renci.SshNet/SftpClient.cs | 12 +- src/Renci.SshNet/SshClient.cs | 6 +- 12 files changed, 149 insertions(+), 101 deletions(-) create mode 100644 src/Renci.SshNet/IPrivateKeySource.cs diff --git a/src/Renci.SshNet/IPrivateKeySource.cs b/src/Renci.SshNet/IPrivateKeySource.cs new file mode 100644 index 000000000..fc3405462 --- /dev/null +++ b/src/Renci.SshNet/IPrivateKeySource.cs @@ -0,0 +1,15 @@ +锘縰sing Renci.SshNet.Security; + +namespace Renci.SshNet +{ + /// + /// Represents private key source interface. + /// + public interface IPrivateKeySource + { + /// + /// Gets the host key. + /// + HostAlgorithm HostKey { get; } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/NetConfClient.cs b/src/Renci.SshNet/NetConfClient.cs index b1877c601..b7ec82ec2 100644 --- a/src/Renci.SshNet/NetConfClient.cs +++ b/src/Renci.SshNet/NetConfClient.cs @@ -103,7 +103,7 @@ public NetConfClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public NetConfClient(string host, int port, string username, params PrivateKeyFile[] keyFiles) + public NetConfClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) { } @@ -116,7 +116,7 @@ public NetConfClient(string host, int port, string username, params PrivateKeyFi /// Authentication private key file(s) . /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public NetConfClient(string host, string username, params PrivateKeyFile[] keyFiles) + public NetConfClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } @@ -163,7 +163,7 @@ internal NetConfClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, I /// /// The NetConf server capabilities. /// - public XmlDocument ServerCapabilities + public XmlDocument ServerCapabilities { get { return _netConfSession.ServerCapabilities; } } @@ -277,4 +277,4 @@ private INetConfSession CreateAndConnectNetConfSession() } } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs index 93ebbe19d..43d80b506 100644 --- a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs +++ b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs @@ -28,7 +28,7 @@ public override string Name /// /// Gets the key files used for authentication. /// - public ICollection KeyFiles { get; private set; } + public ICollection KeyFiles { get; private set; } /// /// Initializes a new instance of the class. @@ -36,13 +36,13 @@ public override string Name /// The username. /// The key files. /// is whitespace or null. - public PrivateKeyAuthenticationMethod(string username, params PrivateKeyFile[] keyFiles) + public PrivateKeyAuthenticationMethod(string username, params IPrivateKeySource[] keyFiles) : base(username) { if (keyFiles == null) throw new ArgumentNullException("keyFiles"); - KeyFiles = new Collection(keyFiles); + KeyFiles = new Collection(keyFiles); } /// @@ -250,4 +250,4 @@ protected override void SaveData() } } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs index 7f0c4f658..1f717631b 100644 --- a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs +++ b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs @@ -15,7 +15,7 @@ public class PrivateKeyConnectionInfo : ConnectionInfo, IDisposable /// /// Gets the key files used for authentication. /// - public ICollection KeyFiles { get; private set; } + public ICollection KeyFiles { get; private set; } /// /// Initializes a new instance of the class. @@ -40,7 +40,7 @@ public PrivateKeyConnectionInfo(string host, string username, params PrivateKeyF /// Connection port. /// Connection username. /// Connection key files. - public PrivateKeyConnectionInfo(string host, int port, string username, params PrivateKeyFile[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(host, port, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty, keyFiles) { } @@ -55,7 +55,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, params P /// The proxy host. /// The proxy port. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params PrivateKeyFile[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles) : this(host, port, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles) { } @@ -71,7 +71,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp /// The proxy port. /// The proxy username. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params PrivateKeyFile[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles) : this(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles) { } @@ -85,7 +85,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp /// The proxy host. /// The proxy port. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params PrivateKeyFile[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles) : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles) { } @@ -100,7 +100,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy port. /// The proxy username. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params PrivateKeyFile[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles) : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles) { } @@ -116,7 +116,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy username. /// The proxy password. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params PrivateKeyFile[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles) : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, keyFiles) { } @@ -133,10 +133,10 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy username. /// The proxy password. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params PrivateKeyFile[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles) : base(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, new PrivateKeyAuthenticationMethod(username, keyFiles)) { - KeyFiles = new Collection(keyFiles); + KeyFiles = new Collection(keyFiles); } #region IDisposable Members @@ -194,4 +194,4 @@ protected virtual void Dispose(bool disposing) #endregion } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 1424134f6..f29b3e958 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -63,7 +63,7 @@ namespace Renci.SshNet /// /// /// - public class PrivateKeyFile : IDisposable + public class PrivateKeyFile : IPrivateKeySource, IDisposable { private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?[A-Z0-9-]+),(?[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?([a-zA-Z0-9/+=]{1,80}\r?\n)+)-+ *END \k PRIVATE KEY *-+", #if FEATURE_REGEX_COMPILE @@ -79,6 +79,15 @@ public class PrivateKeyFile : IDisposable /// public HostAlgorithm HostKey { get; private set; } + /// + /// Initializes a new instance of the class. + /// + /// The key. + public PrivateKeyFile(Key key) + { + HostKey = new KeyHostAlgorithm(key.ToString(), key); + } + /// /// Initializes a new instance of the class. /// @@ -262,7 +271,7 @@ private void Open(Stream privateKey, string passPhrase) if (decryptedLength > blobSize - 4) throw new SshException("Invalid passphrase."); - + if (keyType == "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}") { var exponent = reader.ReadBigIntWithBits();//e @@ -515,8 +524,7 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) throw new SshException("OpenSSH key type '" + keyType + "' is not supported."); } - //comment, we don't need this but we could log it, not sure if necessary - var comment = privateKeyReader.ReadString(Encoding.UTF8); + parsedKey.Comment = privateKeyReader.ReadString(Encoding.UTF8); //The list of privatekey/comment pairs is padded with the bytes 1, 2, 3, ... //until the total length is a multiple of the cipher block size. @@ -642,4 +650,4 @@ protected override void SaveData() } } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/ScpClient.cs b/src/Renci.SshNet/ScpClient.cs index 8a252cac9..d8ad55692 100644 --- a/src/Renci.SshNet/ScpClient.cs +++ b/src/Renci.SshNet/ScpClient.cs @@ -142,7 +142,7 @@ public ScpClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public ScpClient(string host, int port, string username, params PrivateKeyFile[] keyFiles) + public ScpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) { } @@ -155,7 +155,7 @@ public ScpClient(string host, int port, string username, params PrivateKeyFile[] /// Authentication private key file(s) . /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public ScpClient(string host, string username, params PrivateKeyFile[] keyFiles) + public ScpClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } @@ -466,4 +466,4 @@ private static SshException SecureExecutionRequestRejectedException() throw new SshException("Secure copy execution request was rejected by the server. Please consult the server logs."); } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs index deb4b1181..15f1cb019 100644 --- a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs @@ -99,6 +99,15 @@ public ED25519Key() { } + /// + /// Initializes a new instance of the class. + /// + /// pk data. + public ED25519Key(byte[] pk) + { + publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + } + /// /// Initializes a new instance of the class. /// diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs index 38d60966e..920614672 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs @@ -39,12 +39,12 @@ public override bool Verify(byte[] input, byte[] signature) // for 521 sig_size is 132 var sig_size = _key.KeyLength == 521 ? 132 : _key.KeyLength / 4; var ssh_data = new SshDataSignature(signature, sig_size); -#if NETSTANDARD2_0 - return _key.Ecdsa.VerifyData(input, ssh_data.Signature, _key.HashAlgorithm); -#else +#if NETFRAMEWORK var ecdsa = (ECDsaCng)_key.Ecdsa; ecdsa.HashAlgorithm = _key.HashAlgorithm; return ecdsa.VerifyData(input, ssh_data.Signature); +#else + return _key.Ecdsa.VerifyData(input, ssh_data.Signature, _key.HashAlgorithm); #endif } @@ -57,12 +57,12 @@ public override bool Verify(byte[] input, byte[] signature) /// public override byte[] Sign(byte[] input) { -#if NETSTANDARD2_0 - var signed = _key.Ecdsa.SignData(input, _key.HashAlgorithm); -#else +#if NETFRAMEWORK var ecdsa = (ECDsaCng)_key.Ecdsa; ecdsa.HashAlgorithm = _key.HashAlgorithm; var signed = ecdsa.SignData(input); +#else + var signed = _key.Ecdsa.SignData(input, _key.HashAlgorithm); #endif var ssh_data = new SshDataSignature(signed.Length); ssh_data.Signature = signed; diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs index 58861f020..46f1dcc65 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -18,7 +18,7 @@ public class EcdsaKey : Key, IDisposable internal const string ECDSA_P384_OID_VALUE = "1.3.132.0.34"; // Also called nistP384 or secP384r1 internal const string ECDSA_P521_OID_VALUE = "1.3.132.0.35"; // Also called nistP521or secP521r1 -#if !NETSTANDARD2_0 +#if NETFRAMEWORK internal enum KeyBlobMagicNumber : int { BCRYPT_ECDSA_PUBLIC_P256_MAGIC = 0x31534345, @@ -57,45 +57,45 @@ public override string ToString() return string.Format("ecdsa-sha2-nistp{0}", KeyLength); } -#if NETSTANDARD2_0 +#if NETFRAMEWORK /// /// Gets the HashAlgorithm to use /// - public HashAlgorithmName HashAlgorithm + public CngAlgorithm HashAlgorithm { get { - switch (KeyLength) + switch (Ecdsa.KeySize) { case 256: - return HashAlgorithmName.SHA256; + return CngAlgorithm.Sha256; case 384: - return HashAlgorithmName.SHA384; + return CngAlgorithm.Sha384; case 521: - return HashAlgorithmName.SHA512; + return CngAlgorithm.Sha512; + default: + throw new SshException("Unknown KeySize: " + Ecdsa.KeySize); } - return HashAlgorithmName.SHA256; } } #else /// /// Gets the HashAlgorithm to use /// - public CngAlgorithm HashAlgorithm + public HashAlgorithmName HashAlgorithm { get { - switch (Ecdsa.KeySize) + switch (KeyLength) { case 256: - return CngAlgorithm.Sha256; + return HashAlgorithmName.SHA256; case 384: - return CngAlgorithm.Sha384; + return HashAlgorithmName.SHA384; case 521: - return CngAlgorithm.Sha512; - default: - throw new SshException("Unknown KeySize: " + Ecdsa.KeySize); + return HashAlgorithmName.SHA512; } + return HashAlgorithmName.SHA256; } } #endif @@ -144,28 +144,7 @@ public override BigInteger[] Public byte[] curve; byte[] qx; byte[] qy; -#if NETSTANDARD2_0 - var parameter = Ecdsa.ExportParameters(false); - qx = parameter.Q.X; - qy = parameter.Q.Y; - switch (parameter.Curve.Oid.FriendlyName) - { - case "ECDSA_P256": - case "nistP256": - curve = Encoding.ASCII.GetBytes("nistp256"); - break; - case "ECDSA_P384": - case "nistP384": - curve = Encoding.ASCII.GetBytes("nistp384"); - break; - case "ECDSA_P521": - case "nistP521": - curve = Encoding.ASCII.GetBytes("nistp521"); - break; - default: - throw new SshException("Unexpected Curve Name: " + parameter.Curve.Oid.FriendlyName); - } -#else +#if NETFRAMEWORK var blob = key.Export(CngKeyBlobFormat.EccPublicBlob); KeyBlobMagicNumber magic; @@ -191,6 +170,27 @@ public override BigInteger[] Public default: throw new SshException("Unexpected Curve Magic: " + magic); } +#else + var parameter = Ecdsa.ExportParameters(false); + qx = parameter.Q.X; + qy = parameter.Q.Y; + switch (parameter.Curve.Oid.FriendlyName) + { + case "ECDSA_P256": + case "nistP256": + curve = Encoding.ASCII.GetBytes("nistp256"); + break; + case "ECDSA_P384": + case "nistP384": + curve = Encoding.ASCII.GetBytes("nistp384"); + break; + case "ECDSA_P521": + case "nistP521": + curve = Encoding.ASCII.GetBytes("nistp521"); + break; + default: + throw new SshException("Unexpected Curve Name: " + parameter.Curve.Oid.FriendlyName); + } #endif // Make ECPoint from x and y // Prepend 04 (uncompressed format) + qx-bytes + qy-bytes @@ -212,6 +212,11 @@ public override BigInteger[] Public } } + /// + /// Gets the PrivateKey Bytes + /// + public byte[] PrivateKey { get; private set; } + /// /// Gets ECDsa Object /// @@ -278,29 +283,7 @@ public EcdsaKey(byte[] data) private void Import(string curve_oid, byte[] publickey, byte[] privatekey) { -#if NETSTANDARD2_0 - var curve = ECCurve.CreateFromValue(curve_oid); - var parameter = new ECParameters - { - Curve = curve - }; - - // ECPoint as BigInteger(2) - var cord_size = (publickey.Length - 1) / 2; - var qx = new byte[cord_size]; - Buffer.BlockCopy(publickey, 1, qx, 0, qx.Length); - - var qy = new byte[cord_size]; - Buffer.BlockCopy(publickey, cord_size + 1, qy, 0, qy.Length); - - parameter.Q.X = qx; - parameter.Q.Y = qy; - - if (privatekey != null) - parameter.D = privatekey.TrimLeadingZeros().Pad(cord_size); - - Ecdsa = ECDsa.Create(parameter); -#else +#if NETFRAMEWORK var curve_magic = KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC; switch (GetCurveName(curve_oid)) { @@ -335,7 +318,10 @@ private void Import(string curve_oid, byte[] publickey, byte[] privatekey) Buffer.BlockCopy(publickey, cord_size + 1, qy, 0, qy.Length); if (privatekey != null) + { privatekey = privatekey.Pad(cord_size); + PrivateKey = privatekey; + } int headerSize = Marshal.SizeOf(typeof(BCRYPT_ECCKEY_BLOB)); int blobSize = headerSize + qx.Length + qy.Length; @@ -355,6 +341,31 @@ private void Import(string curve_oid, byte[] publickey, byte[] privatekey) key = CngKey.Import(blob, privatekey == null ? CngKeyBlobFormat.EccPublicBlob : CngKeyBlobFormat.EccPrivateBlob); Ecdsa = new ECDsaCng(key); +#else + var curve = ECCurve.CreateFromValue(curve_oid); + var parameter = new ECParameters + { + Curve = curve + }; + + // ECPoint as BigInteger(2) + var cord_size = (publickey.Length - 1) / 2; + var qx = new byte[cord_size]; + Buffer.BlockCopy(publickey, 1, qx, 0, qx.Length); + + var qy = new byte[cord_size]; + Buffer.BlockCopy(publickey, cord_size + 1, qy, 0, qy.Length); + + parameter.Q.X = qx; + parameter.Q.Y = qy; + + if (privatekey != null) + { + parameter.D = privatekey.TrimLeadingZeros().Pad(cord_size); + PrivateKey = parameter.D; + } + + Ecdsa = ECDsa.Create(parameter); #endif } diff --git a/src/Renci.SshNet/Security/Cryptography/Key.cs b/src/Renci.SshNet/Security/Cryptography/Key.cs index c668a66c3..61c5150c2 100644 --- a/src/Renci.SshNet/Security/Cryptography/Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/Key.cs @@ -36,6 +36,11 @@ public abstract class Key /// public abstract int KeyLength { get; } + /// + /// Gets the Key Comment + /// + public string Comment { get; set; } + /// /// Initializes a new instance of the class. /// diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 4ac9d5543..d33e21816 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -208,7 +208,7 @@ public SftpClient(string host, string username, string password) /// is invalid. -or- is nunullll or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public SftpClient(string host, int port, string username, params PrivateKeyFile[] keyFiles) + public SftpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) { } @@ -221,7 +221,7 @@ public SftpClient(string host, int port, string username, params PrivateKeyFile[ /// Authentication private key file(s) . /// is null. /// is invalid. -or- is null or contains only whitespace characters. - public SftpClient(string host, string username, params PrivateKeyFile[] keyFiles) + public SftpClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } @@ -712,13 +712,13 @@ public bool Exists(string path) // using SSH_FXP_REALPATH is not an alternative as the SFTP specification has not always // been clear on how the server should respond when the specified path is not present on // the server: - // + // // SSH 1 to 4: // No mention of how the server should respond if the path is not present on the server. // // SSH 5: // The server SHOULD fail the request if the path is not present on the server. - // + // // SSH 6: // Draft 06: The server SHOULD fail the request if the path is not present on the server. // Draft 07 to 13: The server MUST NOT fail the request if the path does not exist. @@ -747,7 +747,7 @@ public bool Exists(string path) /// is null or contains only whitespace characters. /// Client is not connected. /// Permission to perform the operation was denied by the remote host. -or- A SSH command was denied by the server. - /// was not found on the remote host./// + /// was not found on the remote host./// /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. /// @@ -2400,4 +2400,4 @@ private ISftpSession CreateAndConnectToSftpSession() } } } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/SshClient.cs b/src/Renci.SshNet/SshClient.cs index 49c9ff84b..881a173d4 100644 --- a/src/Renci.SshNet/SshClient.cs +++ b/src/Renci.SshNet/SshClient.cs @@ -104,7 +104,7 @@ public SshClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public SshClient(string host, int port, string username, params PrivateKeyFile[] keyFiles) + public SshClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) { } @@ -121,7 +121,7 @@ public SshClient(string host, int port, string username, params PrivateKeyFile[] /// /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public SshClient(string host, string username, params PrivateKeyFile[] keyFiles) + public SshClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } @@ -507,4 +507,4 @@ private void EnsureSessionIsOpen() throw new SshConnectionException("Client not connected."); } } -} +} \ No newline at end of file From 03c6d60736b8f7b42e44d6989a53f9b644a091fb Mon Sep 17 00:00:00 2001 From: drieseng Date: Sun, 29 May 2022 16:58:07 +0200 Subject: [PATCH 11/96] Use cryptographically secure random number generator. Fixes CVE-2022-29245. --- src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs index 9de7af8fb..1fba1c207 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs @@ -46,9 +46,7 @@ public override void Start(Session session, KeyExchangeInitMessage message) var basepoint = new byte[MontgomeryCurve25519.PublicKeySizeInBytes]; basepoint[0] = 9; - var rnd = new Random(); - _privateKey = new byte[MontgomeryCurve25519.PrivateKeySizeInBytes]; - rnd.NextBytes(_privateKey); + _privateKey = CryptoAbstraction.GenerateRandom(MontgomeryCurve25519.PrivateKeySizeInBytes); _clientExchangeValue = new byte[MontgomeryCurve25519.PublicKeySizeInBytes]; MontgomeryOperations.scalarmult(_clientExchangeValue, 0, _privateKey, 0, basepoint, 0); From bd7c02f6e43e9de77fad745fda9b053605ef9c67 Mon Sep 17 00:00:00 2001 From: drieseng Date: Sun, 29 May 2022 17:00:12 +0200 Subject: [PATCH 12/96] Remove unused import. --- src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs index 1fba1c207..b7a318bb9 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs @@ -1,5 +1,4 @@ -锘縰sing System; -using Renci.SshNet.Abstractions; +锘縰sing Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Security.Chaos.NaCl; From 34ce2bd1d0eb7dc68f8ad5a68f407f66d774f9ed Mon Sep 17 00:00:00 2001 From: Owen Krueger <37021716+Owen-Krueger@users.noreply.github.com> Date: Sun, 3 Jul 2022 14:11:46 -0500 Subject: [PATCH 13/96] Add IBaseClient for BaseClient and ISftpClient to inherit from (#975) Add IBaseClient for BaseClient and ISftpClient to inherit from --- src/Renci.SshNet/BaseClient.cs | 6 +- src/Renci.SshNet/IBaseClient.cs | 108 ++++++++++++++++++++++++++++++++ src/Renci.SshNet/ISftpClient.cs | 4 +- src/Renci.SshNet/SftpClient.cs | 2 +- 4 files changed, 114 insertions(+), 6 deletions(-) create mode 100644 src/Renci.SshNet/IBaseClient.cs diff --git a/src/Renci.SshNet/BaseClient.cs b/src/Renci.SshNet/BaseClient.cs index 4e0975b09..754396108 100644 --- a/src/Renci.SshNet/BaseClient.cs +++ b/src/Renci.SshNet/BaseClient.cs @@ -13,7 +13,7 @@ namespace Renci.SshNet /// /// Serves as base class for client implementations, provides common client functionality. /// - public abstract class BaseClient : IDisposable + public abstract class BaseClient : IBaseClient, IDisposable { /// /// Holds value indicating whether the connection info is owned by this client. @@ -387,7 +387,7 @@ private void Session_HostKeyReceived(object sender, HostKeyEventArgs e) } } -#region IDisposable Members + #region IDisposable Members private bool _isDisposed; @@ -446,7 +446,7 @@ protected void CheckDisposed() Dispose(false); } -#endregion + #endregion /// /// Stops the keep-alive timer, and waits until all timer callbacks have been diff --git a/src/Renci.SshNet/IBaseClient.cs b/src/Renci.SshNet/IBaseClient.cs new file mode 100644 index 000000000..bd9518ac4 --- /dev/null +++ b/src/Renci.SshNet/IBaseClient.cs @@ -0,0 +1,108 @@ +锘縰sing Renci.SshNet.Common; +using System; +using System.Net.Sockets; +using System.Threading; +#if FEATURE_TAP +using System.Threading.Tasks; +#endif + +namespace Renci.SshNet +{ + /// + /// Serves as base class for client implementations, provides common client functionality. + /// + public interface IBaseClient + { + /// + /// Gets the connection info. + /// + /// + /// The connection info. + /// + /// The method was called after the client was disposed. + ConnectionInfo ConnectionInfo { get; } + + /// + /// Gets a value indicating whether this client is connected to the server. + /// + /// + /// true if this client is connected; otherwise, false. + /// + /// The method was called after the client was disposed. + bool IsConnected { get; } + + /// + /// Gets or sets the keep-alive interval. + /// + /// + /// The keep-alive interval. Specify negative one (-1) milliseconds to disable the + /// keep-alive. This is the default value. + /// + /// The method was called after the client was disposed. + TimeSpan KeepAliveInterval { get; set; } + + /// + /// Occurs when an error occurred. + /// + /// + /// + /// + event EventHandler ErrorOccurred; + + /// + /// Occurs when host key received. + /// + /// + /// + /// + event EventHandler HostKeyReceived; + + /// + /// Connects client to the server. + /// + /// The client is already connected. + /// The method was called after the client was disposed. + /// Socket connection to the SSH server or proxy server could not be established, or an error occurred while resolving the hostname. + /// SSH session could not be established. + /// Authentication of SSH session failed. + /// Failed to establish proxy connection. + void Connect(); + +#if FEATURE_TAP + /// + /// Asynchronously connects client to the server. + /// + /// The to observe. + /// A that represents the asynchronous connect operation. + /// + /// The client is already connected. + /// The method was called after the client was disposed. + /// Socket connection to the SSH server or proxy server could not be established, or an error occurred while resolving the hostname. + /// SSH session could not be established. + /// Authentication of SSH session failed. + /// Failed to establish proxy connection. + Task ConnectAsync(CancellationToken cancellationToken); +#endif + + /// + /// Disconnects client from the server. + /// + /// The method was called after the client was disposed. + void Disconnect(); + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + void Dispose(); + + /// + /// Sends a keep-alive message to the server. + /// + /// + /// Use to configure the client to send a keep-alive at regular + /// intervals. + /// + /// The method was called after the client was disposed. + void SendKeepAlive(); + } +} \ No newline at end of file diff --git a/src/Renci.SshNet/ISftpClient.cs b/src/Renci.SshNet/ISftpClient.cs index dc2d2c899..eda042eff 100644 --- a/src/Renci.SshNet/ISftpClient.cs +++ b/src/Renci.SshNet/ISftpClient.cs @@ -14,7 +14,7 @@ namespace Renci.SshNet /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public interface ISftpClient : IDisposable + public interface ISftpClient : IBaseClient, IDisposable { /// /// Gets or sets the maximum size of the buffer in bytes. @@ -720,7 +720,7 @@ public interface ISftpClient : IDisposable /// Permission to list the contents of the directory was denied by the remote host. -or- A SSH command was denied by the server. /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. - Task> ListDirectoryAsync(string path, CancellationToken cancellationToken); + Task> ListDirectoryAsync(string path, CancellationToken cancellationToken); #endif /// diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index d33e21816..a7ce34538 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -552,7 +552,7 @@ public IEnumerable ListDirectory(string path, Action listCallbac /// Permission to list the contents of the directory was denied by the remote host. -or- A SSH command was denied by the server. /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. - public async Task> ListDirectoryAsync(string path, CancellationToken cancellationToken) + public async Task> ListDirectoryAsync(string path, CancellationToken cancellationToken) { base.CheckDisposed(); if (path == null) From b9bc4750ab147948d66678af7e583878ce96f28a Mon Sep 17 00:00:00 2001 From: Masuri Date: Sat, 27 Aug 2022 03:54:30 +0900 Subject: [PATCH 14/96] fix typo (#999) --- src/Renci.SshNet/Sftp/SftpFileReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Renci.SshNet/Sftp/SftpFileReader.cs b/src/Renci.SshNet/Sftp/SftpFileReader.cs index 3aed4f535..a881e9c03 100644 --- a/src/Renci.SshNet/Sftp/SftpFileReader.cs +++ b/src/Renci.SshNet/Sftp/SftpFileReader.cs @@ -82,7 +82,7 @@ public byte[] Read() lock (_readLock) { - // wait until either the next chunk is avalable, an exception has occurred or the current + // wait until either the next chunk is available, an exception has occurred or the current // instance is already disposed while (!_queue.TryGetValue(_nextChunkIndex, out nextChunk) && _exception == null) { From f3ebc290e258d90ba4efd16fd8ab25369330f490 Mon Sep 17 00:00:00 2001 From: LemonPi314 <49930425+LemonPi314@users.noreply.github.com> Date: Tue, 29 Nov 2022 15:33:47 -0500 Subject: [PATCH 15/96] Fix Seek Operations in SftpFileStream (#910) * Fix offset operations in SftpFileStream.Seek * Fix seek exception message and add default case for invalid seek origin * Use named params when throwing ArgumentException * Add tests for seeking from end of file --- ...ningOfStream_OriginEndAndOffsetNegative.cs | 103 ++++++++++++++++++ ...ningOfStream_OriginEndAndOffsetPositive.cs | 103 ++++++++++++++++++ ...eginningOfStream_OriginEndAndOffsetZero.cs | 103 ++++++++++++++++++ src/Renci.SshNet/Sftp/SftpFileStream.cs | 62 ++++------- 4 files changed, 331 insertions(+), 40 deletions(-) create mode 100644 src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetNegative.cs create mode 100644 src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetPositive.cs create mode 100644 src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetZero.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetNegative.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetNegative.cs new file mode 100644 index 000000000..e47e716e1 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetNegative.cs @@ -0,0 +1,103 @@ +锘縰sing System; +using System.IO; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Sftp; + +namespace Renci.SshNet.Tests.Classes.Sftp +{ + [TestClass] + public class SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetNegative : SftpFileStreamTestBase + { + private Random _random; + private string _path; + private FileMode _fileMode; + private FileAccess _fileAccess; + private int _bufferSize; + private uint _readBufferSize; + private uint _writeBufferSize; + private int _length; + private byte[] _handle; + private SftpFileStream _target; + private int _offset; + private SftpFileAttributes _attributes; + private long _actual; + + protected override void SetupData() + { + base.SetupData(); + + _random = new Random(); + _path = _random.Next().ToString(); + _fileMode = FileMode.OpenOrCreate; + _fileAccess = FileAccess.Write; + _bufferSize = _random.Next(5, 1000); + _readBufferSize = (uint)_random.Next(5, 1000); + _writeBufferSize = (uint)_random.Next(5, 1000); + _length = _random.Next(5, 10000); + _handle = GenerateRandom(_random.Next(1, 10), _random); + _offset = _random.Next(-_length, -1); + _attributes = SftpFileAttributes.Empty; + } + + protected override void SetupMocks() + { + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.RequestOpen(_path, Flags.Write | Flags.CreateNewOrOpen, false)) + .Returns(_handle); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.CalculateOptimalReadLength((uint)_bufferSize)) + .Returns(_readBufferSize); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.CalculateOptimalWriteLength((uint)_bufferSize, _handle)) + .Returns(_writeBufferSize); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.IsOpen) + .Returns(true); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.RequestFStat(_handle, false)) + .Returns(_attributes); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.RequestFSetStat(_handle, _attributes)); + SftpSessionMock.InSequence(MockSequence).Setup(session => session.IsOpen).Returns(true); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.RequestFStat(_handle, false)) + .Returns(_attributes); + } + + protected override void Arrange() + { + base.Arrange(); + + _target = new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize); + _target.SetLength(_length); + } + + protected override void Act() + { + _actual = _target.Seek(_offset, SeekOrigin.End); + } + + [TestMethod] + public void SeekShouldHaveReturnedOffset() + { + Assert.AreEqual(_attributes.Size + _offset, _actual); + } + + [TestMethod] + public void IsOpenOnSftpSessionShouldHaveBeenInvokedTwice() + { + SftpSessionMock.Verify(session => session.IsOpen, Times.Exactly(2)); + } + + [TestMethod] + public void PositionShouldReturnOffset() + { + SftpSessionMock.InSequence(MockSequence).Setup(session => session.IsOpen).Returns(true); + + Assert.AreEqual(_attributes.Size + _offset, _target.Position); + + SftpSessionMock.Verify(session => session.IsOpen, Times.Exactly(3)); + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetPositive.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetPositive.cs new file mode 100644 index 000000000..506342f1a --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetPositive.cs @@ -0,0 +1,103 @@ +锘縰sing System; +using System.IO; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Sftp; + +namespace Renci.SshNet.Tests.Classes.Sftp +{ + [TestClass] + public class SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetPositive : SftpFileStreamTestBase + { + private Random _random; + private string _path; + private FileMode _fileMode; + private FileAccess _fileAccess; + private int _bufferSize; + private uint _readBufferSize; + private uint _writeBufferSize; + private int _length; + private byte[] _handle; + private SftpFileStream _target; + private int _offset; + private SftpFileAttributes _attributes; + private long _actual; + + protected override void SetupData() + { + base.SetupData(); + + _random = new Random(); + _path = _random.Next().ToString(); + _fileMode = FileMode.OpenOrCreate; + _fileAccess = FileAccess.Write; + _bufferSize = _random.Next(5, 1000); + _readBufferSize = (uint)_random.Next(5, 1000); + _writeBufferSize = (uint)_random.Next(5, 1000); + _length = _random.Next(5, 10000); + _handle = GenerateRandom(_random.Next(1, 10), _random); + _offset = _random.Next(1, int.MaxValue); + _attributes = SftpFileAttributes.Empty; + } + + protected override void SetupMocks() + { + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.RequestOpen(_path, Flags.Write | Flags.CreateNewOrOpen, false)) + .Returns(_handle); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.CalculateOptimalReadLength((uint)_bufferSize)) + .Returns(_readBufferSize); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.CalculateOptimalWriteLength((uint)_bufferSize, _handle)) + .Returns(_writeBufferSize); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.IsOpen) + .Returns(true); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.RequestFStat(_handle, false)) + .Returns(_attributes); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.RequestFSetStat(_handle, _attributes)); + SftpSessionMock.InSequence(MockSequence).Setup(session => session.IsOpen).Returns(true); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.RequestFStat(_handle, false)) + .Returns(_attributes); + } + + protected override void Arrange() + { + base.Arrange(); + + _target = new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize); + _target.SetLength(_length); + } + + protected override void Act() + { + _actual = _target.Seek(_offset, SeekOrigin.End); + } + + [TestMethod] + public void SeekShouldHaveReturnedOffset() + { + Assert.AreEqual(_attributes.Size + _offset, _actual); + } + + [TestMethod] + public void IsOpenOnSftpSessionShouldHaveBeenInvokedTwice() + { + SftpSessionMock.Verify(session => session.IsOpen, Times.Exactly(2)); + } + + [TestMethod] + public void PositionShouldReturnOffset() + { + SftpSessionMock.InSequence(MockSequence).Setup(session => session.IsOpen).Returns(true); + + Assert.AreEqual(_attributes.Size + _offset, _target.Position); + + SftpSessionMock.Verify(session => session.IsOpen, Times.Exactly(3)); + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetZero.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetZero.cs new file mode 100644 index 000000000..4791acf85 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetZero.cs @@ -0,0 +1,103 @@ +锘縰sing System; +using System.IO; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Moq; +using Renci.SshNet.Sftp; + +namespace Renci.SshNet.Tests.Classes.Sftp +{ + [TestClass] + public class SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetZero : SftpFileStreamTestBase + { + private Random _random; + private string _path; + private FileMode _fileMode; + private FileAccess _fileAccess; + private int _bufferSize; + private uint _readBufferSize; + private uint _writeBufferSize; + private int _length; + private byte[] _handle; + private SftpFileStream _target; + private int _offset; + private SftpFileAttributes _attributes; + private long _actual; + + protected override void SetupData() + { + base.SetupData(); + + _random = new Random(); + _path = _random.Next().ToString(); + _fileMode = FileMode.OpenOrCreate; + _fileAccess = FileAccess.Write; + _bufferSize = _random.Next(5, 1000); + _readBufferSize = (uint)_random.Next(5, 1000); + _writeBufferSize = (uint)_random.Next(5, 1000); + _length = _random.Next(5, 10000); + _handle = GenerateRandom(_random.Next(1, 10), _random); + _offset = 0; + _attributes = SftpFileAttributes.Empty; + } + + protected override void SetupMocks() + { + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.RequestOpen(_path, Flags.Write | Flags.CreateNewOrOpen, false)) + .Returns(_handle); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.CalculateOptimalReadLength((uint)_bufferSize)) + .Returns(_readBufferSize); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.CalculateOptimalWriteLength((uint)_bufferSize, _handle)) + .Returns(_writeBufferSize); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.IsOpen) + .Returns(true); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.RequestFStat(_handle, false)) + .Returns(_attributes); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.RequestFSetStat(_handle, _attributes)); + SftpSessionMock.InSequence(MockSequence).Setup(session => session.IsOpen).Returns(true); + SftpSessionMock.InSequence(MockSequence) + .Setup(session => session.RequestFStat(_handle, false)) + .Returns(_attributes); + } + + protected override void Arrange() + { + base.Arrange(); + + _target = new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize); + _target.SetLength(_length); + } + + protected override void Act() + { + _actual = _target.Seek(_offset, SeekOrigin.End); + } + + [TestMethod] + public void SeekShouldHaveReturnedSize() + { + Assert.AreEqual(_attributes.Size, _actual); + } + + [TestMethod] + public void IsOpenOnSftpSessionShouldHaveBeenInvokedTwice() + { + SftpSessionMock.Verify(session => session.IsOpen, Times.Exactly(2)); + } + + [TestMethod] + public void PositionShouldReturnSize() + { + SftpSessionMock.InSequence(MockSequence).Setup(session => session.IsOpen).Returns(true); + + Assert.AreEqual(_attributes.Size, _target.Position); + + SftpSessionMock.Verify(session => session.IsOpen, Times.Exactly(3)); + } + } +} diff --git a/src/Renci.SshNet/Sftp/SftpFileStream.cs b/src/Renci.SshNet/Sftp/SftpFileStream.cs index ecb424567..b47023687 100644 --- a/src/Renci.SshNet/Sftp/SftpFileStream.cs +++ b/src/Renci.SshNet/Sftp/SftpFileStream.cs @@ -788,26 +788,6 @@ public override long Seek(long offset, SeekOrigin origin) { // Flush the write buffer and then seek. FlushWriteBuffer(); - - switch (origin) - { - case SeekOrigin.Begin: - newPosn = offset; - break; - case SeekOrigin.Current: - newPosn = _position + offset; - break; - case SeekOrigin.End: - var attributes = _session.RequestFStat(_handle, false); - newPosn = attributes.Size - offset; - break; - } - - if (newPosn == -1) - { - throw new EndOfStreamException("End of stream."); - } - _position = newPosn; } else { @@ -838,29 +818,31 @@ public override long Seek(long offset, SeekOrigin origin) // Abandon the read buffer. _bufferPosition = 0; _bufferLen = 0; + } - // Seek to the new position. - switch (origin) - { - case SeekOrigin.Begin: - newPosn = offset; - break; - case SeekOrigin.Current: - newPosn = _position + offset; - break; - case SeekOrigin.End: - var attributes = _session.RequestFStat(_handle, false); - newPosn = attributes.Size - offset; - break; - } - - if (newPosn < 0) - { - throw new EndOfStreamException(); - } + // Seek to the new position. + switch (origin) + { + case SeekOrigin.Begin: + newPosn = offset; + break; + case SeekOrigin.Current: + newPosn = _position + offset; + break; + case SeekOrigin.End: + var attributes = _session.RequestFStat(_handle, false); + newPosn = attributes.Size + offset; + break; + default: + throw new ArgumentException(message: "Invalid seek origin.", paramName: "origin"); + } - _position = newPosn; + if (newPosn < 0) + { + throw new EndOfStreamException(); } + + _position = newPosn; return _position; } } From ab2ccc40bce835ce1d3c136aa702459bfd9948b7 Mon Sep 17 00:00:00 2001 From: Gert Driesen Date: Tue, 20 Dec 2022 16:24:20 +0100 Subject: [PATCH 16/96] Add back copyright to license. (#1060) Fixes #1059. --- LICENSE | 2 ++ 1 file changed, 2 insertions(+) diff --git a/LICENSE b/LICENSE index d13cc4b26..f2aef4f38 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,7 @@ The MIT License (MIT) +Copyright (c) Renci, Oleg Kapeljushnik, Gert Driesen and contributors + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights From cf8510013db0e8a1d54086d67694e041f5ef4b98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Sat, 6 May 2023 22:32:10 +0200 Subject: [PATCH 17/96] Removing old target frameworks (#1109) Remove support for legacy / deprecated target frameworks while adding support for .NET 6.0 (and higher). The supported target frameworks are now: * .NETFramework 4.6.2 (and higher) * .NET Standard 2.0 * .NET 6.0 (and higher) --- README.md | 20 +- appveyor.yml | 12 +- build/build.proj | 115 +- build/nuget/SSH.NET.nuspec | 28 +- build/sandcastle/SSH.NET.shfbproj | 33 +- .../Properties/AssemblyInfo.cs | 5 - .../Renci.SshNet.Silverlight.csproj | 1459 ---------------- src/Renci.SshNet.Silverlight/packages.config | 4 - .../Properties/AssemblyInfo.cs | 5 - .../Renci.SshNet.Silverlight5.csproj | 1463 ---------------- src/Renci.SshNet.Silverlight5/packages.config | 4 - ...nected_KeepAliveInterval_NotNegativeOne.cs | 7 +- .../Classes/ClientAuthenticationTest.cs | 5 +- .../Classes/Common/CountdownEventTest.cs | 49 +- .../Classes/Common/PacketDumpTest.cs | 9 +- .../Common/PipeStream_Close_BlockingWrite.cs | 1 - ...ipeStream_Flush_BytesRemainingAfterRead.cs | 6 +- ...thTest_CreateAbsoluteOrRelativeFilePath.cs | 3 +- .../Classes/Common/SemaphoreLightTest.cs | 15 +- .../Connection/HttpConnectorTestBase.cs | 2 +- ...yClosesConnectionBeforeStatusLineIsSent.cs | 4 + ...nectorTest_Connect_ProxyPasswordIsEmpty.cs | 4 + ...nnectorTest_Connect_ProxyPasswordIsNull.cs | 4 + ...oxyResponseDoesNotContainHttpStatusLine.cs | 4 + ...seStatusIs200_ExtraTextBeforeStatusLine.cs | 4 + ...xyResponseStatusIs200_HeadersAndContent.cs | 4 + ...ct_ProxyResponseStatusIs200_OnlyHeaders.cs | 4 + ...est_Connect_ProxyResponseStatusIsNot200.cs | 4 + ...nectorTest_Connect_ProxyUserNameIsEmpty.cs | 4 + ...nnect_ProxyUserNameIsNotNullAndNotEmpty.cs | 4 + ...nnectorTest_Connect_ProxyUserNameIsNull.cs | 4 + ...rTest_Connect_TimeoutReadingHttpContent.cs | 4 + ...orTest_Connect_TimeoutReadingStatusLine.cs | 4 + ...ectionClosedByServer_NoDataSentByServer.cs | 4 + ...est_ServerResponseContainsNullCharacter.cs | 4 + ...entificationOnlyContainsProtocolVersion.cs | 4 + ...changeTest_ServerResponseValid_Comments.cs | 4 + ...angeTest_ServerResponseValid_NoComments.cs | 4 + ...rminatedByLineFeedWithoutCarriageReturn.cs | 4 + ...Test_TimeoutReadingIdentificationString.cs | 4 + .../Connection/Socks4ConnectorTestBase.cs | 3 +- ...rTest_Connect_ConnectionRejectedByProxy.cs | 4 + ...nnectorTest_Connect_ConnectionSucceeded.cs | 4 + ...onnect_TimeoutReadingDestinationAddress.cs | 4 + ...torTest_Connect_TimeoutReadingReplyCode.cs | 4 + ...Test_Connect_TimeoutReadingReplyVersion.cs | 4 + .../Connection/Socks5ConnectorTestBase.cs | 1 + ...ct_NoAuthentication_ConnectionSucceeded.cs | 4 + ...Connect_ProxySocksVersionIsNotSupported.cs | 4 + ...wordAuthentication_AuthenticationFailed.cs | 4 + ...swordAuthentication_ConnectionSucceeded.cs | 4 + ...entication_PasswordExceedsMaximumLength.cs | 4 + ...entication_UserNameExceedsMaximumLength.cs | 4 + .../Classes/NetConfClientTest.cs | 4 +- ...rectoryInfo_SendExecRequestReturnsFalse.cs | 8 - ...AndFileInfo_SendExecRequestReturnsFalse.cs | 8 - ...thAndStream_SendExecRequestReturnsFalse.cs | 8 - ...InfoAndPath_SendExecRequestReturnsFalse.cs | 8 - ...InfoAndPath_SendExecRequestReturnsFalse.cs | 8 - ...ientTest_Upload_FileInfoAndPath_Success.cs | 8 - ...reamAndPath_SendExecRequestReturnsFalse.cs | 8 - .../SessionTest_Connected_ConnectionReset.cs | 2 +- .../Classes/SftpClientTest.cs | 12 +- .../Common/ArgumentExceptionAssert.cs | 15 + .../Common/AsyncSocketListener.cs | 144 +- .../Renci.SshNet.Tests.csproj | 68 +- .../Properties/AssemblyInfo.cs | 10 - .../Properties/Renci.SshNet.UAP10.rd.xml | 33 - .../Renci.SshNet.UAP10.csproj | 1526 ----------------- src/Renci.SshNet.UAP10/project.json | 18 - src/Renci.SshNet.VS2012.sln | 108 -- src/Renci.SshNet.VS2015.sln | 130 -- src/Renci.SshNet.VS2015.sln.DotSettings | 22 - src/Renci.SshNet.VS2017.sln | 82 - .../Properties/AssemblyInfo.cs | 5 - .../Renci.SshNet.WindowsPhone.csproj | 1435 ---------------- src/Renci.SshNet.WindowsPhone/packages.config | 4 - .../Properties/AssemblyInfo.cs | 8 - .../Renci.SshNet.WindowsPhone8.csproj | 1496 ---------------- .../packages.config | 5 - ...nci.SshNet.VS2019.sln => Renci.SshNet.sln} | 0 .../Abstractions/SocketAbstraction.cs | 4 +- src/Renci.SshNet/ForwardedPortDynamic.NET.cs | 9 + src/Renci.SshNet/Renci.SshNet.csproj | 36 +- .../Renci.SshNet.WindowsPhone8.Tests/App.xaml | 21 - .../App.xaml.cs | 222 --- .../Assets/AlignmentGrid.png | Bin 9042 -> 0 bytes .../Assets/ApplicationIcon.png | Bin 3392 -> 0 bytes .../Assets/Tiles/FlipCycleTileLarge.png | Bin 9930 -> 0 bytes .../Assets/Tiles/FlipCycleTileMedium.png | Bin 9070 -> 0 bytes .../Assets/Tiles/FlipCycleTileSmall.png | Bin 3674 -> 0 bytes .../LocalizedStrings.cs | 14 - .../MainPage.xaml | 62 - .../MainPage.xaml.cs | 21 - .../Properties/AppManifest.xml | 6 - .../Properties/AssemblyInfo.cs | 37 - .../Properties/WMAppManifest.xml | 46 - .../Renci.SshNet.WindowsPhone8.Tests.csproj | 148 -- .../Resources/AppResources.Designer.cs | 108 -- .../Resources/AppResources.resx | 137 -- 100 files changed, 376 insertions(+), 9051 deletions(-) delete mode 100644 src/Renci.SshNet.Silverlight/Properties/AssemblyInfo.cs delete mode 100644 src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj delete mode 100644 src/Renci.SshNet.Silverlight/packages.config delete mode 100644 src/Renci.SshNet.Silverlight5/Properties/AssemblyInfo.cs delete mode 100644 src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj delete mode 100644 src/Renci.SshNet.Silverlight5/packages.config create mode 100644 src/Renci.SshNet.Tests/Common/ArgumentExceptionAssert.cs delete mode 100644 src/Renci.SshNet.UAP10/Properties/AssemblyInfo.cs delete mode 100644 src/Renci.SshNet.UAP10/Properties/Renci.SshNet.UAP10.rd.xml delete mode 100644 src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj delete mode 100644 src/Renci.SshNet.UAP10/project.json delete mode 100644 src/Renci.SshNet.VS2012.sln delete mode 100644 src/Renci.SshNet.VS2015.sln delete mode 100644 src/Renci.SshNet.VS2015.sln.DotSettings delete mode 100644 src/Renci.SshNet.VS2017.sln delete mode 100644 src/Renci.SshNet.WindowsPhone/Properties/AssemblyInfo.cs delete mode 100644 src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj delete mode 100644 src/Renci.SshNet.WindowsPhone/packages.config delete mode 100644 src/Renci.SshNet.WindowsPhone8/Properties/AssemblyInfo.cs delete mode 100644 src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj delete mode 100644 src/Renci.SshNet.WindowsPhone8/packages.config rename src/{Renci.SshNet.VS2019.sln => Renci.SshNet.sln} (100%) delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/App.xaml delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/App.xaml.cs delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/Assets/AlignmentGrid.png delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/Assets/ApplicationIcon.png delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/Assets/Tiles/FlipCycleTileLarge.png delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/Assets/Tiles/FlipCycleTileMedium.png delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/Assets/Tiles/FlipCycleTileSmall.png delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/LocalizedStrings.cs delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/MainPage.xaml delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/MainPage.xaml.cs delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/Properties/AppManifest.xml delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/Properties/AssemblyInfo.cs delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/Properties/WMAppManifest.xml delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/Renci.SshNet.WindowsPhone8.Tests.csproj delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/Resources/AppResources.Designer.cs delete mode 100644 test/Renci.SshNet.WindowsPhone8.Tests/Resources/AppResources.resx diff --git a/README.md b/README.md index 242c6dc6a..5708d0af4 100755 --- a/README.md +++ b/README.md @@ -116,15 +116,9 @@ Private keys can be encrypted using one of the following cipher methods: ## Framework Support **SSH.NET** supports the following target frameworks: -* .NET Framework 3.5 -* .NET Framework 4.0 (and higher) -* .NET Standard 1.3 +* .NETFramework 4.6.2 (and higher) * .NET Standard 2.0 -* Silverlight 4 -* Silverlight 5 -* Windows Phone 7.1 -* Windows Phone 8.0 -* Universal Windows Platform 10 +* .NET 6 (and higher) ## Usage @@ -178,16 +172,6 @@ using (var client = new SshClient("sftp.foo.com", "guest", "pwd")) } ``` -## Building SSH.NET - -Software | net35 | net40 | netstandard1.3 | netstandard2.0 | sl4 | sl5 | wp71 | wp8 | uap10.0 | ---------------------------------- | :---: | :---: | :------------: | :------------: | :-: | :-: | :--: | :-: | :-----: | -Windows Phone SDK 8.0 | | | | | x | x | x | x | -Visual Studio 2012 Update 5 | x | x | | | x | x | x | x | -Visual Studio 2015 Update 3 | x | x | | | | x | | x | x -Visual Studio 2017 | x | x | x | x | | | | | -Visual Studio 2019 | x | x | x | x | | | | | - ## Supporting SSH.NET Do you or your company rely on **SSH.NET** in your projects? If you want to encourage us to keep on going and show us that you appreciate our work, please consider becoming a [sponsor](https://github.com/sponsors/sshnet) through GitHub Sponsors. diff --git a/appveyor.yml b/appveyor.yml index 2425ef712..d380a3f58 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,14 +1,14 @@ -os: Visual Studio 2019 +os: Visual Studio 2022 before_build: - - nuget restore src\Renci.SshNet.VS2019.sln + - nuget restore src\Renci.SshNet.sln build: - project: src\Renci.SshNet.VS2019.sln + project: src\Renci.SshNet.sln verbosity: minimal test_script: - cmd: >- - vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net35\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning" - - vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net472\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning" + vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net462\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning" --blame + + vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net7.0\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning" --blame \ No newline at end of file diff --git a/build/build.proj b/build/build.proj index 40ef012b6..d2911509c 100644 --- a/build/build.proj +++ b/build/build.proj @@ -8,86 +8,37 @@ MSBuildTasks 1.5.0.214 - - - - $(MSBuildThisFileDirectory)..\src\Renci.SshNet.VS2012.sln - 14.0 - 14.0 - - - $(MSBuildThisFileDirectory)..\src\Renci.SshNet.VS2015.sln - 14.0 - 14.0 - - - - - - $(MSBuildThisFileDirectory)..\src\Renci.SshNet.VS2019.sln - 16.0 - - - - Renci.SshNet.WindowsPhone\bin\$(Configuration) - wp71 - - - Renci.SshNet.WindowsPhone8\bin\$(Configuration) - wp8 - - - Renci.SshNet.Silverlight\bin\$(Configuration) - sl4 - - - Renci.SshNet.Silverlight5\bin\$(Configuration) - sl5 - - - Renci.SshNet.UAP10\bin\$(Configuration) - uap10 - + + $(MSBuildThisFileDirectory)..\src\Renci.SshNet.sln + 17.0 + - - Renci.SshNet\bin\$(Configuration)\net35 - net35 - - - Renci.SshNet\bin\$(Configuration)\net40 - net40 - - - Renci.SshNet\bin\$(Configuration)\netstandard1.3 - netstandard1.3 + + Renci.SshNet\bin\$(Configuration)\net462 + net462 Renci.SshNet\bin\$(Configuration)\netstandard2.0 netstandard2.0 + + Renci.SshNet\bin\$(Configuration)\net6.0 + net6.0 + + + Renci.SshNet\bin\$(Configuration)\net7.0 + net7.0 + - - - - - + - - - - - Configuration=Release;VisualStudioVersion=%(VisualStudioVersionClassic.VisualStudioVersion) - - - - @@ -99,26 +50,11 @@ - - - - - - - - - - - Configuration=Release;VisualStudioVersion=%(VisualStudioVersionClassic.VisualStudioVersion) - - - - - + @@ -131,12 +67,7 @@ - - - - - - + @@ -153,16 +84,6 @@ - - - - - - - - - - diff --git a/build/nuget/SSH.NET.nuspec b/build/nuget/SSH.NET.nuspec index 038305832..3fe48202b 100644 --- a/build/nuget/SSH.NET.nuspec +++ b/build/nuget/SSH.NET.nuspec @@ -16,37 +16,15 @@ en-US ssh scp sftp - - - - - - - - - - - - - + - - - - - - - - - - + - + - diff --git a/build/sandcastle/SSH.NET.shfbproj b/build/sandcastle/SSH.NET.shfbproj index 68579630e..15d8dc2f2 100644 --- a/build/sandcastle/SSH.NET.shfbproj +++ b/build/sandcastle/SSH.NET.shfbproj @@ -1,21 +1,22 @@ 锘 - + + v4.6.2 + Debug AnyCPU + 2.0 {f7266fb1-f50a-4a5b-b35a-5ea8ebdc1be9} - 2015.6.5.0 + 2017.9.26.0 Documentation Documentation Documentation - .NET Framework 4.0 + .NET Framework 4.6.2 ..\target\help SshNet.Help en-US @@ -24,25 +25,15 @@ C# Blank False - VS2010 + VS2013 False Guid SSH.NET Client Library Documentation AboveNamespaces - - - - - {@HelpFormatOutputPaths} - - - - - - + - - + + Summary, Parameter, Returns, AutoDocumentCtors, TypeParameter, AutoDocumentDispose OnlyWarningsAndErrors @@ -54,7 +45,7 @@ True + the build. The others are optional common platform types that may appear. --> diff --git a/src/Renci.SshNet.Silverlight/Properties/AssemblyInfo.cs b/src/Renci.SshNet.Silverlight/Properties/AssemblyInfo.cs deleted file mode 100644 index f9c8d3244..000000000 --- a/src/Renci.SshNet.Silverlight/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -锘縰sing System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("SSH.NET Silverlight 4")] -[assembly: Guid("2b3f6251-8079-48aa-a76b-df70e40092e2")] \ No newline at end of file diff --git a/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj b/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj deleted file mode 100644 index 7505a175a..000000000 --- a/src/Renci.SshNet.Silverlight/Renci.SshNet.Silverlight.csproj +++ /dev/null @@ -1,1459 +0,0 @@ -锘 - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {77C294BB-1DC2-49DC-BE16-963F8F22794D} - {A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - Renci.SshNet - Renci.SshNet - Silverlight - v4.0 - $(TargetFrameworkVersion) - false - true - true - - - - v3.5 - - - true - full - false - Bin\Debug - TRACE;DEBUG;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_MEMORYSTREAM_GETBUFFER - true - true - prompt - 4 - Bin\Debug\Renci.SshNet.xml - - - none - true - Bin\Release - TRACE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_MEMORYSTREAM_GETBUFFER - true - true - prompt - 4 - Bin\Release\Renci.SshNet.xml - 1591 - - - true - - - ..\Renci.SshNet.snk - - - - - ..\..\packages\SshNet.Security.Cryptography.1.2.0\lib\sl4\SshNet.Security.Cryptography.dll - - - - - - - - - Abstractions\CryptoAbstraction.cs - - - Abstractions\DiagnosticAbstraction.cs - - - Abstractions\DnsAbstraction.cs - - - Abstractions\FileSystemAbstraction.cs - - - Abstractions\ReflectionAbstraction.cs - - - Abstractions\SocketAbstraction.cs - - - Abstractions\ThreadAbstraction.cs - - - AuthenticationMethod.cs - - - AuthenticationResult.cs - - - BaseClient.cs - - - Channels\Channel.cs - - - Channels\ChannelDirectTcpip.cs - - - Channels\ChannelForwardedTcpip.cs - - - Channels\ChannelSession.cs - - - Channels\ChannelTypes.cs - - - Channels\ClientChannel.cs - - - Channels\IChannel.cs - - - Channels\IChannelDirectTcpip.cs - - - Channels\IChannelForwardedTcpip.cs - - - Channels\IChannelSession.cs - - - Channels\ServerChannel.cs - - - CipherInfo.cs - - - ClientAuthentication.cs - - - CommandAsyncResult.cs - - - Common\Array.cs - - - Common\ASCIIEncoding.cs - - - Common\AsyncResult.cs - - - Common\AuthenticationBannerEventArgs.cs - - - Common\AuthenticationEventArgs.cs - - - Common\AuthenticationPasswordChangeEventArgs.cs - - - Common\AuthenticationPrompt.cs - - - Common\AuthenticationPromptEventArgs.cs - - - Common\BigInteger.cs - - - Common\ChannelDataEventArgs.cs - - - Common\ChannelEventArgs.cs - - - Common\ChannelExtendedDataEventArgs.cs - - - Common\ChannelOpenConfirmedEventArgs.cs - - - Common\ChannelOpenFailedEventArgs.cs - - - Common\ChannelRequestEventArgs.cs - - - Common\CountdownEvent.cs - - - Common\DerData.cs - - - Common\ExceptionEventArgs.cs - - - Common\Extensions.cs - - - Common\HostKeyEventArgs.cs - - - Common\ObjectIdentifier.cs - - - Common\Pack.cs - - - Common\PacketDump.cs - - - Common\PipeStream.cs - - - Common\PortForwardEventArgs.cs - - - Common\PosixPath.cs - - - Common\ProxyException.cs - - - Common\ScpDownloadEventArgs.cs - - - Common\ScpException.cs - - - Common\ScpUploadEventArgs.cs - - - Common\SemaphoreLight.cs - - - Common\SftpPathNotFoundException.cs - - - Common\SftpPermissionDeniedException.cs - - - Common\ShellDataEventArgs.cs - - - Common\SshAuthenticationException.cs - - - Common\SshConnectionException.cs - - - Common\SshData.cs - - - Common\SshDataStream.cs - - - Common\SshException.cs - - - Common\SshOperationTimeoutException.cs - - - Common\SshPassPhraseNullOrEmptyException.cs - - - Common\TerminalModes.cs - - - Compression\CompressionMode.cs - - - Compression\Compressor.cs - - - Compression\Zlib.cs - - - Compression\ZlibOpenSsh.cs - - - Compression\ZlibStream.cs - - - ConnectionInfo.cs - - - Connection\ConnectorBase.cs - - - Connection\DirectConnector.cs - - - Connection\HttpConnector.cs - - - Connection\IConnector.cs - - - Connection\IProtocolVersionExchange.cs - - - Connection\ISocketFactory.cs - - - Connection\ProtocolVersionExchange.cs - - - Connection\SocketFactory.cs - - - Connection\Socks4Connector.cs - - - Connection\Socks5Connector.cs - - - Connection\SshIdentification.cs - - - ExpectAction.cs - - - ExpectAsyncResult.cs - - - ForwardedPort.cs - - - ForwardedPortDynamic.cs - - - ForwardedPortLocal.cs - - - ForwardedPortRemote.cs - - - ForwardedPortStatus.cs - - - HashInfo.cs - - - IAuthenticationMethod.cs - - - IClientAuthentication.cs - - - IConnectionInfo.cs - - - IForwardedPort.cs - - - IRemotePathTransformation.cs - - - IServiceFactory.cs - - - ISession.cs - - - ISubsystemSession.cs - - - KeyboardInteractiveAuthenticationMethod.cs - - - KeyboardInteractiveConnectionInfo.cs - - - MessageEventArgs.cs - - - Messages\Authentication\BannerMessage.cs - - - Messages\Authentication\FailureMessage.cs - - - Messages\Authentication\InformationRequestMessage.cs - - - Messages\Authentication\InformationResponseMessage.cs - - - Messages\Authentication\PasswordChangeRequiredMessage.cs - - - Messages\Authentication\PublicKeyMessage.cs - - - Messages\Authentication\RequestMessage.cs - - - Messages\Authentication\RequestMessageHost.cs - - - Messages\Authentication\RequestMessageKeyboardInteractive.cs - - - Messages\Authentication\RequestMessageNone.cs - - - Messages\Authentication\RequestMessagePassword.cs - - - Messages\Authentication\RequestMessagePublicKey.cs - - - Messages\Authentication\SuccessMessage.cs - - - Messages\Connection\CancelTcpIpForwardGlobalRequestMessage.cs - - - Messages\Connection\ChannelCloseMessage.cs - - - Messages\Connection\ChannelDataMessage.cs - - - Messages\Connection\ChannelEofMessage.cs - - - Messages\Connection\ChannelExtendedDataMessage.cs - - - Messages\Connection\ChannelFailureMessage.cs - - - Messages\Connection\ChannelMessage.cs - - - Messages\Connection\ChannelOpenConfirmationMessage.cs - - - Messages\Connection\ChannelOpenFailureMessage.cs - - - Messages\Connection\ChannelOpenFailureReasons.cs - - - Messages\Connection\ChannelOpen\ChannelOpenInfo.cs - - - Messages\Connection\ChannelOpen\ChannelOpenMessage.cs - - - Messages\Connection\ChannelOpen\DirectTcpipChannelInfo.cs - - - Messages\Connection\ChannelOpen\ForwardedTcpipChannelInfo.cs - - - Messages\Connection\ChannelOpen\SessionChannelOpenInfo.cs - - - Messages\Connection\ChannelOpen\X11ChannelOpenInfo.cs - - - Messages\Connection\ChannelRequest\BreakRequestInfo.cs - - - Messages\Connection\ChannelRequest\ChannelRequestMessage.cs - - - Messages\Connection\ChannelRequest\EndOfWriteRequestInfo.cs - - - Messages\Connection\ChannelRequest\EnvironmentVariableRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExecRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExitSignalRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExitStatusRequestInfo.cs - - - Messages\Connection\ChannelRequest\KeepAliveRequestInfo.cs - - - Messages\Connection\ChannelRequest\PseudoTerminalInfo.cs - - - Messages\Connection\ChannelRequest\RequestInfo.cs - - - Messages\Connection\ChannelRequest\ShellRequestInfo.cs - - - Messages\Connection\ChannelRequest\SignalRequestInfo.cs - - - Messages\Connection\ChannelRequest\SubsystemRequestInfo.cs - - - Messages\Connection\ChannelRequest\WindowChangeRequestInfo.cs - - - Messages\Connection\ChannelRequest\X11ForwardingRequestInfo.cs - - - Messages\Connection\ChannelRequest\XonXoffRequestInfo.cs - - - Messages\Connection\ChannelSuccessMessage.cs - - - Messages\Connection\ChannelWindowAdjustMessage.cs - - - Messages\Connection\GlobalRequestMessage.cs - - - Messages\Connection\GlobalRequestName.cs - - - Messages\Connection\RequestFailureMessage.cs - - - Messages\Connection\RequestSuccessMessage.cs - - - Messages\Connection\TcpIpForwardGlobalRequestMessage.cs - - - Messages\Message.cs - - - Messages\MessageAttribute.cs - - - Messages\ServiceName.cs - - - Messages\Transport\DebugMessage.cs - - - Messages\Transport\DisconnectMessage.cs - - - Messages\Transport\DisconnectReason.cs - - - Messages\Transport\IgnoreMessage.cs - - - Messages\Transport\IKeyExchangedAllowed.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeGroup.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeInit.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeReply.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeRequest.cs - - - Messages\Transport\KeyExchangeDhInitMessage.cs - - - Messages\Transport\KeyExchangeDhReplyMessage.cs - - - Messages\Transport\KeyExchangeEcdhInitMessage.cs - - - Messages\Transport\KeyExchangeEcdhReplyMessage.cs - - - Messages\Transport\KeyExchangeInitMessage.cs - - - Messages\Transport\NewKeysMessage.cs - - - Messages\Transport\ServiceAcceptMessage.cs - - - Messages\Transport\ServiceRequestMessage.cs - - - Messages\Transport\UnimplementedMessage.cs - - - NoneAuthenticationMethod.cs - - - PasswordAuthenticationMethod.cs - - - PasswordConnectionInfo.cs - - - PrivateKeyAuthenticationMethod.cs - - - PrivateKeyConnectionInfo.cs - - - PrivateKeyFile.cs - - - ProxyTypes.cs - - - RemotePathDoubleQuoteTransformation.cs - - - RemotePathNoneTransformation.cs - - - RemotePathShellQuoteTransformation.cs - - - RemotePathTransformation.cs - - - ScpClient.cs - - - Security\Algorithm.cs - - - Security\Cryptography\BouncyCastle\asn1\sec\SECNamedCurves.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9Curve.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECParameters.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECParametersHolder.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECPoint.cs - - - Security\Cryptography\BouncyCastle\crypto\agreement\ECDHCBasicAgreement.cs - - - Security\Cryptography\BouncyCastle\crypto\AsymmetricCipherKeyPair.cs - - - Security\Cryptography\BouncyCastle\crypto\AsymmetricKeyParameter.cs - - - Security\Cryptography\BouncyCastle\crypto\digests\GeneralDigest.cs - - - Security\Cryptography\BouncyCastle\crypto\digests\Sha256Digest.cs - - - Security\Cryptography\BouncyCastle\crypto\generators\ECKeyPairGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\IAsymmetricCipherKeyPairGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\IDigest.cs - - - Security\Cryptography\BouncyCastle\crypto\KeyGenerationParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECDomainParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyGenerationParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECPrivateKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECPublicKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\CryptoApiRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\DigestRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\IRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\util\Pack.cs - - - Security\Cryptography\BouncyCastle\math\BigInteger.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\SimpleBigDecimal.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\Tnaf.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\ZTauElement.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECAlgorithms.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECCurve.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECFieldElement.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECLookupTable.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECPoint.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECPointMap.cs - - - Security\Cryptography\BouncyCastle\math\ec\endo\ECEndomorphism.cs - - - Security\Cryptography\BouncyCastle\math\ec\endo\GlvEndomorphism.cs - - - Security\Cryptography\BouncyCastle\math\ec\LongArray.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\AbstractECMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\ECMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointCombMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointUtilities.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\GlvMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\IPreCompCallback.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\PreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\ValidityPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafL2RMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafUtilities.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\field\FiniteFields.cs - - - Security\Cryptography\BouncyCastle\math\field\GenericPolynomialExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\GF2Polynomial.cs - - - Security\Cryptography\BouncyCastle\math\field\IExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\IFiniteField.cs - - - Security\Cryptography\BouncyCastle\math\field\IPolynomial.cs - - - Security\Cryptography\BouncyCastle\math\field\IPolynomialExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\PrimeField.cs - - - Security\Cryptography\BouncyCastle\math\raw\Mod.cs - - - Security\Cryptography\BouncyCastle\math\raw\Nat.cs - - - Security\Cryptography\BouncyCastle\security\DigestUtilities.cs - - - Security\Cryptography\BouncyCastle\security\SecureRandom.cs - - - Security\Cryptography\BouncyCastle\security\SecurityUtilityException.cs - - - Security\Cryptography\BouncyCastle\util\Arrays.cs - - - Security\Cryptography\BouncyCastle\util\BigIntegers.cs - - - Security\Cryptography\BouncyCastle\util\encoders\Hex.cs - - - Security\Cryptography\BouncyCastle\util\encoders\HexEncoder.cs - - - Security\Cryptography\BouncyCastle\util\IMemoable.cs - - - Security\Cryptography\BouncyCastle\util\Integers.cs - - - Security\Cryptography\BouncyCastle\util\MemoableResetException.cs - - - Security\Cryptography\BouncyCastle\util\Times.cs - - - Security\CertificateHostAlgorithm.cs - - - Security\Cryptography\Chaos.NaCl\CryptoBytes.cs - - - Security\Cryptography\Chaos.NaCl\Ed25519.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Array16.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Array8.cs - - - Security\Cryptography\Chaos.NaCl\Internal\ByteIntegerConverter.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_1.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cmov.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cswap.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_frombytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_invert.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnegative.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnonzero.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul121666.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_neg.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_pow22523.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\FieldElement.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_double_scalarmult.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_frombytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_madd.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_msub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p3.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_dbl.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_dbl.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_cached.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_p2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_precomp_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_scalarmult_base.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_sub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\GroupElement.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\keypair.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\open.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\scalarmult.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_clamp.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_mul_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_reduce.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sign.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sqrtm1.cs - - - Security\Cryptography\Chaos.NaCl\Internal\InternalAssert.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Poly1305Donna.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Salsa\Salsa20.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Salsa\SalsaCore.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Sha512Internal.cs - - - Security\Cryptography\Chaos.NaCl\MontgomeryCurve25519.cs - - - Security\Cryptography\Chaos.NaCl\Sha512.cs - - - Security\Cryptography\AsymmetricCipher.cs - - - Security\Cryptography\Bcrypt.cs - - - Security\Cryptography\BlockCipher.cs - - - Security\Cryptography\Cipher.cs - - - Security\Cryptography\CipherDigitalSignature.cs - - - Security\Cryptography\Ciphers\AesCipher.cs - - - Security\Cryptography\Ciphers\Arc4Cipher.cs - - - Security\Cryptography\Ciphers\BlowfishCipher.cs - - - Security\Cryptography\Ciphers\CastCipher.cs - - - Security\Cryptography\Ciphers\CipherMode.cs - - - Security\Cryptography\Ciphers\CipherPadding.cs - - - Security\Cryptography\Ciphers\DesCipher.cs - - - Security\Cryptography\Ciphers\Modes\CbcCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\CfbCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\CtrCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\OfbCipherMode.cs - - - Security\Cryptography\Ciphers\Paddings\PKCS7Padding.cs - - - Security\Cryptography\Ciphers\Paddings\PKCS5Padding.cs - - - Security\Cryptography\Ciphers\RsaCipher.cs - - - Security\Cryptography\Ciphers\SerpentCipher.cs - - - Security\Cryptography\Ciphers\TripleDesCipher.cs - - - Security\Cryptography\Ciphers\TwofishCipher.cs - - - Security\Cryptography\DigitalSignature.cs - - - Security\Cryptography\DsaDigitalSignature.cs - - - Security\Cryptography\DsaKey.cs - - - Security\Cryptography\ED25519DigitalSignature.cs - - - Security\Cryptography\ED25519Key.cs - - - Security\Cryptography\HMACMD5.cs - - - Security\Cryptography\HMACSHA1.cs - - - Security\Cryptography\HMACSHA256.cs - - - Security\Cryptography\HMACSHA384.cs - - - Security\Cryptography\HMACSHA512.cs - - - Security\Cryptography\Key.cs - - - Security\Cryptography\RsaDigitalSignature.cs - - - Security\Cryptography\RsaKey.cs - - - Security\Cryptography\StreamCipher.cs - - - Security\Cryptography\SymmetricCipher.cs - - - Security\GroupExchangeHashData.cs - - - Security\HostAlgorithm.cs - - - Security\IKeyExchange.cs - - - Security\KeyExchange.cs - - - Security\KeyExchangeDiffieHellman.cs - - - Security\KeyExchangeDiffieHellmanGroup14Sha1.cs - - - Security\KeyExchangeDiffieHellmanGroup14Sha256.cs - - - Security\KeyExchangeDiffieHellmanGroup16Sha512.cs - - - Security\KeyExchangeDiffieHellmanGroup1Sha1.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeSha1.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs - - - Security\KeyExchangeDiffieHellmanGroupSha1.cs - - - Security\KeyExchangeDiffieHellmanGroupSha256.cs - - - Security\KeyExchangeDiffieHellmanGroupSha512.cs - - - Security\KeyExchangeDiffieHellmanGroupShaBase.cs - - - Security\KeyExchangeEC.cs - - - Security\KeyExchangeECCurve25519.cs - - - Security\KeyExchangeECDH.cs - - - Security\KeyExchangeECDH256.cs - - - Security\KeyExchangeECDH384.cs - - - Security\KeyExchangeECDH521.cs - - - Security\KeyExchangeHash.cs - - - Security\KeyHostAlgorithm.cs - - - ServiceFactory.cs - - - Session.cs - - - SftpClient.cs - - - ISftpClient.cs - - - Sftp\Flags.cs - - - Sftp\ISftpFileReader.cs - - - Sftp\ISftpResponseFactory.cs - - - Sftp\ISftpSession.cs - - - Sftp\Requests\ExtendedRequests\FStatVfsRequest.cs - - - Sftp\Requests\ExtendedRequests\HardLinkRequest.cs - - - Sftp\Requests\ExtendedRequests\PosixRenameRequest.cs - - - Sftp\Requests\ExtendedRequests\StatVfsRequest.cs - - - Sftp\Requests\SftpBlockRequest.cs - - - Sftp\Requests\SftpCloseRequest.cs - - - Sftp\Requests\SftpExtendedRequest.cs - - - Sftp\Requests\SftpFSetStatRequest.cs - - - Sftp\Requests\SftpFStatRequest.cs - - - Sftp\Requests\SftpInitRequest.cs - - - Sftp\Requests\SftpLinkRequest.cs - - - Sftp\Requests\SftpLStatRequest.cs - - - Sftp\Requests\SftpMkDirRequest.cs - - - Sftp\Requests\SftpOpenDirRequest.cs - - - Sftp\Requests\SftpOpenRequest.cs - - - Sftp\Requests\SftpReadDirRequest.cs - - - Sftp\Requests\SftpReadLinkRequest.cs - - - Sftp\Requests\SftpReadRequest.cs - - - Sftp\Requests\SftpRealPathRequest.cs - - - Sftp\Requests\SftpRemoveRequest.cs - - - Sftp\Requests\SftpRenameRequest.cs - - - Sftp\Requests\SftpRequest.cs - - - Sftp\Requests\SftpRmDirRequest.cs - - - Sftp\Requests\SftpSetStatRequest.cs - - - Sftp\Requests\SftpStatRequest.cs - - - Sftp\Requests\SftpSymLinkRequest.cs - - - Sftp\Requests\SftpUnblockRequest.cs - - - Sftp\Requests\SftpWriteRequest.cs - - - Sftp\Responses\ExtendedReplies\ExtendedReplyInfo.cs - - - Sftp\Responses\ExtendedReplies\StatVfsReplyInfo.cs - - - Sftp\Responses\SftpAttrsResponse.cs - - - Sftp\Responses\SftpDataResponse.cs - - - Sftp\Responses\SftpExtendedReplyResponse.cs - - - Sftp\Responses\SftpHandleResponse.cs - - - Sftp\Responses\SftpNameResponse.cs - - - Sftp\Responses\SftpResponse.cs - - - Sftp\Responses\SftpStatusResponse.cs - - - Sftp\Responses\SftpVersionResponse.cs - - - Sftp\SftpCloseAsyncResult.cs - - - Sftp\SftpDownloadAsyncResult.cs - - - Sftp\SftpFile.cs - - - Sftp\ISftpFile.cs - - - Sftp\SftpFileAttributes.cs - - - Sftp\SftpFileReader.cs - - - Sftp\SftpFileStream.cs - - - Sftp\SftpFileSystemInformation.cs - - - Sftp\SftpListDirectoryAsyncResult.cs - - - Sftp\SftpMessage.cs - - - Sftp\SftpMessageTypes.cs - - - Sftp\SftpOpenAsyncResult.cs - - - Sftp\SftpReadAsyncResult.cs - - - Sftp\SftpRealPathAsyncResult.cs - - - Sftp\SftpResponseFactory.cs - - - Sftp\SftpSession.cs - - - Sftp\SFtpStatAsyncResult.cs - - - Sftp\SftpSynchronizeDirectoriesAsyncResult.cs - - - Sftp\SftpUploadAsyncResult.cs - - - Sftp\StatusCodes.cs - - - Shell.cs - - - ShellStream.cs - - - SshClient.cs - - - SshCommand.cs - - - SshMessageFactory.cs - - - SubsystemSession.cs - - - - Properties\CommonAssemblyInfo.cs - - - - - Renci.SshNet.snk - - - Designer - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Renci.SshNet.Silverlight/packages.config b/src/Renci.SshNet.Silverlight/packages.config deleted file mode 100644 index c0653dc39..000000000 --- a/src/Renci.SshNet.Silverlight/packages.config +++ /dev/null @@ -1,4 +0,0 @@ -锘 - - - \ No newline at end of file diff --git a/src/Renci.SshNet.Silverlight5/Properties/AssemblyInfo.cs b/src/Renci.SshNet.Silverlight5/Properties/AssemblyInfo.cs deleted file mode 100644 index 7266e1543..000000000 --- a/src/Renci.SshNet.Silverlight5/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -锘縰sing System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("SSH.NET Silverlight 5")] -[assembly: Guid("2b3f6251-8079-48aa-a76b-df70e40092e2")] \ No newline at end of file diff --git a/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj b/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj deleted file mode 100644 index cff69e1cd..000000000 --- a/src/Renci.SshNet.Silverlight5/Renci.SshNet.Silverlight5.csproj +++ /dev/null @@ -1,1463 +0,0 @@ -锘 - - - Debug - AnyCPU - 8.0.50727 - 2.0 - {E367F791-C1EC-4181-912A-2943CAC6B3BC} - {A1591282-1198-4647-A2B1-27E5FF5F6F3B};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - Renci.SshNet - Renci.SshNet - Silverlight - v5.0 - $(TargetFrameworkVersion) - false - true - true - - - - v3.5 - - - true - full - false - Bin\Debug - TRACE;DEBUG;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 - true - true - prompt - 4 - false - Bin\Debug\Renci.SshNet.xml - true - - - none - true - Bin\Release - TRACE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 - true - true - prompt - 4 - false - Bin\Release\Renci.SshNet.xml - - - true - - - true - - - ..\Renci.SshNet.snk - - - - - ..\..\packages\SshNet.Security.Cryptography.1.2.0\lib\sl5\SshNet.Security.Cryptography.dll - True - - - - - - - - - Abstractions\CryptoAbstraction.cs - - - Abstractions\DiagnosticAbstraction.cs - - - Abstractions\DnsAbstraction.cs - - - Abstractions\FileSystemAbstraction.cs - - - Abstractions\ReflectionAbstraction.cs - - - Abstractions\SocketAbstraction.cs - - - Abstractions\ThreadAbstraction.cs - - - AuthenticationMethod.cs - - - AuthenticationResult.cs - - - BaseClient.cs - - - Channels\Channel.cs - - - Channels\ChannelDirectTcpip.cs - - - Channels\ChannelForwardedTcpip.cs - - - Channels\ChannelSession.cs - - - Channels\ChannelTypes.cs - - - Channels\ClientChannel.cs - - - Channels\IChannel.cs - - - Channels\IChannelDirectTcpip.cs - - - Channels\IChannelForwardedTcpip.cs - - - Channels\IChannelSession.cs - - - Channels\ServerChannel.cs - - - CipherInfo.cs - - - ClientAuthentication.cs - - - CommandAsyncResult.cs - - - Common\Array.cs - - - Common\ASCIIEncoding.cs - - - Common\AsyncResult.cs - - - Common\AuthenticationBannerEventArgs.cs - - - Common\AuthenticationEventArgs.cs - - - Common\AuthenticationPasswordChangeEventArgs.cs - - - Common\AuthenticationPrompt.cs - - - Common\AuthenticationPromptEventArgs.cs - - - Common\BigInteger.cs - - - Common\ChannelDataEventArgs.cs - - - Common\ChannelEventArgs.cs - - - Common\ChannelExtendedDataEventArgs.cs - - - Common\ChannelOpenConfirmedEventArgs.cs - - - Common\ChannelOpenFailedEventArgs.cs - - - Common\ChannelRequestEventArgs.cs - - - Common\CountdownEvent.cs - - - Common\DerData.cs - - - Common\ExceptionEventArgs.cs - - - Common\Extensions.cs - - - Common\HostKeyEventArgs.cs - - - Common\ObjectIdentifier.cs - - - Common\Pack.cs - - - Common\PacketDump.cs - - - Common\PipeStream.cs - - - Common\PortForwardEventArgs.cs - - - Common\PosixPath.cs - - - Common\ProxyException.cs - - - Common\ScpDownloadEventArgs.cs - - - Common\ScpException.cs - - - Common\ScpUploadEventArgs.cs - - - Common\SemaphoreLight.cs - - - Common\SftpPathNotFoundException.cs - - - Common\SftpPermissionDeniedException.cs - - - Common\ShellDataEventArgs.cs - - - Common\SshAuthenticationException.cs - - - Common\SshConnectionException.cs - - - Common\SshData.cs - - - Common\SshDataStream.cs - - - Common\SshException.cs - - - Common\SshOperationTimeoutException.cs - - - Common\SshPassPhraseNullOrEmptyException.cs - - - Common\TerminalModes.cs - - - Compression\CompressionMode.cs - - - Compression\Compressor.cs - - - Compression\Zlib.cs - - - Compression\ZlibOpenSsh.cs - - - Compression\ZlibStream.cs - - - ConnectionInfo.cs - - - Connection\ConnectorBase.cs - - - Connection\DirectConnector.cs - - - Connection\HttpConnector.cs - - - Connection\IConnector.cs - - - Connection\IProtocolVersionExchange.cs - - - Connection\ISocketFactory.cs - - - Connection\ProtocolVersionExchange.cs - - - Connection\SocketFactory.cs - - - Connection\Socks4Connector.cs - - - Connection\Socks5Connector.cs - - - Connection\SshIdentification.cs - - - ExpectAction.cs - - - ExpectAsyncResult.cs - - - ForwardedPort.cs - - - ForwardedPortDynamic.cs - - - ForwardedPortLocal.cs - - - ForwardedPortRemote.cs - - - ForwardedPortStatus.cs - - - HashInfo.cs - - - IAuthenticationMethod.cs - - - IClientAuthentication.cs - - - IConnectionInfo.cs - - - IForwardedPort.cs - - - IRemotePathTransformation.cs - - - IServiceFactory.cs - - - ISession.cs - - - ISubsystemSession.cs - - - KeyboardInteractiveAuthenticationMethod.cs - - - KeyboardInteractiveConnectionInfo.cs - - - MessageEventArgs.cs - - - Messages\Authentication\BannerMessage.cs - - - Messages\Authentication\FailureMessage.cs - - - Messages\Authentication\InformationRequestMessage.cs - - - Messages\Authentication\InformationResponseMessage.cs - - - Messages\Authentication\PasswordChangeRequiredMessage.cs - - - Messages\Authentication\PublicKeyMessage.cs - - - Messages\Authentication\RequestMessage.cs - - - Messages\Authentication\RequestMessageHost.cs - - - Messages\Authentication\RequestMessageKeyboardInteractive.cs - - - Messages\Authentication\RequestMessageNone.cs - - - Messages\Authentication\RequestMessagePassword.cs - - - Messages\Authentication\RequestMessagePublicKey.cs - - - Messages\Authentication\SuccessMessage.cs - - - Messages\Connection\CancelTcpIpForwardGlobalRequestMessage.cs - - - Messages\Connection\ChannelCloseMessage.cs - - - Messages\Connection\ChannelDataMessage.cs - - - Messages\Connection\ChannelEofMessage.cs - - - Messages\Connection\ChannelExtendedDataMessage.cs - - - Messages\Connection\ChannelFailureMessage.cs - - - Messages\Connection\ChannelMessage.cs - - - Messages\Connection\ChannelOpenConfirmationMessage.cs - - - Messages\Connection\ChannelOpenFailureMessage.cs - - - Messages\Connection\ChannelOpenFailureReasons.cs - - - Messages\Connection\ChannelOpen\ChannelOpenInfo.cs - - - Messages\Connection\ChannelOpen\ChannelOpenMessage.cs - - - Messages\Connection\ChannelOpen\DirectTcpipChannelInfo.cs - - - Messages\Connection\ChannelOpen\ForwardedTcpipChannelInfo.cs - - - Messages\Connection\ChannelOpen\SessionChannelOpenInfo.cs - - - Messages\Connection\ChannelOpen\X11ChannelOpenInfo.cs - - - Messages\Connection\ChannelRequest\BreakRequestInfo.cs - - - Messages\Connection\ChannelRequest\ChannelRequestMessage.cs - - - Messages\Connection\ChannelRequest\EndOfWriteRequestInfo.cs - - - Messages\Connection\ChannelRequest\EnvironmentVariableRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExecRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExitSignalRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExitStatusRequestInfo.cs - - - Messages\Connection\ChannelRequest\KeepAliveRequestInfo.cs - - - Messages\Connection\ChannelRequest\PseudoTerminalInfo.cs - - - Messages\Connection\ChannelRequest\RequestInfo.cs - - - Messages\Connection\ChannelRequest\ShellRequestInfo.cs - - - Messages\Connection\ChannelRequest\SignalRequestInfo.cs - - - Messages\Connection\ChannelRequest\SubsystemRequestInfo.cs - - - Messages\Connection\ChannelRequest\WindowChangeRequestInfo.cs - - - Messages\Connection\ChannelRequest\X11ForwardingRequestInfo.cs - - - Messages\Connection\ChannelRequest\XonXoffRequestInfo.cs - - - Messages\Connection\ChannelSuccessMessage.cs - - - Messages\Connection\ChannelWindowAdjustMessage.cs - - - Messages\Connection\GlobalRequestMessage.cs - - - Messages\Connection\GlobalRequestName.cs - - - Messages\Connection\RequestFailureMessage.cs - - - Messages\Connection\RequestSuccessMessage.cs - - - Messages\Connection\TcpIpForwardGlobalRequestMessage.cs - - - Messages\Message.cs - - - Messages\MessageAttribute.cs - - - Messages\ServiceName.cs - - - Messages\Transport\DebugMessage.cs - - - Messages\Transport\DisconnectMessage.cs - - - Messages\Transport\DisconnectReason.cs - - - Messages\Transport\IgnoreMessage.cs - - - Messages\Transport\IKeyExchangedAllowed.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeGroup.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeInit.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeReply.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeRequest.cs - - - Messages\Transport\KeyExchangeDhInitMessage.cs - - - Messages\Transport\KeyExchangeDhReplyMessage.cs - - - Messages\Transport\KeyExchangeEcdhInitMessage.cs - - - Messages\Transport\KeyExchangeEcdhReplyMessage.cs - - - Messages\Transport\KeyExchangeInitMessage.cs - - - Messages\Transport\NewKeysMessage.cs - - - Messages\Transport\ServiceAcceptMessage.cs - - - Messages\Transport\ServiceRequestMessage.cs - - - Messages\Transport\UnimplementedMessage.cs - - - NoneAuthenticationMethod.cs - - - PasswordAuthenticationMethod.cs - - - PasswordConnectionInfo.cs - - - PrivateKeyAuthenticationMethod.cs - - - PrivateKeyConnectionInfo.cs - - - PrivateKeyFile.cs - - - ProxyTypes.cs - - - RemotePathDoubleQuoteTransformation.cs - - - RemotePathNoneTransformation.cs - - - RemotePathShellQuoteTransformation.cs - - - RemotePathTransformation.cs - - - ScpClient.cs - - - Security\Algorithm.cs - - - Security\Cryptography\BouncyCastle\asn1\sec\SECNamedCurves.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9Curve.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECParameters.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECParametersHolder.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECPoint.cs - - - Security\Cryptography\BouncyCastle\crypto\agreement\ECDHCBasicAgreement.cs - - - Security\Cryptography\BouncyCastle\crypto\AsymmetricCipherKeyPair.cs - - - Security\Cryptography\BouncyCastle\crypto\AsymmetricKeyParameter.cs - - - Security\Cryptography\BouncyCastle\crypto\digests\GeneralDigest.cs - - - Security\Cryptography\BouncyCastle\crypto\digests\Sha256Digest.cs - - - Security\Cryptography\BouncyCastle\crypto\generators\ECKeyPairGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\IAsymmetricCipherKeyPairGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\IDigest.cs - - - Security\Cryptography\BouncyCastle\crypto\KeyGenerationParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECDomainParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyGenerationParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECPrivateKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECPublicKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\CryptoApiRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\DigestRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\IRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\util\Pack.cs - - - Security\Cryptography\BouncyCastle\math\BigInteger.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\SimpleBigDecimal.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\Tnaf.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\ZTauElement.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECAlgorithms.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECCurve.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECFieldElement.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECLookupTable.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECPoint.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECPointMap.cs - - - Security\Cryptography\BouncyCastle\math\ec\endo\ECEndomorphism.cs - - - Security\Cryptography\BouncyCastle\math\ec\endo\GlvEndomorphism.cs - - - Security\Cryptography\BouncyCastle\math\ec\LongArray.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\AbstractECMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\ECMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointCombMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointUtilities.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\GlvMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\IPreCompCallback.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\PreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\ValidityPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafL2RMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafUtilities.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\field\FiniteFields.cs - - - Security\Cryptography\BouncyCastle\math\field\GenericPolynomialExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\GF2Polynomial.cs - - - Security\Cryptography\BouncyCastle\math\field\IExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\IFiniteField.cs - - - Security\Cryptography\BouncyCastle\math\field\IPolynomial.cs - - - Security\Cryptography\BouncyCastle\math\field\IPolynomialExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\PrimeField.cs - - - Security\Cryptography\BouncyCastle\math\raw\Mod.cs - - - Security\Cryptography\BouncyCastle\math\raw\Nat.cs - - - Security\Cryptography\BouncyCastle\security\DigestUtilities.cs - - - Security\Cryptography\BouncyCastle\security\SecureRandom.cs - - - Security\Cryptography\BouncyCastle\security\SecurityUtilityException.cs - - - Security\Cryptography\BouncyCastle\util\Arrays.cs - - - Security\Cryptography\BouncyCastle\util\BigIntegers.cs - - - Security\Cryptography\BouncyCastle\util\encoders\Hex.cs - - - Security\Cryptography\BouncyCastle\util\encoders\HexEncoder.cs - - - Security\Cryptography\BouncyCastle\util\IMemoable.cs - - - Security\Cryptography\BouncyCastle\util\Integers.cs - - - Security\Cryptography\BouncyCastle\util\MemoableResetException.cs - - - Security\Cryptography\BouncyCastle\util\Times.cs - - - Security\CertificateHostAlgorithm.cs - - - Security\Cryptography\Chaos.NaCl\CryptoBytes.cs - - - Security\Cryptography\Chaos.NaCl\Ed25519.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Array16.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Array8.cs - - - Security\Cryptography\Chaos.NaCl\Internal\ByteIntegerConverter.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_1.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cmov.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cswap.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_frombytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_invert.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnegative.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnonzero.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul121666.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_neg.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_pow22523.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\FieldElement.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_double_scalarmult.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_frombytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_madd.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_msub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p3.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_dbl.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_dbl.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_cached.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_p2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_precomp_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_scalarmult_base.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_sub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\GroupElement.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\keypair.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\open.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\scalarmult.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_clamp.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_mul_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_reduce.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sign.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sqrtm1.cs - - - Security\Cryptography\Chaos.NaCl\Internal\InternalAssert.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Poly1305Donna.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Salsa\Salsa20.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Salsa\SalsaCore.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Sha512Internal.cs - - - Security\Cryptography\Chaos.NaCl\MontgomeryCurve25519.cs - - - Security\Cryptography\Chaos.NaCl\Sha512.cs - - - Security\Cryptography\AsymmetricCipher.cs - - - Security\Cryptography\Bcrypt.cs - - - Security\Cryptography\BlockCipher.cs - - - Security\Cryptography\Cipher.cs - - - Security\Cryptography\CipherDigitalSignature.cs - - - Security\Cryptography\Ciphers\AesCipher.cs - - - Security\Cryptography\Ciphers\Arc4Cipher.cs - - - Security\Cryptography\Ciphers\BlowfishCipher.cs - - - Security\Cryptography\Ciphers\CastCipher.cs - - - Security\Cryptography\Ciphers\CipherMode.cs - - - Security\Cryptography\Ciphers\CipherPadding.cs - - - Security\Cryptography\Ciphers\DesCipher.cs - - - Security\Cryptography\Ciphers\Modes\CbcCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\CfbCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\CtrCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\OfbCipherMode.cs - - - Security\Cryptography\Ciphers\Paddings\PKCS7Padding.cs - - - Security\Cryptography\Ciphers\Paddings\PKCS5Padding.cs - - - Security\Cryptography\Ciphers\RsaCipher.cs - - - Security\Cryptography\Ciphers\SerpentCipher.cs - - - Security\Cryptography\Ciphers\TripleDesCipher.cs - - - Security\Cryptography\Ciphers\TwofishCipher.cs - - - Security\Cryptography\DigitalSignature.cs - - - Security\Cryptography\DsaDigitalSignature.cs - - - Security\Cryptography\DsaKey.cs - - - Security\Cryptography\ED25519DigitalSignature.cs - - - Security\Cryptography\ED25519Key.cs - - - Security\Cryptography\HMACMD5.cs - - - Security\Cryptography\HMACSHA1.cs - - - Security\Cryptography\HMACSHA256.cs - - - Security\Cryptography\HMACSHA384.cs - - - Security\Cryptography\HMACSHA512.cs - - - Security\Cryptography\Key.cs - - - Security\Cryptography\RsaDigitalSignature.cs - - - Security\Cryptography\RsaKey.cs - - - Security\Cryptography\StreamCipher.cs - - - Security\Cryptography\SymmetricCipher.cs - - - Security\GroupExchangeHashData.cs - - - Security\HostAlgorithm.cs - - - Security\IKeyExchange.cs - - - Security\KeyExchange.cs - - - Security\KeyExchangeDiffieHellman.cs - - - Security\KeyExchangeDiffieHellmanGroup14Sha1.cs - - - Security\KeyExchangeDiffieHellmanGroup14Sha256.cs - - - Security\KeyExchangeDiffieHellmanGroup16Sha512.cs - - - Security\KeyExchangeDiffieHellmanGroup1Sha1.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeSha1.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs - - - Security\KeyExchangeDiffieHellmanGroupSha1.cs - - - Security\KeyExchangeDiffieHellmanGroupSha256.cs - - - Security\KeyExchangeDiffieHellmanGroupSha512.cs - - - Security\KeyExchangeDiffieHellmanGroupShaBase.cs - - - Security\KeyExchangeEC.cs - - - Security\KeyExchangeECCurve25519.cs - - - Security\KeyExchangeECDH.cs - - - Security\KeyExchangeECDH256.cs - - - Security\KeyExchangeECDH384.cs - - - Security\KeyExchangeECDH521.cs - - - Security\KeyExchangeHash.cs - - - Security\KeyHostAlgorithm.cs - - - ServiceFactory.cs - - - Session.cs - - - SftpClient.cs - - - ISftpClient.cs - - - Sftp\Flags.cs - - - Sftp\ISftpFileReader.cs - - - Sftp\ISftpResponseFactory.cs - - - Sftp\ISftpSession.cs - - - Sftp\Requests\ExtendedRequests\FStatVfsRequest.cs - - - Sftp\Requests\ExtendedRequests\HardLinkRequest.cs - - - Sftp\Requests\ExtendedRequests\PosixRenameRequest.cs - - - Sftp\Requests\ExtendedRequests\StatVfsRequest.cs - - - Sftp\Requests\SftpBlockRequest.cs - - - Sftp\Requests\SftpCloseRequest.cs - - - Sftp\Requests\SftpExtendedRequest.cs - - - Sftp\Requests\SftpFSetStatRequest.cs - - - Sftp\Requests\SftpFStatRequest.cs - - - Sftp\Requests\SftpInitRequest.cs - - - Sftp\Requests\SftpLinkRequest.cs - - - Sftp\Requests\SftpLStatRequest.cs - - - Sftp\Requests\SftpMkDirRequest.cs - - - Sftp\Requests\SftpOpenDirRequest.cs - - - Sftp\Requests\SftpOpenRequest.cs - - - Sftp\Requests\SftpReadDirRequest.cs - - - Sftp\Requests\SftpReadLinkRequest.cs - - - Sftp\Requests\SftpReadRequest.cs - - - Sftp\Requests\SftpRealPathRequest.cs - - - Sftp\Requests\SftpRemoveRequest.cs - - - Sftp\Requests\SftpRenameRequest.cs - - - Sftp\Requests\SftpRequest.cs - - - Sftp\Requests\SftpRmDirRequest.cs - - - Sftp\Requests\SftpSetStatRequest.cs - - - Sftp\Requests\SftpStatRequest.cs - - - Sftp\Requests\SftpSymLinkRequest.cs - - - Sftp\Requests\SftpUnblockRequest.cs - - - Sftp\Requests\SftpWriteRequest.cs - - - Sftp\Responses\ExtendedReplies\ExtendedReplyInfo.cs - - - Sftp\Responses\ExtendedReplies\StatVfsReplyInfo.cs - - - Sftp\Responses\SftpAttrsResponse.cs - - - Sftp\Responses\SftpDataResponse.cs - - - Sftp\Responses\SftpExtendedReplyResponse.cs - - - Sftp\Responses\SftpHandleResponse.cs - - - Sftp\Responses\SftpNameResponse.cs - - - Sftp\Responses\SftpResponse.cs - - - Sftp\Responses\SftpStatusResponse.cs - - - Sftp\Responses\SftpVersionResponse.cs - - - Sftp\SftpCloseAsyncResult.cs - - - Sftp\SftpDownloadAsyncResult.cs - - - Sftp\SftpFile.cs - - - Sftp\ISftpFile.cs - - - Sftp\SftpFileAttributes.cs - - - Sftp\SftpFileReader.cs - - - Sftp\SftpFileStream.cs - - - Sftp\SftpFileSystemInformation.cs - - - Sftp\SftpListDirectoryAsyncResult.cs - - - Sftp\SftpMessage.cs - - - Sftp\SftpMessageTypes.cs - - - Sftp\SftpOpenAsyncResult.cs - - - Sftp\SftpReadAsyncResult.cs - - - Sftp\SftpRealPathAsyncResult.cs - - - Sftp\SftpResponseFactory.cs - - - Sftp\SftpSession.cs - - - Sftp\SFtpStatAsyncResult.cs - - - Sftp\SftpSynchronizeDirectoriesAsyncResult.cs - - - Sftp\SftpUploadAsyncResult.cs - - - Sftp\StatusCodes.cs - - - Shell.cs - - - ShellStream.cs - - - SshClient.cs - - - SshCommand.cs - - - SshMessageFactory.cs - - - SubsystemSession.cs - - - - Properties\CommonAssemblyInfo.cs - - - - - Renci.SshNet.snk - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Renci.SshNet.Silverlight5/packages.config b/src/Renci.SshNet.Silverlight5/packages.config deleted file mode 100644 index d4c6bef0d..000000000 --- a/src/Renci.SshNet.Silverlight5/packages.config +++ /dev/null @@ -1,4 +0,0 @@ -锘 - - - \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs index 26a8da00e..b9c50e76d 100644 --- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs @@ -56,8 +56,13 @@ protected override void Act() { _client.KeepAliveInterval = _keepAliveInterval; - // allow keep-alive to be sent a few times + // allow keep-alive to be sent a few times. .NET 7 is faster and + // we need to wait less because we want exactly three messages in a session. +#if NETFRAMEWORK Thread.Sleep(195); +#else + Thread.Sleep(180); +#endif } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest.cs b/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest.cs index a5969d354..e2bb4d8c2 100644 --- a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest.cs @@ -1,6 +1,7 @@ 锘縰sing System; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes { @@ -28,7 +29,7 @@ public void Ctor_PartialSuccessLimit_Zero() catch (ArgumentOutOfRangeException ex) { Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format("Cannot be less than one.{0}Parameter name: {1}", Environment.NewLine, ex.ParamName), ex.Message); + ArgumentExceptionAssert.MessageEquals("Cannot be less than one.", ex); Assert.AreEqual("partialSuccessLimit", ex.ParamName); } } @@ -46,7 +47,7 @@ public void Ctor_PartialSuccessLimit_Negative() catch (ArgumentOutOfRangeException ex) { Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format("Cannot be less than one.{0}Parameter name: {1}", Environment.NewLine, ex.ParamName), ex.Message); + ArgumentExceptionAssert.MessageEquals("Cannot be less than one.", ex); Assert.AreEqual("partialSuccessLimit", ex.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs b/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs index 742d9e1e1..6954beb14 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs @@ -1,4 +1,5 @@ 锘縰sing System; +using System.Diagnostics; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; #if !FEATURE_THREAD_COUNTDOWNEVENT @@ -111,16 +112,17 @@ public void Wait_TimeoutInfinite_ShouldBlockUntilCountdownEventIsSet() threads[i].Start(); } - var start = DateTime.Now; + var watch = new Stopwatch(); + watch.Start(); var actual = countdownEvent.Wait(timeout); - var elapsedTime = DateTime.Now - start; + watch.Stop(); Assert.IsTrue(actual); Assert.AreEqual(expectedSignalCount, signalCount); Assert.IsTrue(countdownEvent.IsSet); Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0)); - Assert.IsTrue(elapsedTime >= sleep); - Assert.IsTrue(elapsedTime <= sleep.Add(TimeSpan.FromMilliseconds(100))); + Assert.IsTrue(watch.Elapsed >= sleep); + Assert.IsTrue(watch.Elapsed <= sleep.Add(TimeSpan.FromMilliseconds(100))); countdownEvent.Dispose(); } @@ -150,16 +152,17 @@ public void Wait_ShouldReturnTrueWhenCountdownEventIsSetBeforeTimeoutExpires() threads[i].Start(); } - var start = DateTime.Now; + var watch = new Stopwatch(); + watch.Start(); var actual = countdownEvent.Wait(timeout); - var elapsedTime = DateTime.Now - start; + watch.Stop(); Assert.IsTrue(actual); Assert.AreEqual(expectedSignalCount, signalCount); Assert.IsTrue(countdownEvent.IsSet); Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0)); - Assert.IsTrue(elapsedTime >= sleep); - Assert.IsTrue(elapsedTime <= timeout); + Assert.IsTrue(watch.Elapsed >= sleep); + Assert.IsTrue(watch.Elapsed <= timeout); countdownEvent.Dispose(); } @@ -189,14 +192,14 @@ public void Wait_ShouldReturnFalseWhenTimeoutExpiresBeforeCountdownEventIsSet() threads[i].Start(); } - var start = DateTime.Now; + var watch = new Stopwatch(); + watch.Start(); var actual = countdownEvent.Wait(timeout); - var elapsedTime = DateTime.Now - start; + watch.Stop(); Assert.IsFalse(actual); Assert.IsFalse(countdownEvent.IsSet); Assert.IsFalse(countdownEvent.WaitHandle.WaitOne(0)); - Assert.IsTrue(elapsedTime >= timeout); countdownEvent.Wait(Session.InfiniteTimeSpan); countdownEvent.Dispose(); @@ -239,16 +242,17 @@ public void WaitHandle_WaitOne_TimeoutInfinite_ShouldBlockUntilCountdownEventIsS threads[i].Start(); } - var start = DateTime.Now; + var watch = new Stopwatch(); + watch.Start(); var actual = countdownEvent.WaitHandle.WaitOne(timeout); - var elapsedTime = DateTime.Now - start; + watch.Stop(); Assert.IsTrue(actual); Assert.AreEqual(expectedSignalCount, signalCount); Assert.IsTrue(countdownEvent.IsSet); Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0)); - Assert.IsTrue(elapsedTime >= sleep); - Assert.IsTrue(elapsedTime <= sleep.Add(TimeSpan.FromMilliseconds(100))); + Assert.IsTrue(watch.Elapsed >= sleep); + Assert.IsTrue(watch.Elapsed <= sleep.Add(TimeSpan.FromMilliseconds(100))); countdownEvent.Dispose(); } @@ -278,16 +282,17 @@ public void WaitHandle_WaitOne_ShouldReturnTrueWhenCountdownEventIsSetBeforeTime threads[i].Start(); } - var start = DateTime.Now; + var watch = new Stopwatch(); + watch.Start(); var actual = countdownEvent.Wait(timeout); - var elapsedTime = DateTime.Now - start; + watch.Stop(); Assert.IsTrue(actual); Assert.AreEqual(expectedSignalCount, signalCount); Assert.IsTrue(countdownEvent.IsSet); Assert.IsTrue(countdownEvent.WaitHandle.WaitOne(0)); - Assert.IsTrue(elapsedTime >= sleep); - Assert.IsTrue(elapsedTime <= timeout); + Assert.IsTrue(watch.Elapsed >= sleep); + Assert.IsTrue(watch.Elapsed <= timeout); countdownEvent.Dispose(); } @@ -317,14 +322,14 @@ public void WaitHandle_WaitOne_ShouldReturnFalseWhenTimeoutExpiresBeforeCountdow threads[i].Start(); } - var start = DateTime.Now; + var watch = new Stopwatch(); + watch.Start(); var actual = countdownEvent.WaitHandle.WaitOne(timeout); - var elapsedTime = DateTime.Now - start; + watch.Stop(); Assert.IsFalse(actual); Assert.IsFalse(countdownEvent.IsSet); Assert.IsFalse(countdownEvent.WaitHandle.WaitOne(0)); - Assert.IsTrue(elapsedTime >= timeout); countdownEvent.Wait(Session.InfiniteTimeSpan); countdownEvent.Dispose(); diff --git a/src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs b/src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs index 3b481bf46..845f433ba 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs @@ -1,6 +1,7 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; using System; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Common { @@ -37,11 +38,9 @@ public void Create_ByteArrayAndIndentLevel_IndentLevelLessThanZero() catch (ArgumentOutOfRangeException ex) { Assert.IsNull(ex.InnerException); -#if NETFRAMEWORK - Assert.AreEqual(string.Format("Cannot be less than zero.{0}Parameter name: {1}", Environment.NewLine, ex.ParamName), ex.Message); -#else - Assert.AreEqual(string.Format("Cannot be less than zero. (Parameter '{1}')", Environment.NewLine, ex.ParamName), ex.Message); -#endif + + ArgumentExceptionAssert.MessageEquals("Cannot be less than zero.", ex); + Assert.AreEqual("indentLevel", ex.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs index 1fbd2d158..0b6210046 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs @@ -32,7 +32,6 @@ protected override void Arrange() catch (Exception ex) { _writeException = ex; - throw; } }); _writehread.Start(); diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs index 3af0a3dec..95047cac1 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs @@ -88,7 +88,7 @@ public void ReadingMoreBytesThanAvailableDoesNotBlock() Assert.AreEqual(0, buffer[2]); Assert.AreEqual(0, buffer[3]); } - +#if NETFRAMEWORK [TestMethod] public void WriteCausesSubsequentReadToBlockUntilRequestedNumberOfBytesAreAvailable() { @@ -104,7 +104,10 @@ public void WriteCausesSubsequentReadToBlockUntilRequestedNumberOfBytesAreAvaila readThread.Start(); Assert.IsFalse(readThread.Join(500)); + + // Thread Abort method is obsolete: https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/5.0/thread-abort-obsolete readThread.Abort(); + Assert.AreEqual(int.MaxValue, bytesRead); Assert.AreEqual(0, buffer[0]); @@ -112,5 +115,6 @@ public void WriteCausesSubsequentReadToBlockUntilRequestedNumberOfBytesAreAvaila Assert.AreEqual(0, buffer[2]); Assert.AreEqual(0, buffer[3]); } +#endif } } diff --git a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs index 986ccdea1..7378a30e3 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs @@ -1,6 +1,7 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; using System; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Common { @@ -37,7 +38,7 @@ public void Path_Empty() catch (ArgumentException ex) { Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format("The path is a zero-length string.{0}Parameter name: {1}", Environment.NewLine, ex.ParamName), ex.Message); + ArgumentExceptionAssert.MessageEquals("The path is a zero-length string.", ex); Assert.AreEqual("path", ex.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs b/src/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs index b1d3bfeb0..93322c780 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs @@ -1,4 +1,5 @@ 锘縰sing System; +using System.Diagnostics; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; @@ -58,12 +59,13 @@ public void WaitTest() const int initialCount = 2; var target = new SemaphoreLight(initialCount); - var start = DateTime.Now; + var watch = new Stopwatch(); + watch.Start(); target.Wait(); target.Wait(); - - Assert.IsTrue((DateTime.Now - start).TotalMilliseconds < 50); + + Assert.IsTrue(watch.ElapsedMilliseconds < 50); var releaseThread = new Thread( () => @@ -75,11 +77,10 @@ public void WaitTest() target.Wait(); - var end = DateTime.Now; - var elapsed = end - start; + watch.Stop(); - Assert.IsTrue(elapsed.TotalMilliseconds > 200); - Assert.IsTrue(elapsed.TotalMilliseconds < 250); + Assert.IsTrue(watch.ElapsedMilliseconds > 200); + Assert.IsTrue(watch.ElapsedMilliseconds < 250); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTestBase.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTestBase.cs index 82cfe0c26..1ed56ecd5 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTestBase.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTestBase.cs @@ -24,7 +24,7 @@ protected virtual void SetupData() protected virtual void SetupMocks() { } - + protected sealed override void Arrange() { CreateMocks(); diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs index 72bdca901..cd577ec9c 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs @@ -5,6 +5,7 @@ using System; using System.Net; using System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -76,6 +77,9 @@ protected override void Act() { _actualException = ex; } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs index c94933b2c..59fb77aaa 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -88,6 +89,9 @@ protected override void TearDown() protected override void Act() { _actual = Connector.Connect(_connectionInfo); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs index 277a6f292..dd267ef5d 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -88,6 +89,9 @@ protected override void TearDown() protected override void Act() { _actual = Connector.Connect(_connectionInfo); + + // Give some time to process all messages + Thread.Sleep(400); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs index b9f90019b..77f9091ad 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -81,6 +82,9 @@ protected override void Act() { _actualException = ex; } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs index 704913305..da56fa458 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -92,6 +93,9 @@ protected override void TearDown() protected override void Act() { _actual = Connector.Connect(_connectionInfo); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs index dc0bba593..e89547b66 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -92,6 +93,9 @@ protected override void TearDown() protected override void Act() { _actual = Connector.Connect(_connectionInfo); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs index 235b4dc0a..30cca421e 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -90,6 +91,9 @@ protected override void TearDown() protected override void Act() { _actual = Connector.Connect(_connectionInfo); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs index 9eb0094b7..8edca1811 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -81,6 +82,9 @@ protected override void Act() { _actualException = ex; } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs index 33c222532..d6b71bd04 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -89,6 +90,9 @@ protected override void TearDown() protected override void Act() { _actual = Connector.Connect(_connectionInfo); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs index dad0e74b5..a12558714 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -85,6 +86,9 @@ protected override void TearDown() protected override void Act() { _actual = Connector.Connect(_connectionInfo); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs index 3de1bddb4..0e11e189b 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs @@ -7,6 +7,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -90,6 +91,9 @@ protected override void TearDown() protected override void Act() { _actual = Connector.Connect(_connectionInfo); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs index b1c24fc62..9c219c016 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs @@ -10,6 +10,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -113,6 +114,9 @@ protected override void Act() { _stopWatch.Stop(); } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs index b4d77ec55..a05212312 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs @@ -8,6 +8,7 @@ using System.Globalization; using System.Net; using System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -89,6 +90,9 @@ protected override void Act() { _stopWatch.Stop(); } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs index c01aacc10..fea7a6648 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -79,6 +80,9 @@ protected void Act() { _actualException = ex; } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter.cs index 29792888e..2b3245eef 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter.cs @@ -8,6 +8,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -83,6 +84,9 @@ protected void Act() { _actualException = ex; } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs index ff2bc5e50..b97ba5f8f 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs @@ -8,6 +8,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -84,6 +85,9 @@ protected void Act() { _actualException = ex; } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs index df533ebe7..56ad91011 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs @@ -8,6 +8,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -76,6 +77,9 @@ protected void Arrange() protected void Act() { _actual = _protocolVersionExchange.Start(_clientVersion, _client, _timeout); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs index 8b4f5997e..03c1832df 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs @@ -8,6 +8,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -76,6 +77,9 @@ protected void Arrange() protected void Act() { _actual = _protocolVersionExchange.Start(_clientVersion, _client, _timeout); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs index 98bbf6fe1..f66afe057 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs @@ -8,6 +8,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -76,6 +77,9 @@ protected void Arrange() protected void Act() { _actual = _protocolVersionExchange.Start(_clientVersion, _client, _timeout); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs index 6ef1668ff..238d7e337 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs @@ -8,6 +8,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -81,6 +82,9 @@ protected void Act() { _actualException = ex; } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs index 50f622561..16dc70006 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs @@ -2,6 +2,7 @@ using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; using System.Net; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -32,7 +33,7 @@ protected sealed override void Arrange() SetupData(); SetupMocks(); } - + protected ConnectionInfo CreateConnectionInfo(string proxyUser, string proxyPassword) { return new ConnectionInfo(IPAddress.Loopback.ToString(), diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs index 3ef993f20..e993fa573 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -81,6 +82,9 @@ protected override void Act() { _actualException = ex; } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs index 9f184942a..f4c97c639 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -92,6 +93,9 @@ protected override void TearDown() protected override void Act() { _actual = Connector.Connect(_connectionInfo); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs index df8cc365a..0981e13a9 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs @@ -8,6 +8,7 @@ using System.Globalization; using System.Net; using System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -93,6 +94,9 @@ protected override void Act() { _stopWatch.Stop(); } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs index 501ff8fcf..cdcc667ec 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs @@ -8,6 +8,7 @@ using System.Globalization; using System.Net; using System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -89,6 +90,9 @@ protected override void Act() { _stopWatch.Stop(); } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs index 679d213ad..15751c79a 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs @@ -8,6 +8,7 @@ using System.Globalization; using System.Net; using System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -81,6 +82,9 @@ protected override void Act() { _stopWatch.Stop(); } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs index 2d2f2cb9b..9125fb34e 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs @@ -4,6 +4,7 @@ using System; using System.Net; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs index 7f4b108ca..61afbf71c 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -122,6 +123,9 @@ protected override void TearDown() protected override void Act() { _actual = Connector.Connect(_connectionInfo); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs index dc9a3a9ee..e90bd32c1 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs @@ -5,6 +5,7 @@ using System; using System.Net; using System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -70,6 +71,9 @@ protected override void Act() { _actualException = ex; } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs index 878636ba4..a76a100e2 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs @@ -8,6 +8,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -97,6 +98,9 @@ protected override void Act() { _actualException = ex; } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs index b94c40e8b..a9f7e4ef1 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs @@ -8,6 +8,7 @@ using System.Net; using System.Net.Sockets; using System.Text; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -123,6 +124,9 @@ protected override void TearDown() protected override void Act() { _actual = Connector.Connect(_connectionInfo); + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs index 61db86a4f..5e1d5389b 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -84,6 +85,9 @@ protected override void Act() { _actualException = ex; } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs index 7a0ef5d41..653b41181 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Net; using System.Net.Sockets; +using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -84,6 +85,9 @@ protected override void Act() { _actualException = ex; } + + // Give some time to process all messages + Thread.Sleep(200); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs index d70fea366..0a76674be 100644 --- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs @@ -86,7 +86,7 @@ public void OperationTimeout_LessThanLowerLimit() catch (ArgumentOutOfRangeException ex) { Assert.IsNull(ex.InnerException); - Assert.AreEqual("The timeout must represent a value between -1 and Int32.MaxValue, inclusive." + Environment.NewLine + "Parameter name: " + ex.ParamName, ex.Message); + ArgumentExceptionAssert.MessageEquals("The timeout must represent a value between -1 and Int32.MaxValue, inclusive.", ex); Assert.AreEqual("value", ex.ParamName); } } @@ -105,7 +105,7 @@ public void OperationTimeout_GreaterThanLowerLimit() catch (ArgumentOutOfRangeException ex) { Assert.IsNull(ex.InnerException); - Assert.AreEqual("The timeout must represent a value between -1 and Int32.MaxValue, inclusive." + Environment.NewLine + "Parameter name: " + ex.ParamName, ex.Message); + ArgumentExceptionAssert.MessageEquals("The timeout must represent a value between -1 and Int32.MaxValue, inclusive.", ex); Assert.AreEqual("value", ex.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs index dd7e61e61..620f3dd29 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs @@ -54,11 +54,7 @@ protected override void SetupMocks() .Setup(p => p.SendExecRequest(string.Format("scp -prf {0}", _transformedPath))) .Returns(false); _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); -#if NET35 - _pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose()); -#else _pipeStreamMock.InSequence(sequence).Setup(p => p.Close()); -#endif } protected override void Arrange() @@ -106,11 +102,7 @@ public void DisposeOnChannelShouldBeInvokedOnce() [TestMethod] public void DisposeOnPipeStreamShouldBeInvokedOnce() { -#if NET35 - _pipeStreamMock.As().Verify(p => p.Dispose(), Times.Once); -#else _pipeStreamMock.Verify(p => p.Close(), Times.Once); -#endif } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs index 8d1d1a1a2..f0ea9758a 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs @@ -53,11 +53,7 @@ protected override void SetupMocks() _channelSessionMock.InSequence(sequence) .Setup(p => p.SendExecRequest(string.Format("scp -pf {0}", _transformedPath))).Returns(false); _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); -#if NET35 - _pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose()); -#else _pipeStreamMock.InSequence(sequence).Setup(p => p.Close()); -#endif } protected override void Arrange() @@ -105,11 +101,7 @@ public void DisposeOnChannelShouldBeInvokedOnce() [TestMethod] public void DisposeOnPipeStreamShouldBeInvokedOnce() { -#if NET35 - _pipeStreamMock.As().Verify(p => p.Dispose(), Times.Once); -#else _pipeStreamMock.Verify(p => p.Close(), Times.Once); -#endif } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs index 0fe2566fa..bbb025209 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs @@ -54,11 +54,7 @@ protected override void SetupMocks() .Setup(p => p.SendExecRequest(string.Format("scp -f {0}", _transformedPath))) .Returns(false); _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); -#if NET35 - _pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose()); -#else _pipeStreamMock.InSequence(sequence).Setup(p => p.Close()); -#endif } protected override void Arrange() @@ -116,11 +112,7 @@ public void DisposeOnChannelShouldBeInvokedOnce() [TestMethod] public void DisposeOnPipeStreamShouldBeInvokedOnce() { -#if NET35 - _pipeStreamMock.As().Verify(p => p.Dispose(), Times.Once); -#else _pipeStreamMock.Verify(p => p.Close(), Times.Once); -#endif } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs index 5c8d7c282..f2521136a 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs @@ -53,11 +53,7 @@ protected override void SetupMocks() .Setup(p => p.SendExecRequest(string.Format("scp -r -p -d -t {0}", _transformedPath))) .Returns(false); _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); -#if NET35 - _pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose()); -#else _pipeStreamMock.InSequence(sequence).Setup(p => p.Close()); -#endif } protected override void Arrange() @@ -105,11 +101,7 @@ public void DisposeOnChannelShouldBeInvokedOnce() [TestMethod] public void DisposeOnPipeStreamShouldBeInvokedOnce() { -#if NET35 - _pipeStreamMock.As().Verify(p => p.Dispose(), Times.Once); -#else _pipeStreamMock.Verify(p => p.Close(), Times.Once); -#endif } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs index 57d89d698..782ffe977 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs @@ -59,11 +59,7 @@ protected override void SetupMocks() .Setup(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath))) .Returns(false); _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); -#if NET35 - _pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose()); -#else _pipeStreamMock.InSequence(sequence).Setup(p => p.Close()); -#endif } protected override void Arrange() @@ -122,11 +118,7 @@ public void DisposeOnChannelShouldBeInvokedOnce() [TestMethod] public void DisposeOnPipeStreamShouldBeInvokedOnce() { -#if NET35 - _pipeStreamMock.As().Verify(p => p.Dispose(), Times.Once); -#else _pipeStreamMock.Verify(p => p.Close(), Times.Once); -#endif } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs index 3cae19e67..6e31f4e2a 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs @@ -84,11 +84,7 @@ protected override void SetupMocks() p => p.SendData(It.Is(b => b.SequenceEqual(new byte[] {0})))); _pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0); _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); -#if NET35 - _pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose()); -#else _pipeStreamMock.InSequence(sequence).Setup(p => p.Close()); -#endif } protected override void Arrange() @@ -134,11 +130,7 @@ public void DisposeOnChannelShouldBeInvokedOnce() [TestMethod] public void DisposeOnPipeStreamShouldBeInvokedOnce() { -#if NET35 - _pipeStreamMock.As().Verify(p => p.Dispose(), Times.Once); -#else _pipeStreamMock.Verify(p => p.Close(), Times.Once); -#endif } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs index 21c761134..f253a8da2 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs @@ -57,11 +57,7 @@ protected override void SetupMocks() .Setup(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath))) .Returns(false); _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); -#if NET35 - _pipeStreamMock.As().InSequence(sequence).Setup(p => p.Dispose()); -#else _pipeStreamMock.InSequence(sequence).Setup(p => p.Close()); -#endif } protected override void Arrange() @@ -119,11 +115,7 @@ public void DisposeOnChannelShouldBeInvokedOnce() [TestMethod] public void DisposeOnPipeStreamShouldBeInvokedOnce() { -#if NET35 - _pipeStreamMock.As().Verify(p => p.Dispose(), Times.Once); -#else _pipeStreamMock.Verify(p => p.Close(), Times.Once); -#endif } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs index a177317f3..f17209beb 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs @@ -17,7 +17,7 @@ protected override void Act() ServerSocket.Close(); // give session some time to react to connection reset - Thread.Sleep(200); + Thread.Sleep(300); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs index 506891910..a66e49312 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs @@ -94,11 +94,7 @@ public void OperationTimeout_LessThanLowerLimit() catch (ArgumentOutOfRangeException ex) { Assert.IsNull(ex.InnerException); -#if NETFRAMEWORK - Assert.AreEqual("The timeout must represent a value between -1 and Int32.MaxValue, inclusive." + Environment.NewLine + "Parameter name: " + ex.ParamName, ex.Message); -#else - Assert.AreEqual("The timeout must represent a value between -1 and Int32.MaxValue, inclusive. (Parameter '" + ex.ParamName + "')", ex.Message); -#endif + ArgumentExceptionAssert.MessageEquals("The timeout must represent a value between -1 and Int32.MaxValue, inclusive.", ex); Assert.AreEqual("value", ex.ParamName); } } @@ -117,11 +113,7 @@ public void OperationTimeout_GreaterThanLowerLimit() catch (ArgumentOutOfRangeException ex) { Assert.IsNull(ex.InnerException); -#if NETFRAMEWORK - Assert.AreEqual("The timeout must represent a value between -1 and Int32.MaxValue, inclusive." + Environment.NewLine + "Parameter name: " + ex.ParamName, ex.Message); -#else - Assert.AreEqual("The timeout must represent a value between -1 and Int32.MaxValue, inclusive. (Parameter '" + ex.ParamName + "')", ex.Message); -#endif + ArgumentExceptionAssert.MessageEquals("The timeout must represent a value between -1 and Int32.MaxValue, inclusive.", ex); Assert.AreEqual("value", ex.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Common/ArgumentExceptionAssert.cs b/src/Renci.SshNet.Tests/Common/ArgumentExceptionAssert.cs new file mode 100644 index 000000000..5caee457d --- /dev/null +++ b/src/Renci.SshNet.Tests/Common/ArgumentExceptionAssert.cs @@ -0,0 +1,15 @@ +锘縰sing System; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Renci.SshNet.Tests.Common +{ + public static class ArgumentExceptionAssert + { + public static void MessageEquals(string expected, ArgumentException exception) + { + var newMessage = new ArgumentException(expected, exception.ParamName); + + Assert.AreEqual(newMessage.Message, exception.Message); + } + } +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs b/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs index 5512b15c7..8fa81a301 100644 --- a/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs +++ b/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs @@ -107,12 +107,24 @@ public void Dispose() private void StartListener(object state) { - var listener = (Socket)state; - while (_started) + try { - _acceptCallbackDone.Reset(); - listener.BeginAccept(AcceptCallback, listener); - _acceptCallbackDone.WaitOne(); + var listener = (Socket)state; + while (_started) + { + _acceptCallbackDone.Reset(); + listener.BeginAccept(AcceptCallback, listener); + _acceptCallbackDone.WaitOne(); + } + } + catch (Exception ex) + { + // On .NET framework when Thread throws an exception then unit tests + // were executed without any problem. + // On new .NET exceptions from Thread breaks unit tests session. + Console.Error.WriteLine("[{0}] Failure in StartListener: {1}", + typeof(AsyncSocketListener).FullName, + ex); } } @@ -131,21 +143,38 @@ private void AcceptCallback(IAsyncResult ar) { handler = listener.EndAccept(ar); } + catch (SocketException ex) + { + // The listener is stopped through a Dispose() call, which in turn causes + // Socket.EndAccept(...) to throw a SocketException or + // ObjectDisposedException + // + // Since we consider such an exception normal when the listener is being + // stopped, we only write a message to stderr if the listener is considered + // to be up and running + if (_started) + { + Console.Error.WriteLine("[{0}] Failure accepting new connection: {1}", + typeof(AsyncSocketListener).FullName, + ex); + } + return; + } catch (ObjectDisposedException ex) { // The listener is stopped through a Dispose() call, which in turn causes - // Socket.EndAccept(IAsyncResult) to throw an ObjectDisposedException + // Socket.EndAccept(IAsyncResult) to throw a SocketException or + // ObjectDisposedException // - // Since we consider this ObjectDisposedException normal when the listener - // is being stopped, we only write a message to stderr if the listener - // is considered to be up and running + // Since we consider such an exception normal when the listener is being + // stopped, we only write a message to stderr if the listener is considered + // to be up and running if (_started) { Console.Error.WriteLine("[{0}] Failure accepting new connection: {1}", - typeof(AsyncSocketListener).FullName, - ex); + typeof(AsyncSocketListener).FullName, + ex); } - return; } @@ -164,14 +193,31 @@ private void AcceptCallback(IAsyncResult ar) { handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state); } + catch (SocketException ex) + { + // The listener is stopped through a Dispose() call, which in turn causes + // Socket.BeginReceive(...) to throw a SocketException or + // ObjectDisposedException + // + // Since we consider such an exception normal when the listener is being + // stopped, we only write a message to stderr if the listener is considered + // to be up and running + if (_started) + { + Console.Error.WriteLine("[{0}] Failure receiving new data: {1}", + typeof(AsyncSocketListener).FullName, + ex); + } + } catch (ObjectDisposedException ex) { // The listener is stopped through a Dispose() call, which in turn causes - // Socket.BeginReceive(...) to throw an ObjectDisposedException + // Socket.BeginReceive(...) to throw a SocketException or + // ObjectDisposedException // - // Since we consider this ObjectDisposedException normal when the listener - // is being stopped, we only write a message to stderr if the listener - // is considered to be up and running + // Since we consider such an exception normal when the listener is being + // stopped, we only write a message to stderr if the listener is considered + // to be up and running if (_started) { Console.Error.WriteLine("[{0}] Failure receiving new data: {1}", @@ -192,7 +238,11 @@ private void ReadCallback(IAsyncResult ar) try { // Read data from the client socket. - bytesRead = handler.EndReceive(ar); + bytesRead = handler.EndReceive(ar, out var errorCode); + if (errorCode != SocketError.Success) + { + bytesRead = 0; + } } catch (SocketException ex) { @@ -229,28 +279,7 @@ private void ReadCallback(IAsyncResult ar) return; } - if (bytesRead > 0) - { - var bytesReceived = new byte[bytesRead]; - Array.Copy(state.Buffer, bytesReceived, bytesRead); - SignalBytesReceived(bytesReceived, handler); - - try - { - handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state); - } - catch (SocketException ex) - { - if (!_started) - { - throw new Exception("BeginReceive while stopping!", ex); - } - - throw new Exception("BeginReceive while started!: " + ex.SocketErrorCode + " " + _stackTrace, ex); - } - - } - else + void ConnectionDisconnected() { SignalDisconnected(handler); @@ -262,11 +291,17 @@ private void ReadCallback(IAsyncResult ar) { return; } + try { handler.Shutdown(SocketShutdown.Send); handler.Close(); } + catch (SocketException ex) when (ex.SocketErrorCode == SocketError.ConnectionReset) + { + // On .NET 7 we got Socker Exception with ConnectionReset from Shutdown method + // when the socket is disposed + } catch (SocketException ex) { throw new Exception("Exception in ReadCallback: " + ex.SocketErrorCode + " " + _stackTrace, ex); @@ -280,6 +315,37 @@ private void ReadCallback(IAsyncResult ar) } } } + + if (bytesRead > 0) + { + var bytesReceived = new byte[bytesRead]; + Array.Copy(state.Buffer, bytesReceived, bytesRead); + SignalBytesReceived(bytesReceived, handler); + + try + { + handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state); + } + catch (ObjectDisposedException) + { + // TODO On .NET 7, sometimes we get ObjectDisposedException when _started but only on appveyor, locally it works + ConnectionDisconnected(); + } + catch (SocketException ex) + { + if (!_started) + { + throw new Exception("BeginReceive while stopping!", ex); + } + + throw new Exception("BeginReceive while started!: " + ex.SocketErrorCode + " " + _stackTrace, ex); + } + + } + else + { + ConnectionDisconnected(); + } } private void SignalBytesReceived(byte[] bytesReceived, Socket client) diff --git a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index 3b38bfbe8..b577179e2 100644 --- a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -1,44 +1,15 @@ 锘 - 7.3 - true + 7.3 + true ..\Renci.SshNet.snk + net462;net6.0;net7.0 - - net35;net472;netcoreapp2.1 - - - net35;net472;netcoreapp3.1;net5.0 - - - net472;netcoreapp3.1;net5.0;net6.0 - - - - - - - FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_TPL - - - FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_TPL;FEATURE_TAP - - - FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_TPL;FEATURE_TAP - - - FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_TPL;FEATURE_TAP - - - FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_TPL;FEATURE_TAP - - - FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_TPL;FEATURE_TAP - - + FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_TPL;FEATURE_TAP + @@ -73,18 +44,6 @@ - - - $(MSBuildProgramFiles32)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll - $(MSTestV1UnitTestFrameworkAssemblyCandidate) - - $(MSBuildProgramFiles32)\Microsoft Visual Studio\2017\Professional\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll - $(MSTestV1UnitTestFrameworkAssemblyCandidate) - - $(MSBuildProgramFiles32)\Microsoft Visual Studio\2017\Community\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll - $(MSTestV1UnitTestFrameworkAssemblyCandidate) - - $(MSBuildProgramFiles32)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll @@ -100,17 +59,12 @@ $(MSTestV1UnitTestFrameworkAssemblyCandidate) - - - $(MSTestV1UnitTestFrameworkAssembly) - - - - - - - - + + + + + + diff --git a/src/Renci.SshNet.UAP10/Properties/AssemblyInfo.cs b/src/Renci.SshNet.UAP10/Properties/AssemblyInfo.cs deleted file mode 100644 index f71ba6793..000000000 --- a/src/Renci.SshNet.UAP10/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,10 +0,0 @@ -锘縰sing System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.CompilerServices; - -[assembly: AssemblyTitle("SSH.NET UAP 10.0")] -[assembly: InternalsVisibleTo("Renci.SshNet.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f9194e1eb66b7e2575aaee115ee1d27bc100920e7150e43992d6f668f9737de8b9c7ae892b62b8a36dd1d57929ff1541665d101dc476d6e02390846efae7e5186eec409710fdb596e3f83740afef0d4443055937649bc5a773175b61c57615dac0f0fd10f52b52fedf76c17474cc567b3f7a79de95dde842509fb39aaf69c6c2")] -[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] - -// https://github.com/dotnet/corefx/issues/7274 -//[assembly: Guid("4EE4F2DC-208D-42B2-B286-5E5DEC1DD766")] \ No newline at end of file diff --git a/src/Renci.SshNet.UAP10/Properties/Renci.SshNet.UAP10.rd.xml b/src/Renci.SshNet.UAP10/Properties/Renci.SshNet.UAP10.rd.xml deleted file mode 100644 index ba5e1b0ac..000000000 --- a/src/Renci.SshNet.UAP10/Properties/Renci.SshNet.UAP10.rd.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - diff --git a/src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj b/src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj deleted file mode 100644 index a1f0c994f..000000000 --- a/src/Renci.SshNet.UAP10/Renci.SshNet.UAP10.csproj +++ /dev/null @@ -1,1526 +0,0 @@ -锘 - - - - Debug - AnyCPU - {EC212E04-A372-4B95-B45B-C0D4A739EF80} - Library - Properties - Renci.SshNet - Renci.SshNet - en-US - UAP - 10.0.10240.0 - 10.0.10240.0 - 14 - 512 - {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - - - AnyCPU - true - full - false - bin\Debug\ - TRACE;DEBUG;FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII - prompt - 4 - bin\Debug\Renci.SshNet.xml - true - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE;FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII - prompt - 4 - bin\Release\Renci.SshNet.xml - true - - - x86 - true - bin\x86\Debug\ - TRACE;DEBUG;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII - ;2008 - full - x86 - false - prompt - - - x86 - bin\x86\Release\ - TRACE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII - true - ;2008 - pdbonly - x86 - false - prompt - - - ARM - true - bin\ARM\Debug\ - TRACE;DEBUG;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII - ;2008 - full - ARM - false - prompt - - - ARM - bin\ARM\Release\ - TRACE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII - true - ;2008 - pdbonly - ARM - false - prompt - - - x64 - true - bin\x64\Debug\ - TRACE;DEBUG;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII - ;2008 - full - x64 - false - prompt - - - x64 - bin\x64\Release\ - TRACE;FEATURE_DATAGRAMSOCKET;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_ENCODING_ASCII - true - ;2008 - pdbonly - x64 - false - prompt - - - - - - - - Abstractions\CryptoAbstraction.cs - - - Abstractions\DiagnosticAbstraction.cs - - - Abstractions\DnsAbstraction.cs - - - Abstractions\FileSystemAbstraction.cs - - - Abstractions\ReflectionAbstraction.cs - - - Abstractions\SocketAbstraction.cs - - - Abstractions\ThreadAbstraction.cs - - - AuthenticationMethod.cs - - - AuthenticationResult.cs - - - BaseClient.cs - - - Channels\Channel.cs - - - Channels\ChannelDirectTcpip.cs - - - Channels\ChannelForwardedTcpip.cs - - - Channels\ChannelSession.cs - - - Channels\ChannelTypes.cs - - - Channels\ClientChannel.cs - - - Channels\IChannel.cs - - - Channels\IChannelDirectTcpip.cs - - - Channels\IChannelForwardedTcpip.cs - - - Channels\IChannelSession.cs - - - Channels\ServerChannel.cs - - - CipherInfo.cs - - - ClientAuthentication.cs - - - CommandAsyncResult.cs - - - Common\Array.cs - - - Common\ASCIIEncoding.cs - - - Common\AsyncResult.cs - - - Common\AuthenticationBannerEventArgs.cs - - - Common\AuthenticationEventArgs.cs - - - Common\AuthenticationPasswordChangeEventArgs.cs - - - Common\AuthenticationPrompt.cs - - - Common\AuthenticationPromptEventArgs.cs - - - Common\BigInteger.cs - - - Common\ChannelDataEventArgs.cs - - - Common\ChannelEventArgs.cs - - - Common\ChannelExtendedDataEventArgs.cs - - - Common\ChannelOpenConfirmedEventArgs.cs - - - Common\ChannelOpenFailedEventArgs.cs - - - Common\ChannelRequestEventArgs.cs - - - Common\CountdownEvent.cs - - - Common\DerData.cs - - - Common\ExceptionEventArgs.cs - - - Common\Extensions.cs - - - Common\HostKeyEventArgs.cs - - - Common\NetConfServerException.cs - - - Common\ObjectIdentifier.cs - - - Common\Pack.cs - - - Common\PacketDump.cs - - - Common\PipeStream.cs - - - Common\PortForwardEventArgs.cs - - - Common\PosixPath.cs - - - Common\ProxyException.cs - - - Common\ScpDownloadEventArgs.cs - - - Common\ScpException.cs - - - Common\ScpUploadEventArgs.cs - - - Common\SemaphoreLight.cs - - - Common\SftpPathNotFoundException.cs - - - Common\SftpPermissionDeniedException.cs - - - Common\ShellDataEventArgs.cs - - - Common\SshAuthenticationException.cs - - - Common\SshConnectionException.cs - - - Common\SshData.cs - - - Common\SshDataStream.cs - - - Common\SshException.cs - - - Common\SshOperationTimeoutException.cs - - - Common\SshPassPhraseNullOrEmptyException.cs - - - Common\TerminalModes.cs - - - Compression\CompressionMode.cs - - - Compression\Compressor.cs - - - Compression\Zlib.cs - - - Compression\ZlibOpenSsh.cs - - - Compression\ZlibStream.cs - - - ConnectionInfo.cs - - - Connection\ConnectorBase.cs - - - Connection\DirectConnector.cs - - - Connection\HttpConnector.cs - - - Connection\IConnector.cs - - - Connection\IProtocolVersionExchange.cs - - - Connection\ISocketFactory.cs - - - Connection\ProtocolVersionExchange.cs - - - Connection\SocketFactory.cs - - - Connection\Socks4Connector.cs - - - Connection\Socks5Connector.cs - - - Connection\SshIdentification.cs - - - ExpectAction.cs - - - ExpectAsyncResult.cs - - - ForwardedPort.cs - - - ForwardedPortDynamic.cs - - - ForwardedPortDynamic.NET.cs - - - ForwardedPortLocal.cs - - - ForwardedPortLocal.NET.cs - - - ForwardedPortRemote.cs - - - ForwardedPortStatus.cs - - - HashInfo.cs - - - IAuthenticationMethod.cs - - - IClientAuthentication.cs - - - IConnectionInfo.cs - - - IForwardedPort.cs - - - IRemotePathTransformation.cs - - - IServiceFactory.cs - - - IServiceFactory.NET.cs - - - ISession.cs - - - ISftpClient.cs - - - ISubsystemSession.cs - - - KeyboardInteractiveAuthenticationMethod.cs - - - KeyboardInteractiveConnectionInfo.cs - - - MessageEventArgs.cs - - - Messages\Authentication\BannerMessage.cs - - - Messages\Authentication\FailureMessage.cs - - - Messages\Authentication\InformationRequestMessage.cs - - - Messages\Authentication\InformationResponseMessage.cs - - - Messages\Authentication\PasswordChangeRequiredMessage.cs - - - Messages\Authentication\PublicKeyMessage.cs - - - Messages\Authentication\RequestMessage.cs - - - Messages\Authentication\RequestMessageHost.cs - - - Messages\Authentication\RequestMessageKeyboardInteractive.cs - - - Messages\Authentication\RequestMessageNone.cs - - - Messages\Authentication\RequestMessagePassword.cs - - - Messages\Authentication\RequestMessagePublicKey.cs - - - Messages\Authentication\SuccessMessage.cs - - - Messages\Connection\CancelTcpIpForwardGlobalRequestMessage.cs - - - Messages\Connection\ChannelCloseMessage.cs - - - Messages\Connection\ChannelDataMessage.cs - - - Messages\Connection\ChannelEofMessage.cs - - - Messages\Connection\ChannelExtendedDataMessage.cs - - - Messages\Connection\ChannelFailureMessage.cs - - - Messages\Connection\ChannelMessage.cs - - - Messages\Connection\ChannelOpenConfirmationMessage.cs - - - Messages\Connection\ChannelOpenFailureMessage.cs - - - Messages\Connection\ChannelOpenFailureReasons.cs - - - Messages\Connection\ChannelOpen\ChannelOpenInfo.cs - - - Messages\Connection\ChannelOpen\ChannelOpenMessage.cs - - - Messages\Connection\ChannelOpen\DirectTcpipChannelInfo.cs - - - Messages\Connection\ChannelOpen\ForwardedTcpipChannelInfo.cs - - - Messages\Connection\ChannelOpen\SessionChannelOpenInfo.cs - - - Messages\Connection\ChannelOpen\X11ChannelOpenInfo.cs - - - Messages\Connection\ChannelRequest\BreakRequestInfo.cs - - - Messages\Connection\ChannelRequest\ChannelRequestMessage.cs - - - Messages\Connection\ChannelRequest\EndOfWriteRequestInfo.cs - - - Messages\Connection\ChannelRequest\EnvironmentVariableRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExecRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExitSignalRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExitStatusRequestInfo.cs - - - Messages\Connection\ChannelRequest\KeepAliveRequestInfo.cs - - - Messages\Connection\ChannelRequest\PseudoTerminalInfo.cs - - - Messages\Connection\ChannelRequest\RequestInfo.cs - - - Messages\Connection\ChannelRequest\ShellRequestInfo.cs - - - Messages\Connection\ChannelRequest\SignalRequestInfo.cs - - - Messages\Connection\ChannelRequest\SubsystemRequestInfo.cs - - - Messages\Connection\ChannelRequest\WindowChangeRequestInfo.cs - - - Messages\Connection\ChannelRequest\X11ForwardingRequestInfo.cs - - - Messages\Connection\ChannelRequest\XonXoffRequestInfo.cs - - - Messages\Connection\ChannelSuccessMessage.cs - - - Messages\Connection\ChannelWindowAdjustMessage.cs - - - Messages\Connection\GlobalRequestMessage.cs - - - Messages\Connection\GlobalRequestName.cs - - - Messages\Connection\RequestFailureMessage.cs - - - Messages\Connection\RequestSuccessMessage.cs - - - Messages\Connection\TcpIpForwardGlobalRequestMessage.cs - - - Messages\Message.cs - - - Messages\MessageAttribute.cs - - - Messages\ServiceName.cs - - - Messages\Transport\DebugMessage.cs - - - Messages\Transport\DisconnectMessage.cs - - - Messages\Transport\DisconnectReason.cs - - - Messages\Transport\IgnoreMessage.cs - - - Messages\Transport\IKeyExchangedAllowed.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeGroup.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeInit.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeReply.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeRequest.cs - - - Messages\Transport\KeyExchangeDhInitMessage.cs - - - Messages\Transport\KeyExchangeDhReplyMessage.cs - - - Messages\Transport\KeyExchangeEcdhInitMessage.cs - - - Messages\Transport\KeyExchangeEcdhReplyMessage.cs - - - Messages\Transport\KeyExchangeInitMessage.cs - - - Messages\Transport\NewKeysMessage.cs - - - Messages\Transport\ServiceAcceptMessage.cs - - - Messages\Transport\ServiceRequestMessage.cs - - - Messages\Transport\UnimplementedMessage.cs - - - NetConfClient.cs - - - Netconf\INetConfSession.cs - - - Netconf\NetConfSession.cs - - - NoneAuthenticationMethod.cs - - - PasswordAuthenticationMethod.cs - - - PasswordConnectionInfo.cs - - - PrivateKeyAuthenticationMethod.cs - - - PrivateKeyConnectionInfo.cs - - - PrivateKeyFile.cs - - - Properties\CommonAssemblyInfo.cs - - - ProxyTypes.cs - - - RemotePathDoubleQuoteTransformation.cs - - - RemotePathNoneTransformation.cs - - - RemotePathShellQuoteTransformation.cs - - - RemotePathTransformation.cs - - - ScpClient.cs - - - ScpClient.NET.cs - - - Security\Algorithm.cs - - - Security\Cryptography\BouncyCastle\asn1\sec\SECNamedCurves.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9Curve.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECParameters.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECParametersHolder.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECPoint.cs - - - Security\Cryptography\BouncyCastle\crypto\agreement\ECDHCBasicAgreement.cs - - - Security\Cryptography\BouncyCastle\crypto\AsymmetricCipherKeyPair.cs - - - Security\Cryptography\BouncyCastle\crypto\AsymmetricKeyParameter.cs - - - Security\Cryptography\BouncyCastle\crypto\digests\GeneralDigest.cs - - - Security\Cryptography\BouncyCastle\crypto\digests\Sha256Digest.cs - - - Security\Cryptography\BouncyCastle\crypto\generators\ECKeyPairGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\IAsymmetricCipherKeyPairGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\IDigest.cs - - - Security\Cryptography\BouncyCastle\crypto\KeyGenerationParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECDomainParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyGenerationParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECPrivateKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECPublicKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\CryptoApiRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\DigestRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\IRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\util\Pack.cs - - - Security\Cryptography\BouncyCastle\math\BigInteger.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\SimpleBigDecimal.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\Tnaf.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\ZTauElement.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECAlgorithms.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECCurve.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECFieldElement.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECLookupTable.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECPoint.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECPointMap.cs - - - Security\Cryptography\BouncyCastle\math\ec\endo\ECEndomorphism.cs - - - Security\Cryptography\BouncyCastle\math\ec\endo\GlvEndomorphism.cs - - - Security\Cryptography\BouncyCastle\math\ec\LongArray.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\AbstractECMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\ECMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointCombMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointUtilities.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\GlvMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\IPreCompCallback.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\PreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\ValidityPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafL2RMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafUtilities.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\field\FiniteFields.cs - - - Security\Cryptography\BouncyCastle\math\field\GenericPolynomialExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\GF2Polynomial.cs - - - Security\Cryptography\BouncyCastle\math\field\IExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\IFiniteField.cs - - - Security\Cryptography\BouncyCastle\math\field\IPolynomial.cs - - - Security\Cryptography\BouncyCastle\math\field\IPolynomialExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\PrimeField.cs - - - Security\Cryptography\BouncyCastle\math\raw\Mod.cs - - - Security\Cryptography\BouncyCastle\math\raw\Nat.cs - - - Security\Cryptography\BouncyCastle\security\DigestUtilities.cs - - - Security\Cryptography\BouncyCastle\security\SecureRandom.cs - - - Security\Cryptography\BouncyCastle\security\SecurityUtilityException.cs - - - Security\Cryptography\BouncyCastle\util\Arrays.cs - - - Security\Cryptography\BouncyCastle\util\BigIntegers.cs - - - Security\Cryptography\BouncyCastle\util\encoders\Hex.cs - - - Security\Cryptography\BouncyCastle\util\encoders\HexEncoder.cs - - - Security\Cryptography\BouncyCastle\util\IMemoable.cs - - - Security\Cryptography\BouncyCastle\util\Integers.cs - - - Security\Cryptography\BouncyCastle\util\MemoableResetException.cs - - - Security\Cryptography\BouncyCastle\util\Times.cs - - - Security\CertificateHostAlgorithm.cs - - - Security\Cryptography\Chaos.NaCl\CryptoBytes.cs - - - Security\Cryptography\Chaos.NaCl\Ed25519.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Array16.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Array8.cs - - - Security\Cryptography\Chaos.NaCl\Internal\ByteIntegerConverter.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_1.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cmov.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cswap.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_frombytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_invert.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnegative.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnonzero.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul121666.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_neg.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_pow22523.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\FieldElement.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_double_scalarmult.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_frombytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_madd.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_msub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p3.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_dbl.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_dbl.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_cached.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_p2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_precomp_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_scalarmult_base.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_sub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\GroupElement.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\keypair.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\open.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\scalarmult.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_clamp.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_mul_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_reduce.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sign.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sqrtm1.cs - - - Security\Cryptography\Chaos.NaCl\Internal\InternalAssert.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Poly1305Donna.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Salsa\Salsa20.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Salsa\SalsaCore.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Sha512Internal.cs - - - Security\Cryptography\Chaos.NaCl\MontgomeryCurve25519.cs - - - Security\Cryptography\Chaos.NaCl\Sha512.cs - - - Security\Cryptography\AsymmetricCipher.cs - - - Security\Cryptography\Bcrypt.cs - - - Security\Cryptography\BlockCipher.cs - - - Security\Cryptography\Cipher.cs - - - Security\Cryptography\CipherDigitalSignature.cs - - - Security\Cryptography\Ciphers\AesCipher.cs - - - Security\Cryptography\Ciphers\Arc4Cipher.cs - - - Security\Cryptography\Ciphers\BlowfishCipher.cs - - - Security\Cryptography\Ciphers\CastCipher.cs - - - Security\Cryptography\Ciphers\CipherMode.cs - - - Security\Cryptography\Ciphers\CipherPadding.cs - - - Security\Cryptography\Ciphers\DesCipher.cs - - - Security\Cryptography\Ciphers\Modes\CbcCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\CfbCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\CtrCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\OfbCipherMode.cs - - - Security\Cryptography\Ciphers\Paddings\PKCS5Padding.cs - - - Security\Cryptography\Ciphers\Paddings\PKCS7Padding.cs - - - Security\Cryptography\Ciphers\RsaCipher.cs - - - Security\Cryptography\Ciphers\SerpentCipher.cs - - - Security\Cryptography\Ciphers\TripleDesCipher.cs - - - Security\Cryptography\Ciphers\TwofishCipher.cs - - - Security\Cryptography\DigitalSignature.cs - - - Security\Cryptography\DsaDigitalSignature.cs - - - Security\Cryptography\DsaKey.cs - - - Security\Cryptography\ED25519DigitalSignature.cs - - - Security\Cryptography\ED25519Key.cs - - - Security\Cryptography\HMACMD5.cs - - - Security\Cryptography\HMACSHA1.cs - - - Security\Cryptography\HMACSHA256.cs - - - Security\Cryptography\HMACSHA384.cs - - - Security\Cryptography\HMACSHA512.cs - - - Security\Cryptography\Key.cs - - - Security\Cryptography\EcdsaDigitalSignature.cs - - - Security\Cryptography\EcdsaKey.cs - - - Security\Cryptography\RsaDigitalSignature.cs - - - Security\Cryptography\RsaKey.cs - - - Security\Cryptography\StreamCipher.cs - - - Security\Cryptography\SymmetricCipher.cs - - - Security\GroupExchangeHashData.cs - - - Security\HostAlgorithm.cs - - - Security\IKeyExchange.cs - - - Security\KeyExchange.cs - - - Security\KeyExchangeDiffieHellman.cs - - - Security\KeyExchangeDiffieHellmanGroup14Sha1.cs - - - Security\KeyExchangeDiffieHellmanGroup14Sha256.cs - - - Security\KeyExchangeDiffieHellmanGroup16Sha512.cs - - - Security\KeyExchangeDiffieHellmanGroup1Sha1.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeSha1.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs - - - Security\KeyExchangeDiffieHellmanGroupSha1.cs - - - Security\KeyExchangeDiffieHellmanGroupSha256.cs - - - Security\KeyExchangeDiffieHellmanGroupSha512.cs - - - Security\KeyExchangeDiffieHellmanGroupShaBase.cs - - - Security\KeyExchangeEC.cs - - - Security\KeyExchangeECCurve25519.cs - - - Security\KeyExchangeECDH.cs - - - Security\KeyExchangeECDH256.cs - - - Security\KeyExchangeECDH384.cs - - - Security\KeyExchangeECDH521.cs - - - Security\KeyExchangeHash.cs - - - Security\KeyHostAlgorithm.cs - - - ServiceFactory.cs - - - ServiceFactory.NET.cs - - - Session.cs - - - SftpClient.cs - - - Sftp\Flags.cs - - - Sftp\ISftpFileReader.cs - - - Sftp\ISftpResponseFactory.cs - - - Sftp\ISftpSession.cs - - - Sftp\Requests\ExtendedRequests\FStatVfsRequest.cs - - - Sftp\Requests\ExtendedRequests\HardLinkRequest.cs - - - Sftp\Requests\ExtendedRequests\PosixRenameRequest.cs - - - Sftp\Requests\ExtendedRequests\StatVfsRequest.cs - - - Sftp\Requests\SftpBlockRequest.cs - - - Sftp\Requests\SftpCloseRequest.cs - - - Sftp\Requests\SftpExtendedRequest.cs - - - Sftp\Requests\SftpFSetStatRequest.cs - - - Sftp\Requests\SftpFStatRequest.cs - - - Sftp\Requests\SftpInitRequest.cs - - - Sftp\Requests\SftpLinkRequest.cs - - - Sftp\Requests\SftpLStatRequest.cs - - - Sftp\Requests\SftpMkDirRequest.cs - - - Sftp\Requests\SftpOpenDirRequest.cs - - - Sftp\Requests\SftpOpenRequest.cs - - - Sftp\Requests\SftpReadDirRequest.cs - - - Sftp\Requests\SftpReadLinkRequest.cs - - - Sftp\Requests\SftpReadRequest.cs - - - Sftp\Requests\SftpRealPathRequest.cs - - - Sftp\Requests\SftpRemoveRequest.cs - - - Sftp\Requests\SftpRenameRequest.cs - - - Sftp\Requests\SftpRequest.cs - - - Sftp\Requests\SftpRmDirRequest.cs - - - Sftp\Requests\SftpSetStatRequest.cs - - - Sftp\Requests\SftpStatRequest.cs - - - Sftp\Requests\SftpSymLinkRequest.cs - - - Sftp\Requests\SftpUnblockRequest.cs - - - Sftp\Requests\SftpWriteRequest.cs - - - Sftp\Responses\ExtendedReplies\ExtendedReplyInfo.cs - - - Sftp\Responses\ExtendedReplies\StatVfsReplyInfo.cs - - - Sftp\Responses\SftpAttrsResponse.cs - - - Sftp\Responses\SftpDataResponse.cs - - - Sftp\Responses\SftpExtendedReplyResponse.cs - - - Sftp\Responses\SftpHandleResponse.cs - - - Sftp\Responses\SftpNameResponse.cs - - - Sftp\Responses\SftpResponse.cs - - - Sftp\Responses\SftpStatusResponse.cs - - - Sftp\Responses\SftpVersionResponse.cs - - - Sftp\SftpCloseAsyncResult.cs - - - Sftp\SftpDownloadAsyncResult.cs - - - Sftp\SftpFile.cs - - - Sftp\ISftpFile.cs - - - Sftp\SftpFileAttributes.cs - - - Sftp\SftpFileReader.cs - - - Sftp\SftpFileStream.cs - - - Sftp\SftpFileSystemInformation.cs - - - Sftp\SftpListDirectoryAsyncResult.cs - - - Sftp\SftpMessage.cs - - - Sftp\SftpMessageTypes.cs - - - Sftp\SftpOpenAsyncResult.cs - - - Sftp\SftpReadAsyncResult.cs - - - Sftp\SftpRealPathAsyncResult.cs - - - Sftp\SftpResponseFactory.cs - - - Sftp\SftpSession.cs - - - Sftp\SFtpStatAsyncResult.cs - - - Sftp\SftpSynchronizeDirectoriesAsyncResult.cs - - - Sftp\SftpUploadAsyncResult.cs - - - Sftp\StatusCodes.cs - - - Shell.cs - - - ShellStream.cs - - - SshClient.cs - - - SshCommand.cs - - - SshMessageFactory.cs - - - SubsystemSession.cs - - - - - - 14.0 - - - - \ No newline at end of file diff --git a/src/Renci.SshNet.UAP10/project.json b/src/Renci.SshNet.UAP10/project.json deleted file mode 100644 index 6916d5e63..000000000 --- a/src/Renci.SshNet.UAP10/project.json +++ /dev/null @@ -1,18 +0,0 @@ -锘縶 - "dependencies": { - "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.0", - "SshNet.Security.Cryptography": "1.2.0", - "System.Xml.XPath.XmlDocument": "4.0.1" - }, - "frameworks": { - "uap10.0": {} - }, - "runtimes": { - "win10-arm": {}, - "win10-arm-aot": {}, - "win10-x86": {}, - "win10-x86-aot": {}, - "win10-x64": {}, - "win10-x64-aot": {} - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.VS2012.sln b/src/Renci.SshNet.VS2012.sln deleted file mode 100644 index a80b19085..000000000 --- a/src/Renci.SshNet.VS2012.sln +++ /dev/null @@ -1,108 +0,0 @@ -锘 -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2012 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.Silverlight", "Renci.SshNet.Silverlight\Renci.SshNet.Silverlight.csproj", "{77C294BB-1DC2-49DC-BE16-963F8F22794D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.WindowsPhone", "Renci.SshNet.WindowsPhone\Renci.SshNet.WindowsPhone.csproj", "{3AD3EDF0-702E-4A91-8735-DCE4659AA54C}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.Silverlight5", "Renci.SshNet.Silverlight5\Renci.SshNet.Silverlight5.csproj", "{E367F791-C1EC-4181-912A-2943CAC6B3BC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.WindowsPhone8", "Renci.SshNet.WindowsPhone8\Renci.SshNet.WindowsPhone8.csproj", "{4A6CA785-1C8A-47FE-98C0-30C675A9328B}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D}" - ProjectSection(SolutionItems) = preProject - ..\build\build.proj = ..\build\build.proj - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{94EE3919-19FA-4D9B-8DA9-249050B15232}" - ProjectSection(SolutionItems) = preProject - ..\build\nuget\SSH.NET.nuspec = ..\build\nuget\SSH.NET.nuspec - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandcastle", "sandcastle", "{A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1}" - ProjectSection(SolutionItems) = preProject - ..\build\sandcastle\SSH.NET.shfbproj = ..\build\sandcastle\SSH.NET.shfbproj - EndProjectSection -EndProject -Global - GlobalSection(TestCaseManagementSettings) = postSolution - CategoryFile = Renci.SshNet1.vsmdi - EndGlobalSection - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|ARM = Debug|ARM - Debug|Mixed Platforms = Debug|Mixed Platforms - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|ARM = Release|ARM - Release|Mixed Platforms = Release|Mixed Platforms - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Debug|ARM.ActiveCfg = Debug|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Debug|x64.ActiveCfg = Debug|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Debug|x86.ActiveCfg = Debug|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|Any CPU.Build.0 = Release|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|ARM.ActiveCfg = Release|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|x64.ActiveCfg = Release|Any CPU - {77C294BB-1DC2-49DC-BE16-963F8F22794D}.Release|x86.ActiveCfg = Release|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Debug|ARM.ActiveCfg = Debug|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Debug|x64.ActiveCfg = Debug|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Debug|x86.ActiveCfg = Debug|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Release|Any CPU.Build.0 = Release|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Release|ARM.ActiveCfg = Release|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Release|x64.ActiveCfg = Release|Any CPU - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C}.Release|x86.ActiveCfg = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|ARM.ActiveCfg = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|x64.ActiveCfg = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|x86.ActiveCfg = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|Any CPU.Build.0 = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|ARM.ActiveCfg = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|x64.ActiveCfg = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|x86.ActiveCfg = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|ARM.ActiveCfg = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|x64.ActiveCfg = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|x86.ActiveCfg = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|Any CPU.Build.0 = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|ARM.ActiveCfg = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|x64.ActiveCfg = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|x86.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {94EE3919-19FA-4D9B-8DA9-249050B15232} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} - {A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} - EndGlobalSection -EndGlobal diff --git a/src/Renci.SshNet.VS2015.sln b/src/Renci.SshNet.VS2015.sln deleted file mode 100644 index 81fa71554..000000000 --- a/src/Renci.SshNet.VS2015.sln +++ /dev/null @@ -1,130 +0,0 @@ -锘 -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D}" - ProjectSection(SolutionItems) = preProject - ..\build\build.proj = ..\build\build.proj - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{94EE3919-19FA-4D9B-8DA9-249050B15232}" - ProjectSection(SolutionItems) = preProject - ..\build\nuget\SSH.NET.nuspec = ..\build\nuget\SSH.NET.nuspec - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandcastle", "sandcastle", "{A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1}" - ProjectSection(SolutionItems) = preProject - ..\build\sandcastle\SSH.NET.shfbproj = ..\build\sandcastle\SSH.NET.shfbproj - EndProjectSection -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.Silverlight5", "Renci.SshNet.Silverlight5\Renci.SshNet.Silverlight5.csproj", "{E367F791-C1EC-4181-912A-2943CAC6B3BC}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.WindowsPhone8", "Renci.SshNet.WindowsPhone8\Renci.SshNet.WindowsPhone8.csproj", "{4A6CA785-1C8A-47FE-98C0-30C675A9328B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.UAP10", "Renci.SshNet.UAP10\Renci.SshNet.UAP10.csproj", "{EC212E04-A372-4B95-B45B-C0D4A739EF80}" -EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Renci.SshNet.Shared.Tests", "..\test\Renci.SshNet.Shared.Tests\Renci.SshNet.Shared.Tests.shproj", "{FAE3948F-A438-458E-8E0E-7F6E39A5DD8A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet.WindowsPhone8.Tests", "..\test\Renci.SshNet.WindowsPhone8.Tests\Renci.SshNet.WindowsPhone8.Tests.csproj", "{26F0D644-B3EF-47DF-8040-E9E4B2E63884}" -EndProject -Global - GlobalSection(SharedMSBuildProjectFiles) = preSolution - ..\test\Renci.SshNet.Shared.Tests\Renci.SshNet.Shared.Tests.projitems*{26f0d644-b3ef-47df-8040-e9e4b2e63884}*SharedItemsImports = 4 - ..\test\Renci.SshNet.Shared.Tests\Renci.SshNet.Shared.Tests.projitems*{fae3948f-a438-458e-8e0e-7f6e39a5dd8a}*SharedItemsImports = 13 - EndGlobalSection - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|ARM = Debug|ARM - Debug|Mixed Platforms = Debug|Mixed Platforms - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|ARM = Release|ARM - Release|Mixed Platforms = Release|Mixed Platforms - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|ARM.ActiveCfg = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|x64.ActiveCfg = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Debug|x86.ActiveCfg = Debug|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|Any CPU.Build.0 = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|ARM.ActiveCfg = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|x64.ActiveCfg = Release|Any CPU - {E367F791-C1EC-4181-912A-2943CAC6B3BC}.Release|x86.ActiveCfg = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|ARM.ActiveCfg = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|x64.ActiveCfg = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Debug|x86.ActiveCfg = Debug|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|Any CPU.Build.0 = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|ARM.ActiveCfg = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|x64.ActiveCfg = Release|Any CPU - {4A6CA785-1C8A-47FE-98C0-30C675A9328B}.Release|x86.ActiveCfg = Release|Any CPU - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Debug|ARM.ActiveCfg = Debug|ARM - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Debug|ARM.Build.0 = Debug|ARM - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Debug|x64.ActiveCfg = Debug|x64 - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Debug|x64.Build.0 = Debug|x64 - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Debug|x86.ActiveCfg = Debug|x86 - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Debug|x86.Build.0 = Debug|x86 - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Release|Any CPU.Build.0 = Release|Any CPU - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Release|ARM.ActiveCfg = Release|ARM - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Release|ARM.Build.0 = Release|ARM - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Release|x64.ActiveCfg = Release|x64 - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Release|x64.Build.0 = Release|x64 - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Release|x86.ActiveCfg = Release|x86 - {EC212E04-A372-4B95-B45B-C0D4A739EF80}.Release|x86.Build.0 = Release|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Debug|Any CPU.ActiveCfg = Debug|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Debug|ARM.ActiveCfg = Debug|ARM - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Debug|ARM.Build.0 = Debug|ARM - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Debug|ARM.Deploy.0 = Debug|ARM - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Debug|Mixed Platforms.Build.0 = Debug|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Debug|Mixed Platforms.Deploy.0 = Debug|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Debug|x64.ActiveCfg = Debug|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Debug|x86.ActiveCfg = Debug|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Debug|x86.Build.0 = Debug|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Debug|x86.Deploy.0 = Debug|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Release|Any CPU.ActiveCfg = Release|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Release|ARM.ActiveCfg = Release|ARM - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Release|ARM.Build.0 = Release|ARM - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Release|ARM.Deploy.0 = Release|ARM - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Release|Mixed Platforms.Build.0 = Release|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Release|Mixed Platforms.Deploy.0 = Release|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Release|x64.ActiveCfg = Release|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Release|x86.ActiveCfg = Release|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Release|x86.Build.0 = Release|x86 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884}.Release|x86.Deploy.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {94EE3919-19FA-4D9B-8DA9-249050B15232} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} - {A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} - EndGlobalSection - GlobalSection(TestCaseManagementSettings) = postSolution - CategoryFile = Renci.SshNet1.vsmdi - EndGlobalSection -EndGlobal diff --git a/src/Renci.SshNet.VS2015.sln.DotSettings b/src/Renci.SshNet.VS2015.sln.DotSettings deleted file mode 100644 index 15b1b217e..000000000 --- a/src/Renci.SshNet.VS2015.sln.DotSettings +++ /dev/null @@ -1,22 +0,0 @@ -锘 - DO_NOT_SHOW - DO_NOT_SHOW - DO_NOT_SHOW - DO_NOT_SHOW - DO_NOT_SHOW - SUGGESTION - WARNING - DO_NOT_SHOW - DO_NOT_SHOW - DO_NOT_SHOW - True - True - True - NEXT_LINE_SHIFTED_2 - CHOP_IF_LONG - HMACMD - HMACSHA - True - True - True - integration,LongRunning \ No newline at end of file diff --git a/src/Renci.SshNet.VS2017.sln b/src/Renci.SshNet.VS2017.sln deleted file mode 100644 index 9f1ce5e37..000000000 --- a/src/Renci.SshNet.VS2017.sln +++ /dev/null @@ -1,82 +0,0 @@ -锘 -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26014.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D}" - ProjectSection(SolutionItems) = preProject - ..\build\build.cmd = ..\build\build.cmd - ..\build\build.proj = ..\build\build.proj - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{94EE3919-19FA-4D9B-8DA9-249050B15232}" - ProjectSection(SolutionItems) = preProject - ..\build\nuget\SSH.NET.nuspec = ..\build\nuget\SSH.NET.nuspec - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandcastle", "sandcastle", "{A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1}" - ProjectSection(SolutionItems) = preProject - ..\build\sandcastle\SSH.NET.shfbproj = ..\build\sandcastle\SSH.NET.shfbproj - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet", "Renci.SshNet\Renci.SshNet.csproj", "{2F5F8C90-0BD1-424F-997C-7BC6280919D1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.Tests", "Renci.SshNet.Tests\Renci.SshNet.Tests.csproj", "{C45379B9-17B1-4E89-BC2E-6D41726413E8}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|ARM = Debug|ARM - Debug|Mixed Platforms = Debug|Mixed Platforms - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|ARM = Release|ARM - Release|Mixed Platforms = Release|Mixed Platforms - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|ARM.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x64.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x86.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.Build.0 = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|ARM.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x64.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x86.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|ARM.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|x64.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|x86.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Any CPU.Build.0 = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|ARM.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x64.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x86.ActiveCfg = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {94EE3919-19FA-4D9B-8DA9-249050B15232} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} - {A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {C3D130B3-A070-4B12-A10F-E3E44D6ACEE2} - EndGlobalSection - GlobalSection(TestCaseManagementSettings) = postSolution - CategoryFile = Renci.SshNet1.vsmdi - EndGlobalSection -EndGlobal diff --git a/src/Renci.SshNet.WindowsPhone/Properties/AssemblyInfo.cs b/src/Renci.SshNet.WindowsPhone/Properties/AssemblyInfo.cs deleted file mode 100644 index f61fb1340..000000000 --- a/src/Renci.SshNet.WindowsPhone/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,5 +0,0 @@ -锘縰sing System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("SSH.NET Windows Phone 7.1")] -[assembly: Guid("b044a9d9-fe40-4d7e-b198-c142ab9721f0")] diff --git a/src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj b/src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj deleted file mode 100644 index f8342e11b..000000000 --- a/src/Renci.SshNet.WindowsPhone/Renci.SshNet.WindowsPhone.csproj +++ /dev/null @@ -1,1435 +0,0 @@ -锘 - - - Debug - AnyCPU - 10.0.20506 - 2.0 - {3AD3EDF0-702E-4A91-8735-DCE4659AA54C} - {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - Renci.SshNet - Renci.SshNet - v4.0 - $(TargetFrameworkVersion) - WindowsPhone71 - Silverlight - false - true - true - - - true - full - false - Bin\Debug - TRACE;DEBUG;FEATURE_DEVICEINFORMATION_APM;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_REGEX_COMPILE;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_DEVICEINFORMATION_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 - true - true - prompt - 4 - Bin\Debug\Renci.SshNet.xml - - - none - true - Bin\Release - TRACE;FEATURE_DEVICEINFORMATION_APM;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_REGEX_COMPILE;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_DEVICEINFORMATION_APM;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_SHA1;FEATURE_HASH_SHA256;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 - true - true - prompt - 4 - Bin\Release\Renci.SshNet.xml - 1591 - - - - - False - ..\..\packages\SshNet.Security.Cryptography.1.2.0\lib\wp71\SshNet.Security.Cryptography.dll - - - - - - - Abstractions\CryptoAbstraction.cs - - - Abstractions\DiagnosticAbstraction.cs - - - Abstractions\DnsAbstraction.cs - - - Abstractions\FileSystemAbstraction.cs - - - Abstractions\ReflectionAbstraction.cs - - - Abstractions\SocketAbstraction.cs - - - Abstractions\ThreadAbstraction.cs - - - AuthenticationMethod.cs - - - AuthenticationResult.cs - - - BaseClient.cs - - - Channels\Channel.cs - - - Channels\ChannelDirectTcpip.cs - - - Channels\ChannelForwardedTcpip.cs - - - Channels\ChannelSession.cs - - - Channels\ChannelTypes.cs - - - Channels\ClientChannel.cs - - - Channels\IChannel.cs - - - Channels\IChannelDirectTcpip.cs - - - Channels\IChannelForwardedTcpip.cs - - - Channels\IChannelSession.cs - - - Channels\ServerChannel.cs - - - CipherInfo.cs - - - ClientAuthentication.cs - - - CommandAsyncResult.cs - - - Common\Array.cs - - - Common\ASCIIEncoding.cs - - - Common\AsyncResult.cs - - - Common\AuthenticationBannerEventArgs.cs - - - Common\AuthenticationEventArgs.cs - - - Common\AuthenticationPasswordChangeEventArgs.cs - - - Common\AuthenticationPrompt.cs - - - Common\AuthenticationPromptEventArgs.cs - - - Common\BigInteger.cs - - - Common\ChannelDataEventArgs.cs - - - Common\ChannelEventArgs.cs - - - Common\ChannelExtendedDataEventArgs.cs - - - Common\ChannelOpenConfirmedEventArgs.cs - - - Common\ChannelOpenFailedEventArgs.cs - - - Common\ChannelRequestEventArgs.cs - - - Common\CountdownEvent.cs - - - Common\DerData.cs - - - Common\ExceptionEventArgs.cs - - - Common\Extensions.cs - - - Common\HostKeyEventArgs.cs - - - Common\ObjectIdentifier.cs - - - Common\Pack.cs - - - Common\PacketDump.cs - - - Common\PipeStream.cs - - - Common\PortForwardEventArgs.cs - - - Common\PosixPath.cs - - - Common\ProxyException.cs - - - Common\ScpDownloadEventArgs.cs - - - Common\ScpException.cs - - - Common\ScpUploadEventArgs.cs - - - Common\SemaphoreLight.cs - - - Common\SftpPathNotFoundException.cs - - - Common\SftpPermissionDeniedException.cs - - - Common\ShellDataEventArgs.cs - - - Common\SshAuthenticationException.cs - - - Common\SshConnectionException.cs - - - Common\SshData.cs - - - Common\SshDataStream.cs - - - Common\SshException.cs - - - Common\SshOperationTimeoutException.cs - - - Common\SshPassPhraseNullOrEmptyException.cs - - - Common\TerminalModes.cs - - - Compression\CompressionMode.cs - - - Compression\Compressor.cs - - - Compression\Zlib.cs - - - Compression\ZlibOpenSsh.cs - - - Compression\ZlibStream.cs - - - ConnectionInfo.cs - - - Connection\ConnectorBase.cs - - - Connection\DirectConnector.cs - - - Connection\HttpConnector.cs - - - Connection\IConnector.cs - - - Connection\IProtocolVersionExchange.cs - - - Connection\ISocketFactory.cs - - - Connection\ProtocolVersionExchange.cs - - - Connection\SocketFactory.cs - - - Connection\Socks4Connector.cs - - - Connection\Socks5Connector.cs - - - Connection\SshIdentification.cs - - - ExpectAction.cs - - - ExpectAsyncResult.cs - - - ForwardedPort.cs - - - ForwardedPortDynamic.cs - - - ForwardedPortLocal.cs - - - ForwardedPortRemote.cs - - - ForwardedPortStatus.cs - - - HashInfo.cs - - - IAuthenticationMethod.cs - - - IClientAuthentication.cs - - - IConnectionInfo.cs - - - IForwardedPort.cs - - - IRemotePathTransformation.cs - - - IServiceFactory.cs - - - ISession.cs - - - ISubsystemSession.cs - - - KeyboardInteractiveAuthenticationMethod.cs - - - KeyboardInteractiveConnectionInfo.cs - - - MessageEventArgs.cs - - - Messages\Authentication\BannerMessage.cs - - - Messages\Authentication\FailureMessage.cs - - - Messages\Authentication\InformationRequestMessage.cs - - - Messages\Authentication\InformationResponseMessage.cs - - - Messages\Authentication\PasswordChangeRequiredMessage.cs - - - Messages\Authentication\PublicKeyMessage.cs - - - Messages\Authentication\RequestMessage.cs - - - Messages\Authentication\RequestMessageHost.cs - - - Messages\Authentication\RequestMessageKeyboardInteractive.cs - - - Messages\Authentication\RequestMessageNone.cs - - - Messages\Authentication\RequestMessagePassword.cs - - - Messages\Authentication\RequestMessagePublicKey.cs - - - Messages\Authentication\SuccessMessage.cs - - - Messages\Connection\CancelTcpIpForwardGlobalRequestMessage.cs - - - Messages\Connection\ChannelCloseMessage.cs - - - Messages\Connection\ChannelDataMessage.cs - - - Messages\Connection\ChannelEofMessage.cs - - - Messages\Connection\ChannelExtendedDataMessage.cs - - - Messages\Connection\ChannelFailureMessage.cs - - - Messages\Connection\ChannelMessage.cs - - - Messages\Connection\ChannelOpenConfirmationMessage.cs - - - Messages\Connection\ChannelOpenFailureMessage.cs - - - Messages\Connection\ChannelOpenFailureReasons.cs - - - Messages\Connection\ChannelOpen\ChannelOpenInfo.cs - - - Messages\Connection\ChannelOpen\ChannelOpenMessage.cs - - - Messages\Connection\ChannelOpen\DirectTcpipChannelInfo.cs - - - Messages\Connection\ChannelOpen\ForwardedTcpipChannelInfo.cs - - - Messages\Connection\ChannelOpen\SessionChannelOpenInfo.cs - - - Messages\Connection\ChannelOpen\X11ChannelOpenInfo.cs - - - Messages\Connection\ChannelRequest\BreakRequestInfo.cs - - - Messages\Connection\ChannelRequest\ChannelRequestMessage.cs - - - Messages\Connection\ChannelRequest\EndOfWriteRequestInfo.cs - - - Messages\Connection\ChannelRequest\EnvironmentVariableRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExecRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExitSignalRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExitStatusRequestInfo.cs - - - Messages\Connection\ChannelRequest\KeepAliveRequestInfo.cs - - - Messages\Connection\ChannelRequest\PseudoTerminalInfo.cs - - - Messages\Connection\ChannelRequest\RequestInfo.cs - - - Messages\Connection\ChannelRequest\ShellRequestInfo.cs - - - Messages\Connection\ChannelRequest\SignalRequestInfo.cs - - - Messages\Connection\ChannelRequest\SubsystemRequestInfo.cs - - - Messages\Connection\ChannelRequest\WindowChangeRequestInfo.cs - - - Messages\Connection\ChannelRequest\X11ForwardingRequestInfo.cs - - - Messages\Connection\ChannelRequest\XonXoffRequestInfo.cs - - - Messages\Connection\ChannelSuccessMessage.cs - - - Messages\Connection\ChannelWindowAdjustMessage.cs - - - Messages\Connection\GlobalRequestMessage.cs - - - Messages\Connection\GlobalRequestName.cs - - - Messages\Connection\RequestFailureMessage.cs - - - Messages\Connection\RequestSuccessMessage.cs - - - Messages\Connection\TcpIpForwardGlobalRequestMessage.cs - - - Messages\Message.cs - - - Messages\MessageAttribute.cs - - - Messages\ServiceName.cs - - - Messages\Transport\DebugMessage.cs - - - Messages\Transport\DisconnectMessage.cs - - - Messages\Transport\DisconnectReason.cs - - - Messages\Transport\IgnoreMessage.cs - - - Messages\Transport\IKeyExchangedAllowed.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeGroup.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeInit.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeReply.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeRequest.cs - - - Messages\Transport\KeyExchangeDhInitMessage.cs - - - Messages\Transport\KeyExchangeDhReplyMessage.cs - - - Messages\Transport\KeyExchangeEcdhInitMessage.cs - - - Messages\Transport\KeyExchangeEcdhReplyMessage.cs - - - Messages\Transport\KeyExchangeInitMessage.cs - - - Messages\Transport\NewKeysMessage.cs - - - Messages\Transport\ServiceAcceptMessage.cs - - - Messages\Transport\ServiceRequestMessage.cs - - - Messages\Transport\UnimplementedMessage.cs - - - NoneAuthenticationMethod.cs - - - PasswordAuthenticationMethod.cs - - - PasswordConnectionInfo.cs - - - PrivateKeyAuthenticationMethod.cs - - - PrivateKeyConnectionInfo.cs - - - PrivateKeyFile.cs - - - ProxyTypes.cs - - - RemotePathDoubleQuoteTransformation.cs - - - RemotePathNoneTransformation.cs - - - RemotePathShellQuoteTransformation.cs - - - RemotePathTransformation.cs - - - ScpClient.cs - - - Security\Algorithm.cs - - - Security\Cryptography\BouncyCastle\asn1\sec\SECNamedCurves.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9Curve.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECParameters.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECParametersHolder.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECPoint.cs - - - Security\Cryptography\BouncyCastle\crypto\agreement\ECDHCBasicAgreement.cs - - - Security\Cryptography\BouncyCastle\crypto\AsymmetricCipherKeyPair.cs - - - Security\Cryptography\BouncyCastle\crypto\AsymmetricKeyParameter.cs - - - Security\Cryptography\BouncyCastle\crypto\digests\GeneralDigest.cs - - - Security\Cryptography\BouncyCastle\crypto\digests\Sha256Digest.cs - - - Security\Cryptography\BouncyCastle\crypto\generators\ECKeyPairGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\IAsymmetricCipherKeyPairGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\IDigest.cs - - - Security\Cryptography\BouncyCastle\crypto\KeyGenerationParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECDomainParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyGenerationParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECPrivateKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECPublicKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\CryptoApiRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\DigestRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\IRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\util\Pack.cs - - - Security\Cryptography\BouncyCastle\math\BigInteger.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\SimpleBigDecimal.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\Tnaf.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\ZTauElement.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECAlgorithms.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECCurve.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECFieldElement.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECLookupTable.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECPoint.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECPointMap.cs - - - Security\Cryptography\BouncyCastle\math\ec\endo\ECEndomorphism.cs - - - Security\Cryptography\BouncyCastle\math\ec\endo\GlvEndomorphism.cs - - - Security\Cryptography\BouncyCastle\math\ec\LongArray.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\AbstractECMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\ECMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointCombMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointUtilities.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\GlvMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\IPreCompCallback.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\PreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\ValidityPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafL2RMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafUtilities.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\field\FiniteFields.cs - - - Security\Cryptography\BouncyCastle\math\field\GenericPolynomialExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\GF2Polynomial.cs - - - Security\Cryptography\BouncyCastle\math\field\IExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\IFiniteField.cs - - - Security\Cryptography\BouncyCastle\math\field\IPolynomial.cs - - - Security\Cryptography\BouncyCastle\math\field\IPolynomialExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\PrimeField.cs - - - Security\Cryptography\BouncyCastle\math\raw\Mod.cs - - - Security\Cryptography\BouncyCastle\math\raw\Nat.cs - - - Security\Cryptography\BouncyCastle\security\DigestUtilities.cs - - - Security\Cryptography\BouncyCastle\security\SecureRandom.cs - - - Security\Cryptography\BouncyCastle\security\SecurityUtilityException.cs - - - Security\Cryptography\BouncyCastle\util\Arrays.cs - - - Security\Cryptography\BouncyCastle\util\BigIntegers.cs - - - Security\Cryptography\BouncyCastle\util\encoders\Hex.cs - - - Security\Cryptography\BouncyCastle\util\encoders\HexEncoder.cs - - - Security\Cryptography\BouncyCastle\util\IMemoable.cs - - - Security\Cryptography\BouncyCastle\util\Integers.cs - - - Security\Cryptography\BouncyCastle\util\MemoableResetException.cs - - - Security\Cryptography\BouncyCastle\util\Times.cs - - - Security\CertificateHostAlgorithm.cs - - - Security\Cryptography\Chaos.NaCl\CryptoBytes.cs - - - Security\Cryptography\Chaos.NaCl\Ed25519.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Array16.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Array8.cs - - - Security\Cryptography\Chaos.NaCl\Internal\ByteIntegerConverter.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_1.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cmov.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cswap.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_frombytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_invert.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnegative.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnonzero.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul121666.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_neg.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_pow22523.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\FieldElement.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_double_scalarmult.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_frombytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_madd.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_msub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p3.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_dbl.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_dbl.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_cached.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_p2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_precomp_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_scalarmult_base.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_sub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\GroupElement.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\keypair.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\open.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\scalarmult.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_clamp.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_mul_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_reduce.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sign.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sqrtm1.cs - - - Security\Cryptography\Chaos.NaCl\Internal\InternalAssert.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Poly1305Donna.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Salsa\Salsa20.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Salsa\SalsaCore.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Sha512Internal.cs - - - Security\Cryptography\Chaos.NaCl\MontgomeryCurve25519.cs - - - Security\Cryptography\Chaos.NaCl\Sha512.cs - - - Security\Cryptography\AsymmetricCipher.cs - - - Security\Cryptography\Bcrypt.cs - - - Security\Cryptography\BlockCipher.cs - - - Security\Cryptography\Cipher.cs - - - Security\Cryptography\CipherDigitalSignature.cs - - - Security\Cryptography\Ciphers\AesCipher.cs - - - Security\Cryptography\Ciphers\Arc4Cipher.cs - - - Security\Cryptography\Ciphers\BlowfishCipher.cs - - - Security\Cryptography\Ciphers\CastCipher.cs - - - Security\Cryptography\Ciphers\CipherMode.cs - - - Security\Cryptography\Ciphers\CipherPadding.cs - - - Security\Cryptography\Ciphers\DesCipher.cs - - - Security\Cryptography\Ciphers\Modes\CbcCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\CfbCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\CtrCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\OfbCipherMode.cs - - - Security\Cryptography\Ciphers\Paddings\PKCS7Padding.cs - - - Security\Cryptography\Ciphers\RsaCipher.cs - - - Security\Cryptography\Ciphers\SerpentCipher.cs - - - Security\Cryptography\Ciphers\TripleDesCipher.cs - - - Security\Cryptography\Ciphers\TwofishCipher.cs - - - Security\Cryptography\DigitalSignature.cs - - - Security\Cryptography\DsaDigitalSignature.cs - - - Security\Cryptography\DsaKey.cs - - - Security\Cryptography\ED25519DigitalSignature.cs - - - Security\Cryptography\ED25519Key.cs - - - Security\Cryptography\HMACMD5.cs - - - Security\Cryptography\HMACSHA1.cs - - - Security\Cryptography\HMACSHA256.cs - - - Security\Cryptography\HMACSHA384.cs - - - Security\Cryptography\HMACSHA512.cs - - - Security\Cryptography\Key.cs - - - Security\Cryptography\RsaDigitalSignature.cs - - - Security\Cryptography\RsaKey.cs - - - Security\Cryptography\StreamCipher.cs - - - Security\Cryptography\SymmetricCipher.cs - - - Security\GroupExchangeHashData.cs - - - Security\HostAlgorithm.cs - - - Security\IKeyExchange.cs - - - Security\KeyExchange.cs - - - Security\KeyExchangeDiffieHellman.cs - - - Security\KeyExchangeDiffieHellmanGroup14Sha1.cs - - - Security\KeyExchangeDiffieHellmanGroup14Sha256.cs - - - Security\KeyExchangeDiffieHellmanGroup16Sha512.cs - - - Security\KeyExchangeDiffieHellmanGroup1Sha1.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeSha1.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs - - - Security\KeyExchangeDiffieHellmanGroupSha1.cs - - - Security\KeyExchangeDiffieHellmanGroupSha256.cs - - - Security\KeyExchangeDiffieHellmanGroupSha512.cs - - - Security\KeyExchangeDiffieHellmanGroupShaBase.cs - - - Security\KeyExchangeEC.cs - - - Security\KeyExchangeECCurve25519.cs - - - Security\KeyExchangeECDH.cs - - - Security\KeyExchangeECDH256.cs - - - Security\KeyExchangeECDH384.cs - - - Security\KeyExchangeECDH521.cs - - - Security\KeyExchangeHash.cs - - - Security\KeyHostAlgorithm.cs - - - ServiceFactory.cs - - - Session.cs - - - SftpClient.cs - - - ISftpClient.cs - - - Sftp\Flags.cs - - - Sftp\ISftpFileReader.cs - - - Sftp\ISftpResponseFactory.cs - - - Sftp\ISftpSession.cs - - - Sftp\Requests\ExtendedRequests\FStatVfsRequest.cs - - - Sftp\Requests\ExtendedRequests\HardLinkRequest.cs - - - Sftp\Requests\ExtendedRequests\PosixRenameRequest.cs - - - Sftp\Requests\ExtendedRequests\StatVfsRequest.cs - - - Sftp\Requests\SftpBlockRequest.cs - - - Sftp\Requests\SftpCloseRequest.cs - - - Sftp\Requests\SftpExtendedRequest.cs - - - Sftp\Requests\SftpFSetStatRequest.cs - - - Sftp\Requests\SftpFStatRequest.cs - - - Sftp\Requests\SftpInitRequest.cs - - - Sftp\Requests\SftpLinkRequest.cs - - - Sftp\Requests\SftpLStatRequest.cs - - - Sftp\Requests\SftpMkDirRequest.cs - - - Sftp\Requests\SftpOpenDirRequest.cs - - - Sftp\Requests\SftpOpenRequest.cs - - - Sftp\Requests\SftpReadDirRequest.cs - - - Sftp\Requests\SftpReadLinkRequest.cs - - - Sftp\Requests\SftpReadRequest.cs - - - Sftp\Requests\SftpRealPathRequest.cs - - - Sftp\Requests\SftpRemoveRequest.cs - - - Sftp\Requests\SftpRenameRequest.cs - - - Sftp\Requests\SftpRequest.cs - - - Sftp\Requests\SftpRmDirRequest.cs - - - Sftp\Requests\SftpSetStatRequest.cs - - - Sftp\Requests\SftpStatRequest.cs - - - Sftp\Requests\SftpSymLinkRequest.cs - - - Sftp\Requests\SftpUnblockRequest.cs - - - Sftp\Requests\SftpWriteRequest.cs - - - Sftp\Responses\ExtendedReplies\ExtendedReplyInfo.cs - - - Sftp\Responses\ExtendedReplies\StatVfsReplyInfo.cs - - - Sftp\Responses\SftpAttrsResponse.cs - - - Sftp\Responses\SftpDataResponse.cs - - - Sftp\Responses\SftpExtendedReplyResponse.cs - - - Sftp\Responses\SftpHandleResponse.cs - - - Sftp\Responses\SftpNameResponse.cs - - - Sftp\Responses\SftpResponse.cs - - - Sftp\Responses\SftpStatusResponse.cs - - - Sftp\Responses\SftpVersionResponse.cs - - - Sftp\SftpCloseAsyncResult.cs - - - Sftp\SftpDownloadAsyncResult.cs - - - Sftp\SftpFile.cs - - - Sftp\ISftpFile.cs - - - Sftp\SftpFileAttributes.cs - - - Sftp\SftpFileReader.cs - - - Sftp\SftpFileStream.cs - - - Sftp\SftpFileSystemInformation.cs - - - Sftp\SftpListDirectoryAsyncResult.cs - - - Sftp\SftpMessage.cs - - - Sftp\SftpMessageTypes.cs - - - Sftp\SftpOpenAsyncResult.cs - - - Sftp\SftpReadAsyncResult.cs - - - Sftp\SftpRealPathAsyncResult.cs - - - Sftp\SftpResponseFactory.cs - - - Sftp\SftpSession.cs - - - Sftp\SFtpStatAsyncResult.cs - - - Sftp\SftpSynchronizeDirectoriesAsyncResult.cs - - - Sftp\SftpUploadAsyncResult.cs - - - Sftp\StatusCodes.cs - - - Shell.cs - - - ShellStream.cs - - - SshClient.cs - - - SshCommand.cs - - - SshMessageFactory.cs - - - SubsystemSession.cs - - - - Properties\CommonAssemblyInfo.cs - - - - - Designer - - - - - - - \ No newline at end of file diff --git a/src/Renci.SshNet.WindowsPhone/packages.config b/src/Renci.SshNet.WindowsPhone/packages.config deleted file mode 100644 index a9e0cd0e6..000000000 --- a/src/Renci.SshNet.WindowsPhone/packages.config +++ /dev/null @@ -1,4 +0,0 @@ -锘 - - - \ No newline at end of file diff --git a/src/Renci.SshNet.WindowsPhone8/Properties/AssemblyInfo.cs b/src/Renci.SshNet.WindowsPhone8/Properties/AssemblyInfo.cs deleted file mode 100644 index 3db5746c8..000000000 --- a/src/Renci.SshNet.WindowsPhone8/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,8 +0,0 @@ -锘縰sing System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("SSH.NET Windows Phone 8.0")] -[assembly: Guid("b044a9d9-fe40-4d7e-b198-c142ab9721f0")] - -[assembly: InternalsVisibleTo("Renci.SshNet.Tests")] \ No newline at end of file diff --git a/src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj b/src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj deleted file mode 100644 index fb301e597..000000000 --- a/src/Renci.SshNet.WindowsPhone8/Renci.SshNet.WindowsPhone8.csproj +++ /dev/null @@ -1,1496 +0,0 @@ -锘 - - - Debug - AnyCPU - 10.0.20506 - 2.0 - {4A6CA785-1C8A-47FE-98C0-30C675A9328B} - {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - Renci.SshNet - Renci.SshNet - v8.0 - WindowsPhone - false - true - true - 11.0 - - - true - full - false - Bin\Debug - TRACE;DEBUG;FEATURE_REGEX_COMPILE;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_STREAM_TAP;FEATURE_DEVICEINFORMATION_APM;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 - true - true - prompt - 4 - false - Bin\Debug\Renci.SshNet.xml - true - - - none - true - Bin\Release - TRACE;FEATURE_REGEX_COMPILE;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_STREAM_TAP;FEATURE_DEVICEINFORMATION_APM;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 - true - true - prompt - 4 - false - Bin\Release\Renci.SshNet.xml - - - true - - - true - Bin\x86\Debug - TRACE;DEBUG;FEATURE_REGEX_COMPILE;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_STREAM_TAP;FEATURE_DEVICEINFORMATION_APM;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 - true - full - - - prompt - MinimumRecommendedRules.ruleset - false - - - Bin\x86\Release - TRACE;FEATURE_REGEX_COMPILE;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_STREAM_TAP;FEATURE_DEVICEINFORMATION_APM;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 - true - true - pdbonly - - - prompt - MinimumRecommendedRules.ruleset - - - true - Bin\ARM\Debug - TRACE;DEBUG;FEATURE_REGEX_COMPILE;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_STREAM_TAP;FEATURE_DEVICEINFORMATION_APM;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 - true - full - - - prompt - MinimumRecommendedRules.ruleset - false - - - Bin\ARM\Release - TRACE;FEATURE_REGEX_COMPILE;FEATURE_RNG_CSP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_STREAM_TAP;FEATURE_DEVICEINFORMATION_APM;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_HASH_SHA1_MANAGED;FEATURE_HASH_SHA256_MANAGED;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256 - true - true - pdbonly - - - prompt - MinimumRecommendedRules.ruleset - - - - Abstractions\CryptoAbstraction.cs - - - Abstractions\DiagnosticAbstraction.cs - - - Abstractions\DnsAbstraction.cs - - - Abstractions\FileSystemAbstraction.cs - - - Abstractions\ReflectionAbstraction.cs - - - Abstractions\SocketAbstraction.cs - - - Abstractions\ThreadAbstraction.cs - - - AuthenticationMethod.cs - - - AuthenticationResult.cs - - - BaseClient.cs - - - Channels\Channel.cs - - - Channels\ChannelDirectTcpip.cs - - - Channels\ChannelForwardedTcpip.cs - - - Channels\ChannelSession.cs - - - Channels\ChannelTypes.cs - - - Channels\ClientChannel.cs - - - Channels\IChannel.cs - - - Channels\IChannelDirectTcpip.cs - - - Channels\IChannelForwardedTcpip.cs - - - Channels\IChannelSession.cs - - - Channels\ServerChannel.cs - - - CipherInfo.cs - - - ClientAuthentication.cs - - - CommandAsyncResult.cs - - - Common\Array.cs - - - Common\ASCIIEncoding.cs - - - Common\AsyncResult.cs - - - Common\AuthenticationBannerEventArgs.cs - - - Common\AuthenticationEventArgs.cs - - - Common\AuthenticationPasswordChangeEventArgs.cs - - - Common\AuthenticationPrompt.cs - - - Common\AuthenticationPromptEventArgs.cs - - - Common\BigInteger.cs - - - Common\ChannelDataEventArgs.cs - - - Common\ChannelEventArgs.cs - - - Common\ChannelExtendedDataEventArgs.cs - - - Common\ChannelOpenConfirmedEventArgs.cs - - - Common\ChannelOpenFailedEventArgs.cs - - - Common\ChannelRequestEventArgs.cs - - - Common\CountdownEvent.cs - - - Common\DerData.cs - - - Common\ExceptionEventArgs.cs - - - Common\Extensions.cs - - - Common\HostKeyEventArgs.cs - - - Common\ObjectIdentifier.cs - - - Common\Pack.cs - - - Common\PacketDump.cs - - - Common\PipeStream.cs - - - Common\PortForwardEventArgs.cs - - - Common\PosixPath.cs - - - Common\ProxyException.cs - - - Common\ScpDownloadEventArgs.cs - - - Common\ScpException.cs - - - Common\ScpUploadEventArgs.cs - - - Common\SemaphoreLight.cs - - - Common\SftpPathNotFoundException.cs - - - Common\SftpPermissionDeniedException.cs - - - Common\ShellDataEventArgs.cs - - - Common\SshAuthenticationException.cs - - - Common\SshConnectionException.cs - - - Common\SshData.cs - - - Common\SshDataStream.cs - - - Common\SshException.cs - - - Common\SshOperationTimeoutException.cs - - - Common\SshPassPhraseNullOrEmptyException.cs - - - Common\TerminalModes.cs - - - Compression\CompressionMode.cs - - - Compression\Compressor.cs - - - Compression\Zlib.cs - - - Compression\ZlibOpenSsh.cs - - - Compression\ZlibStream.cs - - - ConnectionInfo.cs - - - Connection\ConnectorBase.cs - - - Connection\DirectConnector.cs - - - Connection\HttpConnector.cs - - - Connection\IConnector.cs - - - Connection\IProtocolVersionExchange.cs - - - Connection\ISocketFactory.cs - - - Connection\ProtocolVersionExchange.cs - - - Connection\SocketFactory.cs - - - Connection\Socks4Connector.cs - - - Connection\Socks5Connector.cs - - - Connection\SshIdentification.cs - - - ExpectAction.cs - - - ExpectAsyncResult.cs - - - ForwardedPort.cs - - - ForwardedPortDynamic.cs - - - ForwardedPortDynamic.NET.cs - - - ForwardedPortLocal.cs - - - ForwardedPortLocal.NET.cs - - - ForwardedPortRemote.cs - - - ForwardedPortStatus.cs - - - HashInfo.cs - - - IAuthenticationMethod.cs - - - IClientAuthentication.cs - - - IConnectionInfo.cs - - - IForwardedPort.cs - - - IRemotePathTransformation.cs - - - IServiceFactory.cs - - - ISession.cs - - - ISftpClient.cs - - - ISubsystemSession.cs - - - KeyboardInteractiveAuthenticationMethod.cs - - - KeyboardInteractiveConnectionInfo.cs - - - MessageEventArgs.cs - - - Messages\Authentication\BannerMessage.cs - - - Messages\Authentication\FailureMessage.cs - - - Messages\Authentication\InformationRequestMessage.cs - - - Messages\Authentication\InformationResponseMessage.cs - - - Messages\Authentication\PasswordChangeRequiredMessage.cs - - - Messages\Authentication\PublicKeyMessage.cs - - - Messages\Authentication\RequestMessage.cs - - - Messages\Authentication\RequestMessageHost.cs - - - Messages\Authentication\RequestMessageKeyboardInteractive.cs - - - Messages\Authentication\RequestMessageNone.cs - - - Messages\Authentication\RequestMessagePassword.cs - - - Messages\Authentication\RequestMessagePublicKey.cs - - - Messages\Authentication\SuccessMessage.cs - - - Messages\Connection\CancelTcpIpForwardGlobalRequestMessage.cs - - - Messages\Connection\ChannelCloseMessage.cs - - - Messages\Connection\ChannelDataMessage.cs - - - Messages\Connection\ChannelEofMessage.cs - - - Messages\Connection\ChannelExtendedDataMessage.cs - - - Messages\Connection\ChannelFailureMessage.cs - - - Messages\Connection\ChannelMessage.cs - - - Messages\Connection\ChannelOpenConfirmationMessage.cs - - - Messages\Connection\ChannelOpenFailureMessage.cs - - - Messages\Connection\ChannelOpenFailureReasons.cs - - - Messages\Connection\ChannelOpen\ChannelOpenInfo.cs - - - Messages\Connection\ChannelOpen\ChannelOpenMessage.cs - - - Messages\Connection\ChannelOpen\DirectTcpipChannelInfo.cs - - - Messages\Connection\ChannelOpen\ForwardedTcpipChannelInfo.cs - - - Messages\Connection\ChannelOpen\SessionChannelOpenInfo.cs - - - Messages\Connection\ChannelOpen\X11ChannelOpenInfo.cs - - - Messages\Connection\ChannelRequest\BreakRequestInfo.cs - - - Messages\Connection\ChannelRequest\ChannelRequestMessage.cs - - - Messages\Connection\ChannelRequest\EndOfWriteRequestInfo.cs - - - Messages\Connection\ChannelRequest\EnvironmentVariableRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExecRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExitSignalRequestInfo.cs - - - Messages\Connection\ChannelRequest\ExitStatusRequestInfo.cs - - - Messages\Connection\ChannelRequest\KeepAliveRequestInfo.cs - - - Messages\Connection\ChannelRequest\PseudoTerminalInfo.cs - - - Messages\Connection\ChannelRequest\RequestInfo.cs - - - Messages\Connection\ChannelRequest\ShellRequestInfo.cs - - - Messages\Connection\ChannelRequest\SignalRequestInfo.cs - - - Messages\Connection\ChannelRequest\SubsystemRequestInfo.cs - - - Messages\Connection\ChannelRequest\WindowChangeRequestInfo.cs - - - Messages\Connection\ChannelRequest\X11ForwardingRequestInfo.cs - - - Messages\Connection\ChannelRequest\XonXoffRequestInfo.cs - - - Messages\Connection\ChannelSuccessMessage.cs - - - Messages\Connection\ChannelWindowAdjustMessage.cs - - - Messages\Connection\GlobalRequestMessage.cs - - - Messages\Connection\GlobalRequestName.cs - - - Messages\Connection\RequestFailureMessage.cs - - - Messages\Connection\RequestSuccessMessage.cs - - - Messages\Connection\TcpIpForwardGlobalRequestMessage.cs - - - Messages\Message.cs - - - Messages\MessageAttribute.cs - - - Messages\ServiceName.cs - - - Messages\Transport\DebugMessage.cs - - - Messages\Transport\DisconnectMessage.cs - - - Messages\Transport\DisconnectReason.cs - - - Messages\Transport\IgnoreMessage.cs - - - Messages\Transport\IKeyExchangedAllowed.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeGroup.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeInit.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeReply.cs - - - Messages\Transport\KeyExchangeDhGroupExchangeRequest.cs - - - Messages\Transport\KeyExchangeDhInitMessage.cs - - - Messages\Transport\KeyExchangeDhReplyMessage.cs - - - Messages\Transport\KeyExchangeEcdhInitMessage.cs - - - Messages\Transport\KeyExchangeEcdhReplyMessage.cs - - - Messages\Transport\KeyExchangeInitMessage.cs - - - Messages\Transport\NewKeysMessage.cs - - - Messages\Transport\ServiceAcceptMessage.cs - - - Messages\Transport\ServiceRequestMessage.cs - - - Messages\Transport\UnimplementedMessage.cs - - - NoneAuthenticationMethod.cs - - - PasswordAuthenticationMethod.cs - - - PasswordConnectionInfo.cs - - - PrivateKeyAuthenticationMethod.cs - - - PrivateKeyConnectionInfo.cs - - - PrivateKeyFile.cs - - - ProxyTypes.cs - - - RemotePathDoubleQuoteTransformation.cs - - - RemotePathNoneTransformation.cs - - - RemotePathShellQuoteTransformation.cs - - - RemotePathTransformation.cs - - - ScpClient.cs - - - Security\Algorithm.cs - - - Security\Cryptography\BouncyCastle\asn1\sec\SECNamedCurves.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9Curve.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECParameters.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECParametersHolder.cs - - - Security\Cryptography\BouncyCastle\asn1\x9\X9ECPoint.cs - - - Security\Cryptography\BouncyCastle\crypto\agreement\ECDHCBasicAgreement.cs - - - Security\Cryptography\BouncyCastle\crypto\AsymmetricCipherKeyPair.cs - - - Security\Cryptography\BouncyCastle\crypto\AsymmetricKeyParameter.cs - - - Security\Cryptography\BouncyCastle\crypto\digests\GeneralDigest.cs - - - Security\Cryptography\BouncyCastle\crypto\digests\Sha256Digest.cs - - - Security\Cryptography\BouncyCastle\crypto\generators\ECKeyPairGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\IAsymmetricCipherKeyPairGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\IDigest.cs - - - Security\Cryptography\BouncyCastle\crypto\KeyGenerationParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECDomainParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyGenerationParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECPrivateKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\parameters\ECPublicKeyParameters.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\CryptoApiRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\DigestRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\prng\IRandomGenerator.cs - - - Security\Cryptography\BouncyCastle\crypto\util\Pack.cs - - - Security\Cryptography\BouncyCastle\math\BigInteger.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\SimpleBigDecimal.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\Tnaf.cs - - - Security\Cryptography\BouncyCastle\math\ec\abc\ZTauElement.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECAlgorithms.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECCurve.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECFieldElement.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECLookupTable.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECPoint.cs - - - Security\Cryptography\BouncyCastle\math\ec\ECPointMap.cs - - - Security\Cryptography\BouncyCastle\math\ec\endo\ECEndomorphism.cs - - - Security\Cryptography\BouncyCastle\math\ec\endo\GlvEndomorphism.cs - - - Security\Cryptography\BouncyCastle\math\ec\LongArray.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\AbstractECMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\ECMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointCombMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\FixedPointUtilities.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\GlvMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\IPreCompCallback.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\PreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\ValidityPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafL2RMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WNafUtilities.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafMultiplier.cs - - - Security\Cryptography\BouncyCastle\math\ec\multiplier\WTauNafPreCompInfo.cs - - - Security\Cryptography\BouncyCastle\math\field\FiniteFields.cs - - - Security\Cryptography\BouncyCastle\math\field\GenericPolynomialExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\GF2Polynomial.cs - - - Security\Cryptography\BouncyCastle\math\field\IExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\IFiniteField.cs - - - Security\Cryptography\BouncyCastle\math\field\IPolynomial.cs - - - Security\Cryptography\BouncyCastle\math\field\IPolynomialExtensionField.cs - - - Security\Cryptography\BouncyCastle\math\field\PrimeField.cs - - - Security\Cryptography\BouncyCastle\math\raw\Mod.cs - - - Security\Cryptography\BouncyCastle\math\raw\Nat.cs - - - Security\Cryptography\BouncyCastle\security\DigestUtilities.cs - - - Security\Cryptography\BouncyCastle\security\SecureRandom.cs - - - Security\Cryptography\BouncyCastle\security\SecurityUtilityException.cs - - - Security\Cryptography\BouncyCastle\util\Arrays.cs - - - Security\Cryptography\BouncyCastle\util\BigIntegers.cs - - - Security\Cryptography\BouncyCastle\util\encoders\Hex.cs - - - Security\Cryptography\BouncyCastle\util\encoders\HexEncoder.cs - - - Security\Cryptography\BouncyCastle\util\IMemoable.cs - - - Security\Cryptography\BouncyCastle\util\Integers.cs - - - Security\Cryptography\BouncyCastle\util\MemoableResetException.cs - - - Security\Cryptography\BouncyCastle\util\Times.cs - - - Security\CertificateHostAlgorithm.cs - - - Security\Cryptography\Chaos.NaCl\CryptoBytes.cs - - - Security\Cryptography\Chaos.NaCl\Ed25519.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Array16.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Array8.cs - - - Security\Cryptography\Chaos.NaCl\Internal\ByteIntegerConverter.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\base2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\d2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_1.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cmov.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_cswap.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_frombytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_invert.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnegative.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_isnonzero.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_mul121666.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_neg.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_pow22523.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sq2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_sub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\fe_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\FieldElement.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_double_scalarmult.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_frombytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_madd.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_msub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p1p1_to_p3.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p2_dbl.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_dbl.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_cached.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_p3_to_p2.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_precomp_0.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_scalarmult_base.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_sub.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\ge_tobytes.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\GroupElement.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\keypair.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\open.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\scalarmult.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_clamp.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_mul_add.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sc_reduce.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sign.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Ed25519Ref10\sqrtm1.cs - - - Security\Cryptography\Chaos.NaCl\Internal\InternalAssert.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Poly1305Donna.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Salsa\Salsa20.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Salsa\SalsaCore.cs - - - Security\Cryptography\Chaos.NaCl\Internal\Sha512Internal.cs - - - Security\Cryptography\Chaos.NaCl\MontgomeryCurve25519.cs - - - Security\Cryptography\Chaos.NaCl\Sha512.cs - - - Security\Cryptography\AsymmetricCipher.cs - - - Security\Cryptography\Bcrypt.cs - - - Security\Cryptography\BlockCipher.cs - - - Security\Cryptography\Cipher.cs - - - Security\Cryptography\CipherDigitalSignature.cs - - - Security\Cryptography\Ciphers\AesCipher.cs - - - Security\Cryptography\Ciphers\Arc4Cipher.cs - - - Security\Cryptography\Ciphers\BlowfishCipher.cs - - - Security\Cryptography\Ciphers\CastCipher.cs - - - Security\Cryptography\Ciphers\CipherMode.cs - - - Security\Cryptography\Ciphers\CipherPadding.cs - - - Security\Cryptography\Ciphers\DesCipher.cs - - - Security\Cryptography\Ciphers\Modes\CbcCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\CfbCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\CtrCipherMode.cs - - - Security\Cryptography\Ciphers\Modes\OfbCipherMode.cs - - - Security\Cryptography\Ciphers\Paddings\PKCS7Padding.cs - - - Security\Cryptography\Ciphers\RsaCipher.cs - - - Security\Cryptography\Ciphers\SerpentCipher.cs - - - Security\Cryptography\Ciphers\TripleDesCipher.cs - - - Security\Cryptography\Ciphers\TwofishCipher.cs - - - Security\Cryptography\DigitalSignature.cs - - - Security\Cryptography\DsaDigitalSignature.cs - - - Security\Cryptography\DsaKey.cs - - - Security\Cryptography\ED25519DigitalSignature.cs - - - Security\Cryptography\ED25519Key.cs - - - Security\Cryptography\HMACMD5.cs - - - Security\Cryptography\HMACSHA1.cs - - - Security\Cryptography\HMACSHA256.cs - - - Security\Cryptography\HMACSHA384.cs - - - Security\Cryptography\HMACSHA512.cs - - - Security\Cryptography\Key.cs - - - Security\Cryptography\EcdsaDigitalSignature.cs - - - Security\Cryptography\EcdsaKey.cs - - - Security\Cryptography\RsaDigitalSignature.cs - - - Security\Cryptography\RsaKey.cs - - - Security\Cryptography\StreamCipher.cs - - - Security\Cryptography\SymmetricCipher.cs - - - Security\GroupExchangeHashData.cs - - - Security\HostAlgorithm.cs - - - Security\IKeyExchange.cs - - - Security\KeyExchange.cs - - - Security\KeyExchangeDiffieHellman.cs - - - Security\KeyExchangeDiffieHellmanGroup14Sha1.cs - - - Security\KeyExchangeDiffieHellmanGroup14Sha256.cs - - - Security\KeyExchangeDiffieHellmanGroup16Sha512.cs - - - Security\KeyExchangeDiffieHellmanGroup1Sha1.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeSha1.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeSha256.cs - - - Security\KeyExchangeDiffieHellmanGroupExchangeShaBase.cs - - - Security\KeyExchangeDiffieHellmanGroupSha1.cs - - - Security\KeyExchangeDiffieHellmanGroupSha256.cs - - - Security\KeyExchangeDiffieHellmanGroupSha512.cs - - - Security\KeyExchangeDiffieHellmanGroupShaBase.cs - - - Security\KeyExchangeEC.cs - - - Security\KeyExchangeECCurve25519.cs - - - Security\KeyExchangeECDH.cs - - - Security\KeyExchangeECDH256.cs - - - Security\KeyExchangeECDH384.cs - - - Security\KeyExchangeECDH521.cs - - - Security\KeyExchangeHash.cs - - - Security\KeyHostAlgorithm.cs - - - ServiceFactory.cs - - - Session.cs - - - SftpClient.cs - - - Sftp\Flags.cs - - - Sftp\ISftpFileReader.cs - - - Sftp\ISftpResponseFactory.cs - - - Sftp\ISftpSession.cs - - - Sftp\Requests\ExtendedRequests\FStatVfsRequest.cs - - - Sftp\Requests\ExtendedRequests\HardLinkRequest.cs - - - Sftp\Requests\ExtendedRequests\PosixRenameRequest.cs - - - Sftp\Requests\ExtendedRequests\StatVfsRequest.cs - - - Sftp\Requests\SftpBlockRequest.cs - - - Sftp\Requests\SftpCloseRequest.cs - - - Sftp\Requests\SftpExtendedRequest.cs - - - Sftp\Requests\SftpFSetStatRequest.cs - - - Sftp\Requests\SftpFStatRequest.cs - - - Sftp\Requests\SftpInitRequest.cs - - - Sftp\Requests\SftpLinkRequest.cs - - - Sftp\Requests\SftpLStatRequest.cs - - - Sftp\Requests\SftpMkDirRequest.cs - - - Sftp\Requests\SftpOpenDirRequest.cs - - - Sftp\Requests\SftpOpenRequest.cs - - - Sftp\Requests\SftpReadDirRequest.cs - - - Sftp\Requests\SftpReadLinkRequest.cs - - - Sftp\Requests\SftpReadRequest.cs - - - Sftp\Requests\SftpRealPathRequest.cs - - - Sftp\Requests\SftpRemoveRequest.cs - - - Sftp\Requests\SftpRenameRequest.cs - - - Sftp\Requests\SftpRequest.cs - - - Sftp\Requests\SftpRmDirRequest.cs - - - Sftp\Requests\SftpSetStatRequest.cs - - - Sftp\Requests\SftpStatRequest.cs - - - Sftp\Requests\SftpSymLinkRequest.cs - - - Sftp\Requests\SftpUnblockRequest.cs - - - Sftp\Requests\SftpWriteRequest.cs - - - Sftp\Responses\ExtendedReplies\ExtendedReplyInfo.cs - - - Sftp\Responses\ExtendedReplies\StatVfsReplyInfo.cs - - - Sftp\Responses\SftpAttrsResponse.cs - - - Sftp\Responses\SftpDataResponse.cs - - - Sftp\Responses\SftpExtendedReplyResponse.cs - - - Sftp\Responses\SftpHandleResponse.cs - - - Sftp\Responses\SftpNameResponse.cs - - - Sftp\Responses\SftpResponse.cs - - - Sftp\Responses\SftpStatusResponse.cs - - - Sftp\Responses\SftpVersionResponse.cs - - - Sftp\SftpCloseAsyncResult.cs - - - Sftp\SftpDownloadAsyncResult.cs - - - Sftp\SftpFile.cs - - - Sftp\ISftpFile.cs - - - Sftp\SftpFileAttributes.cs - - - Sftp\SftpFileReader.cs - - - Sftp\SftpFileStream.cs - - - Sftp\SftpFileSystemInformation.cs - - - Sftp\SftpListDirectoryAsyncResult.cs - - - Sftp\SftpMessage.cs - - - Sftp\SftpMessageTypes.cs - - - Sftp\SftpOpenAsyncResult.cs - - - Sftp\SftpReadAsyncResult.cs - - - Sftp\SftpRealPathAsyncResult.cs - - - Sftp\SftpResponseFactory.cs - - - Sftp\SftpSession.cs - - - Sftp\SFtpStatAsyncResult.cs - - - Sftp\SftpSynchronizeDirectoriesAsyncResult.cs - - - Sftp\SftpUploadAsyncResult.cs - - - Sftp\StatusCodes.cs - - - Shell.cs - - - ShellStream.cs - - - SshClient.cs - - - SshCommand.cs - - - SshMessageFactory.cs - - - SubsystemSession.cs - - - - Properties\CommonAssemblyInfo.cs - - - - - - - - ..\..\packages\SshNet.Security.Cryptography.1.2.0\lib\wp8\SshNet.Security.Cryptography.dll - True - - - - - - - - - - - \ No newline at end of file diff --git a/src/Renci.SshNet.WindowsPhone8/packages.config b/src/Renci.SshNet.WindowsPhone8/packages.config deleted file mode 100644 index a571ea4f4..000000000 --- a/src/Renci.SshNet.WindowsPhone8/packages.config +++ /dev/null @@ -1,5 +0,0 @@ -锘 - - - - \ No newline at end of file diff --git a/src/Renci.SshNet.VS2019.sln b/src/Renci.SshNet.sln similarity index 100% rename from src/Renci.SshNet.VS2019.sln rename to src/Renci.SshNet.sln diff --git a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs index 2029b0143..e358767a1 100644 --- a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs @@ -63,9 +63,9 @@ public static void Connect(Socket socket, IPEndPoint remoteEndpoint, TimeSpan co } #if FEATURE_TAP - public static Task ConnectAsync(Socket socket, IPEndPoint remoteEndpoint, CancellationToken cancellationToken) + public static async Task ConnectAsync(Socket socket, IPEndPoint remoteEndpoint, CancellationToken cancellationToken) { - return socket.ConnectAsync(remoteEndpoint, cancellationToken); + await socket.ConnectAsync(remoteEndpoint, cancellationToken).ConfigureAwait(false); } #endif diff --git a/src/Renci.SshNet/ForwardedPortDynamic.NET.cs b/src/Renci.SshNet/ForwardedPortDynamic.NET.cs index 36a804558..31b3a0ab9 100644 --- a/src/Renci.SshNet/ForwardedPortDynamic.NET.cs +++ b/src/Renci.SshNet/ForwardedPortDynamic.NET.cs @@ -204,10 +204,19 @@ private bool HandleSocks(IChannelDirectTcpip channel, Socket clientSocket, TimeS { // ignore exception thrown by interrupting the blocking receive as part of closing // the forwarded port +#if NETFRAMEWORK if (ex.SocketErrorCode != SocketError.Interrupted) { RaiseExceptionEvent(ex); } +#else + // Since .NET 5 the exception has been changed. + // more info https://github.com/dotnet/runtime/issues/41585 + if (ex.SocketErrorCode != SocketError.ConnectionAborted) + { + RaiseExceptionEvent(ex); + } +#endif return false; } finally diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index 740ec7ee1..d9399877b 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -7,44 +7,18 @@ ../Renci.SshNet.snk 6 true - net35;net40;net472;netstandard1.3;netstandard2.0 + net462;netstandard2.0;net6.0;net7.0 - - + - - - - - - - - - - - - - - FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_POLL;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII;FEATURE_ECDSA - - - FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII;FEATURE_ECDSA - - - FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII;FEATURE_ECDSA;FEATURE_TAP - - - FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_ENCODING_ASCII;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_REFLECTION_TYPEINFO;FEATURE_RNG_CREATE;FEATURE_SOCKET_TAP;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_SOCKET_DISPOSE;FEATURE_DNS_TAP;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_TAP - - + FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_ENCODING_ASCII;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_RNG_CREATE;FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_SOCKET_DISPOSE;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP;FEATURE_STREAM_APM;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_ECDSA;FEATURE_TAP diff --git a/test/Renci.SshNet.WindowsPhone8.Tests/App.xaml b/test/Renci.SshNet.WindowsPhone8.Tests/App.xaml deleted file mode 100644 index 0ce734075..000000000 --- a/test/Renci.SshNet.WindowsPhone8.Tests/App.xaml +++ /dev/null @@ -1,21 +0,0 @@ -锘 - - - - - - - - - - - - \ No newline at end of file diff --git a/test/Renci.SshNet.WindowsPhone8.Tests/App.xaml.cs b/test/Renci.SshNet.WindowsPhone8.Tests/App.xaml.cs deleted file mode 100644 index 771bdf257..000000000 --- a/test/Renci.SshNet.WindowsPhone8.Tests/App.xaml.cs +++ /dev/null @@ -1,222 +0,0 @@ -锘縰sing System; -using System.Diagnostics; -using System.Windows; -using System.Windows.Markup; -using System.Windows.Navigation; -using Microsoft.Phone.Controls; -using Microsoft.Phone.Shell; -using Renci.SshNet.Tests.Resources; - -namespace Renci.SshNet.Tests -{ - public partial class App : Application - { - /// - /// Provides easy access to the root frame of the Phone Application. - /// - /// The root frame of the Phone Application. - public static PhoneApplicationFrame RootFrame { get; private set; } - - /// - /// Constructor for the Application object. - /// - public App() - { - // Global handler for uncaught exceptions. - UnhandledException += Application_UnhandledException; - - // Standard XAML initialization - InitializeComponent(); - - // Phone-specific initialization - InitializePhoneApplication(); - - // Language display initialization - InitializeLanguage(); - - // Show graphics profiling information while debugging. - if (Debugger.IsAttached) - { - // Display the current frame rate counters. - Application.Current.Host.Settings.EnableFrameRateCounter = true; - - // Show the areas of the app that are being redrawn in each frame. - //Application.Current.Host.Settings.EnableRedrawRegions = true; - - // Enable non-production analysis visualization mode, - // which shows areas of a page that are handed off to GPU with a colored overlay. - //Application.Current.Host.Settings.EnableCacheVisualization = true; - - // Prevent the screen from turning off while under the debugger by disabling - // the application's idle detection. - // Caution:- Use this under debug mode only. Application that disables user idle detection will continue to run - // and consume battery power when the user is not using the phone. - PhoneApplicationService.Current.UserIdleDetectionMode = IdleDetectionMode.Disabled; - } - - } - - // Code to execute when the application is launching (eg, from Start) - // This code will not execute when the application is reactivated - private void Application_Launching(object sender, LaunchingEventArgs e) - { - } - - // Code to execute when the application is activated (brought to foreground) - // This code will not execute when the application is first launched - private void Application_Activated(object sender, ActivatedEventArgs e) - { - } - - // Code to execute when the application is deactivated (sent to background) - // This code will not execute when the application is closing - private void Application_Deactivated(object sender, DeactivatedEventArgs e) - { - } - - // Code to execute when the application is closing (eg, user hit Back) - // This code will not execute when the application is deactivated - private void Application_Closing(object sender, ClosingEventArgs e) - { - } - - // Code to execute if a navigation fails - private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e) - { - if (Debugger.IsAttached) - { - // A navigation has failed; break into the debugger - Debugger.Break(); - } - } - - // Code to execute on Unhandled Exceptions - private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) - { - if (Debugger.IsAttached) - { - // An unhandled exception has occurred; break into the debugger - Debugger.Break(); - } - } - - #region Phone application initialization - - // Avoid double-initialization - private bool phoneApplicationInitialized = false; - - // Do not add any additional code to this method - private void InitializePhoneApplication() - { - if (phoneApplicationInitialized) - return; - - // Create the frame but don't set it as RootVisual yet; this allows the splash - // screen to remain active until the application is ready to render. - RootFrame = new PhoneApplicationFrame(); - RootFrame.Navigated += CompleteInitializePhoneApplication; - - // Handle navigation failures - RootFrame.NavigationFailed += RootFrame_NavigationFailed; - - // Handle reset requests for clearing the backstack - RootFrame.Navigated += CheckForResetNavigation; - - // Ensure we don't initialize again - phoneApplicationInitialized = true; - } - - // Do not add any additional code to this method - private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e) - { - // Set the root visual to allow the application to render - if (RootVisual != RootFrame) - RootVisual = RootFrame; - - // Remove this handler since it is no longer needed - RootFrame.Navigated -= CompleteInitializePhoneApplication; - } - - private void CheckForResetNavigation(object sender, NavigationEventArgs e) - { - // If the app has received a 'reset' navigation, then we need to check - // on the next navigation to see if the page stack should be reset - if (e.NavigationMode == NavigationMode.Reset) - RootFrame.Navigated += ClearBackStackAfterReset; - } - - private void ClearBackStackAfterReset(object sender, NavigationEventArgs e) - { - // Unregister the event so it doesn't get called again - RootFrame.Navigated -= ClearBackStackAfterReset; - - // Only clear the stack for 'new' (forward) and 'refresh' navigations - if (e.NavigationMode != NavigationMode.New && e.NavigationMode != NavigationMode.Refresh) - return; - - // For UI consistency, clear the entire page stack - while (RootFrame.RemoveBackEntry() != null) - { - ; // do nothing - } - } - - #endregion - - // Initialize the app's font and flow direction as defined in its localized resource strings. - // - // To ensure that the font of your application is aligned with its supported languages and that the - // FlowDirection for each of those languages follows its traditional direction, ResourceLanguage - // and ResourceFlowDirection should be initialized in each resx file to match these values with that - // file's culture. For example: - // - // AppResources.es-ES.resx - // ResourceLanguage's value should be "es-ES" - // ResourceFlowDirection's value should be "LeftToRight" - // - // AppResources.ar-SA.resx - // ResourceLanguage's value should be "ar-SA" - // ResourceFlowDirection's value should be "RightToLeft" - // - // For more info on localizing Windows Phone apps see http://go.microsoft.com/fwlink/?LinkId=262072. - // - private void InitializeLanguage() - { - try - { - // Set the font to match the display language defined by the - // ResourceLanguage resource string for each supported language. - // - // Fall back to the font of the neutral language if the Display - // language of the phone is not supported. - // - // If a compiler error is hit then ResourceLanguage is missing from - // the resource file. - RootFrame.Language = XmlLanguage.GetLanguage(AppResources.ResourceLanguage); - - // Set the FlowDirection of all elements under the root frame based - // on the ResourceFlowDirection resource string for each - // supported language. - // - // If a compiler error is hit then ResourceFlowDirection is missing from - // the resource file. - FlowDirection flow = (FlowDirection)Enum.Parse(typeof(FlowDirection), AppResources.ResourceFlowDirection); - RootFrame.FlowDirection = flow; - } - catch - { - // If an exception is caught here it is most likely due to either - // ResourceLangauge not being correctly set to a supported language - // code or ResourceFlowDirection is set to a value other than LeftToRight - // or RightToLeft. - - if (Debugger.IsAttached) - { - Debugger.Break(); - } - - throw; - } - } - } -} \ No newline at end of file diff --git a/test/Renci.SshNet.WindowsPhone8.Tests/Assets/AlignmentGrid.png b/test/Renci.SshNet.WindowsPhone8.Tests/Assets/AlignmentGrid.png deleted file mode 100644 index f7d2e97804e451530960b57429a2b0a26c86f5d7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9042 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 IP1{HR1(GMkF8}}l diff --git a/test/Renci.SshNet.WindowsPhone8.Tests/Assets/Tiles/FlipCycleTileMedium.png b/test/Renci.SshNet.WindowsPhone8.Tests/Assets/Tiles/FlipCycleTileMedium.png deleted file mode 100644 index e93b89d600641c9d5b05f94493a9fde6afa850e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9070 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 - /// Provides access to string resources. - /// - public class LocalizedStrings - { - private static readonly AppResources _localizedResources = new AppResources(); - - public AppResources LocalizedResources { get { return _localizedResources; } } - } -} \ No newline at end of file diff --git a/test/Renci.SshNet.WindowsPhone8.Tests/MainPage.xaml b/test/Renci.SshNet.WindowsPhone8.Tests/MainPage.xaml deleted file mode 100644 index 4da3c91e9..000000000 --- a/test/Renci.SshNet.WindowsPhone8.Tests/MainPage.xaml +++ /dev/null @@ -1,62 +0,0 @@ -锘 - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/Renci.SshNet.WindowsPhone8.Tests/MainPage.xaml.cs b/test/Renci.SshNet.WindowsPhone8.Tests/MainPage.xaml.cs deleted file mode 100644 index ce08790e6..000000000 --- a/test/Renci.SshNet.WindowsPhone8.Tests/MainPage.xaml.cs +++ /dev/null @@ -1,21 +0,0 @@ -锘縰sing System.Threading; -using Microsoft.Phone.Controls; -using Microsoft.VisualStudio.TestPlatform.Core; -using Microsoft.VisualStudio.TestPlatform.TestExecutor; -using vstest_executionengine_platformbridge; - -namespace Renci.SshNet.Tests -{ - public partial class MainPage : PhoneApplicationPage - { - // Constructor - public MainPage() - { - InitializeComponent(); - - var wrapper = new TestExecutorServiceWrapper(); - new Thread(new ServiceMain((param0, param1) => wrapper.SendMessage((ContractName)param0, param1)).Run).Start(); - - } - } -} \ No newline at end of file diff --git a/test/Renci.SshNet.WindowsPhone8.Tests/Properties/AppManifest.xml b/test/Renci.SshNet.WindowsPhone8.Tests/Properties/AppManifest.xml deleted file mode 100644 index 6712a1178..000000000 --- a/test/Renci.SshNet.WindowsPhone8.Tests/Properties/AppManifest.xml +++ /dev/null @@ -1,6 +0,0 @@ -锘 - - - diff --git a/test/Renci.SshNet.WindowsPhone8.Tests/Properties/AssemblyInfo.cs b/test/Renci.SshNet.WindowsPhone8.Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index c9bbc102f..000000000 --- a/test/Renci.SshNet.WindowsPhone8.Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,37 +0,0 @@ -锘縰sing System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Resources; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Renci.SshNet.WindowsPhone8.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Renci.SshNet.WindowsPhone8.Tests")] -[assembly: AssemblyCopyright("Copyright 漏 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("911d635c-6e0e-46e8-9e8b-99bfb1790991")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] -[assembly: NeutralResourcesLanguageAttribute("en-US")] diff --git a/test/Renci.SshNet.WindowsPhone8.Tests/Properties/WMAppManifest.xml b/test/Renci.SshNet.WindowsPhone8.Tests/Properties/WMAppManifest.xml deleted file mode 100644 index 1590bfd8f..000000000 --- a/test/Renci.SshNet.WindowsPhone8.Tests/Properties/WMAppManifest.xml +++ /dev/null @@ -1,46 +0,0 @@ -锘 - - - - - Assets\ApplicationIcon.png - - - - - - - - - - - - - - Assets\Tiles\FlipCycleTileSmall.png - 0 - Assets\Tiles\FlipCycleTileMedium.png - Renci.SshNet.WindowsPhone8.Tests - - - - - - - - - - - vstest_executionengine_platformbridge.dll - - - - - - - - - - - - \ No newline at end of file diff --git a/test/Renci.SshNet.WindowsPhone8.Tests/Renci.SshNet.WindowsPhone8.Tests.csproj b/test/Renci.SshNet.WindowsPhone8.Tests/Renci.SshNet.WindowsPhone8.Tests.csproj deleted file mode 100644 index 212e28403..000000000 --- a/test/Renci.SshNet.WindowsPhone8.Tests/Renci.SshNet.WindowsPhone8.Tests.csproj +++ /dev/null @@ -1,148 +0,0 @@ -锘 - - - Debug - x86 - 10.0.20506 - 2.0 - {26F0D644-B3EF-47DF-8040-E9E4B2E63884} - {C089C8C0-30E0-4E22-80C0-CE093F111A43};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - Renci.SshNet.Tests - Renci.SshNet.Tests - WindowsPhone - v8.0 - $(TargetFrameworkVersion) - true - true - - - true - true - Renci.SshNet.WindowsPhone8.Tests_$(Configuration)_$(Platform).xap - Properties\AppManifest.xml - Renci.SshNet.WindowsPhone8.Tests.App - false - 11.0 - true - - - true - full - false - Bin\x86\Debug - TRACE;DEBUG;SILVERLIGHT - true - true - prompt - 4 - - - pdbonly - true - Bin\x86\Release - TRACE;SILVERLIGHT;WINDOWS_PHONE - true - true - prompt - 4 - - - true - full - false - Bin\ARM\Debug - DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE - true - true - prompt - 4 - - - pdbonly - true - Bin\ARM\Release - TRACE;SILVERLIGHT;WINDOWS_PHONE - true - true - prompt - 4 - - - - App.xaml - - - - MainPage.xaml - - - - True - True - AppResources.resx - - - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - - - - - - Designer - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - - - PublicResXFileCodeGenerator - AppResources.Designer.cs - - - - - - - - {4a6ca785-1c8a-47fe-98c0-30c675a9328b} - Renci.SshNet.WindowsPhone8 - - - - - - - - \ No newline at end of file diff --git a/test/Renci.SshNet.WindowsPhone8.Tests/Resources/AppResources.Designer.cs b/test/Renci.SshNet.WindowsPhone8.Tests/Resources/AppResources.Designer.cs deleted file mode 100644 index d4a8eaf71..000000000 --- a/test/Renci.SshNet.WindowsPhone8.Tests/Resources/AppResources.Designer.cs +++ /dev/null @@ -1,108 +0,0 @@ -锘//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Renci.SshNet.Tests.Resources { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class AppResources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal AppResources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Renci.SshNet.Tests.Resources.AppResources", typeof(AppResources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to add. - /// - public static string AppBarButtonText { - get { - return ResourceManager.GetString("AppBarButtonText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Menu Item. - /// - public static string AppBarMenuItemText { - get { - return ResourceManager.GetString("AppBarMenuItemText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MY APPLICATION. - /// - public static string ApplicationTitle { - get { - return ResourceManager.GetString("ApplicationTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to LeftToRight. - /// - public static string ResourceFlowDirection { - get { - return ResourceManager.GetString("ResourceFlowDirection", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to en-US. - /// - public static string ResourceLanguage { - get { - return ResourceManager.GetString("ResourceLanguage", resourceCulture); - } - } - } -} diff --git a/test/Renci.SshNet.WindowsPhone8.Tests/Resources/AppResources.resx b/test/Renci.SshNet.WindowsPhone8.Tests/Resources/AppResources.resx deleted file mode 100644 index 529a19431..000000000 --- a/test/Renci.SshNet.WindowsPhone8.Tests/Resources/AppResources.resx +++ /dev/null @@ -1,137 +0,0 @@ -锘 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - LeftToRight - Controls the FlowDirection for all elements in the RootFrame. Set to the traditional direction of this resource file's language - - - en-US - Controls the Language and ensures that the font for all elements in the RootFrame aligns with the app's language. Set to the language code of this resource file's language. - - - MY APPLICATION - - - add - - - Menu Item - - \ No newline at end of file From 8c932fb1e85760864393c2ed72e078a5bd8ddd9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Tue, 9 May 2023 21:21:13 +0200 Subject: [PATCH 18/96] Remove old features [Part 1] (#1117) Remove obsolete feature switches (now that we've remove support for legacy target frameworks) and remove corresponding conditional code. --- ...pose_SessionIsConnectedAndChannelIsOpen.cs | 3 - .../Classes/Common/CountdownEventTest.cs | 3 - .../CountdownEventTest_Dispose_NotSet.cs | 4 - .../Common/CountdownEventTest_Dispose_Set.cs | 4 - .../Sftp/SftpFileStreamAsyncTestBase.cs | 4 +- ...eStreamTest_OpenAsync_FileAccessInvalid.cs | 4 +- ...OpenAsync_FileModeAppend_FileAccessRead.cs | 4 +- ...sync_FileModeAppend_FileAccessReadWrite.cs | 4 +- ...penAsync_FileModeAppend_FileAccessWrite.cs | 4 +- ...nAsync_FileModeCreateNew_FileAccessRead.cs | 4 +- ...c_FileModeCreateNew_FileAccessReadWrite.cs | 4 +- ...Async_FileModeCreateNew_FileAccessWrite.cs | 4 +- ...OpenAsync_FileModeCreate_FileAccessRead.cs | 4 +- ...te_FileAccessReadWrite_FileDoesNotExist.cs | 4 +- ...deCreate_FileAccessReadWrite_FileExists.cs | 4 +- ...Create_FileAccessWrite_FileDoesNotExist.cs | 6 +- ...leModeCreate_FileAccessWrite_FileExists.cs | 6 +- ...ileStreamTest_OpenAsync_FileModeInvalid.cs | 4 +- ...ync_FileModeOpenOrCreate_FileAccessRead.cs | 6 +- ...ileModeOpenOrCreate_FileAccessReadWrite.cs | 4 +- ...nc_FileModeOpenOrCreate_FileAccessWrite.cs | 4 +- ...t_OpenAsync_FileModeOpen_FileAccessRead.cs | 4 +- ...nAsync_FileModeOpen_FileAccessReadWrite.cs | 4 +- ..._OpenAsync_FileModeOpen_FileAccessWrite.cs | 4 +- ...enAsync_FileModeTruncate_FileAccessRead.cs | 4 +- ...nc_FileModeTruncate_FileAccessReadWrite.cs | 4 +- ...nAsync_FileModeTruncate_FileAccessWrite.cs | 6 +- ...FromServerThanCountAndEqualToBufferSize.cs | 6 +- ...romServerThanCountAndLessThanBufferSize.cs | 4 +- ...fferAndReadMoreBytesFromServerThanCount.cs | 4 +- ...tGreatherThanTwoTimesTheWriteBufferSize.cs | 4 +- .../Classes/SftpClientTest.ConnectAsync.cs | 6 +- .../Classes/SftpClientTest.DeleteFileAsync.cs | 6 +- .../Classes/SftpClientTest.RenameFileAsync.cs | 4 +- .../Common/AsyncSocketListener.cs | 3 - .../Renci.SshNet.Tests.csproj | 2 +- .../Abstractions/CryptoAbstraction.cs | 129 ------- .../Abstractions/DiagnosticAbstraction.cs | 7 - .../Abstractions/DnsAbstraction.cs | 6 - .../Abstractions/ReflectionAbstraction.cs | 8 - .../Abstractions/SocketAbstraction.cs | 361 +----------------- .../Abstractions/SocketExtensions.cs | 4 +- .../Abstractions/ThreadAbstraction.cs | 19 - src/Renci.SshNet/BaseClient.cs | 7 +- src/Renci.SshNet/Common/ASCIIEncoding.cs | 167 -------- src/Renci.SshNet/Common/CountdownEvent.cs | 171 --------- src/Renci.SshNet/Common/Extensions.cs | 60 --- src/Renci.SshNet/Common/PacketDump.cs | 8 +- src/Renci.SshNet/Common/SshData.cs | 5 +- src/Renci.SshNet/Common/SshDataStream.cs | 6 - src/Renci.SshNet/Connection/ConnectorBase.cs | 7 - .../Connection/DirectConnector.cs | 2 - src/Renci.SshNet/Connection/IConnector.cs | 2 - .../Connection/IProtocolVersionExchange.cs | 2 - .../Connection/ProtocolVersionExchange.cs | 11 - src/Renci.SshNet/Connection/ProxyConnector.cs | 12 +- .../Connection/Socks4Connector.cs | 4 - src/Renci.SshNet/ConnectionInfo.cs | 2 - src/Renci.SshNet/IBaseClient.cs | 4 - src/Renci.SshNet/ISession.cs | 4 - src/Renci.SshNet/ISftpClient.cs | 13 - src/Renci.SshNet/NoneAuthenticationMethod.cs | 3 - src/Renci.SshNet/PrivateKeyFile.cs | 9 +- src/Renci.SshNet/Renci.SshNet.csproj | 4 +- .../crypto/prng/CryptoApiRandomGenerator.cs | 10 - .../Security/Cryptography/Bcrypt.cs | 8 +- .../Cryptography/EcdsaDigitalSignature.cs | 4 +- .../Security/Cryptography/EcdsaKey.cs | 4 +- .../Security/Cryptography/HMACMD5.cs | 6 +- .../Security/Cryptography/HMACSHA1.cs | 6 +- .../Security/Cryptography/HMACSHA256.cs | 6 +- .../Security/Cryptography/HMACSHA384.cs | 6 +- .../Security/Cryptography/HMACSHA512.cs | 6 +- src/Renci.SshNet/Session.cs | 67 ---- src/Renci.SshNet/Sftp/ISftpSession.cs | 24 -- src/Renci.SshNet/Sftp/SftpFileStream.cs | 13 +- src/Renci.SshNet/Sftp/SftpSession.cs | 31 -- src/Renci.SshNet/SftpClient.cs | 14 - src/Renci.SshNet/Shell.cs | 18 - 79 files changed, 60 insertions(+), 1353 deletions(-) delete mode 100644 src/Renci.SshNet/Common/ASCIIEncoding.cs delete mode 100644 src/Renci.SshNet/Common/CountdownEvent.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs index a75d407d3..da7739694 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs @@ -5,9 +5,6 @@ using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; -#if !FEATURE_SOCKET_DISPOSE -using Renci.SshNet.Common; -#endif // !FEATURE_SOCKET_DISPOSE using Renci.SshNet.Channels; using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; diff --git a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs b/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs index 6954beb14..6ab52acef 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs @@ -2,9 +2,6 @@ using System.Diagnostics; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; -#if !FEATURE_THREAD_COUNTDOWNEVENT -using CountdownEvent = Renci.SshNet.Common.CountdownEvent; -#endif namespace Renci.SshNet.Tests.Classes.Common { diff --git a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_NotSet.cs b/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_NotSet.cs index 3d5a5d17d..a2badf97e 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_NotSet.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_NotSet.cs @@ -1,10 +1,6 @@ 锘縰sing System; using Microsoft.VisualStudio.TestTools.UnitTesting; -#if !FEATURE_THREAD_COUNTDOWNEVENT -using CountdownEvent = Renci.SshNet.Common.CountdownEvent; -#else using System.Threading; -#endif namespace Renci.SshNet.Tests.Classes.Common { diff --git a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_Set.cs b/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_Set.cs index 60f13c302..df5f5b979 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_Set.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_Set.cs @@ -1,10 +1,6 @@ 锘縰sing System; using Microsoft.VisualStudio.TestTools.UnitTesting; -#if !FEATURE_THREAD_COUNTDOWNEVENT -using CountdownEvent = Renci.SshNet.Common.CountdownEvent; -#else using System.Threading; -#endif namespace Renci.SshNet.Tests.Classes.Common { diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamAsyncTestBase.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamAsyncTestBase.cs index b8b7b4ae9..110a20bed 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamAsyncTestBase.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamAsyncTestBase.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -66,4 +65,3 @@ protected byte[] GenerateRandom(uint length, Random random) } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileAccessInvalid.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileAccessInvalid.cs index fab12dad6..4febea075 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileAccessInvalid.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileAccessInvalid.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -54,4 +53,3 @@ public void CtorShouldHaveThrownArgumentException() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs index 0ffeaeb6c..14a2338b0 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -55,4 +54,3 @@ public void CtorShouldHaveThrownArgumentException() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs index 2ed8cd14f..c58f33873 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -55,4 +54,3 @@ public void CtorShouldHaveThrownArgumentException() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs index 8d9bc960b..a95be4233 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -152,4 +151,3 @@ public void RequestFStatOnSftpSessionShouldBeInvokedOnce() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs index eb83af777..a697a3c53 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -55,4 +54,3 @@ public void CtorShouldHaveThrownArgumentException() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessReadWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessReadWrite.cs index 5c2318086..c1b271dd3 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessReadWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessReadWrite.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -133,4 +132,3 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs index 7671fe300..b6c6487df 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -133,4 +132,3 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs index 2c6d28a6e..460081fca 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -55,4 +54,3 @@ public void CtorShouldHaveThrownArgumentException() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs index 5fe519f17..9563b9fcd 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -133,4 +132,3 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileExists.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileExists.cs index a313afb96..e2d5d061c 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileExists.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileExists.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -133,4 +132,3 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs index c1d7fc960..aa29b7397 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -132,5 +131,4 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnceWithTruncateAndOnceWithCr SftpSessionMock.Verify(p => p.RequestOpenAsync(_path, Flags.Write | Flags.CreateNewOrOpen | Flags.Truncate, _cancellationToken), Times.Once); } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs index 834299706..ed001ab2a 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -132,5 +131,4 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() SftpSessionMock.Verify(p => p.RequestOpenAsync(_path, Flags.Write | Flags.CreateNewOrOpen | Flags.Truncate, _cancellationToken), Times.Once); } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeInvalid.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeInvalid.cs index 9cfc4a37f..075967ac2 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeInvalid.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeInvalid.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -54,4 +53,3 @@ public void CtorShouldHaveThrownArgumentException() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessRead.cs index f9360c40c..15a40915a 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessRead.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -137,5 +136,4 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() SftpSessionMock.Verify(p => p.RequestOpenAsync(_path, Flags.Read | Flags.CreateNewOrOpen, _cancellationToken), Times.Once); } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs index 7e5e4d867..c7cd5d4a4 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -133,4 +132,3 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessWrite.cs index edccf9b99..0b69f581e 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessWrite.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -133,4 +132,3 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessRead.cs index 1d4f686fa..76387888f 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessRead.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -139,4 +138,3 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs index 8ee641337..56589f668 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -133,4 +132,3 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessWrite.cs index 4be281731..db61a2a6e 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessWrite.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -133,4 +132,3 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs index 9883a5a76..9247274e8 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -56,4 +55,3 @@ public void CtorShouldHaveThrownArgumentException() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessReadWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessReadWrite.cs index 2d0efd24f..ecde02148 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessReadWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessReadWrite.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -133,4 +132,3 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessWrite.cs index 5f61e1984..0c06eba6a 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessWrite.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -132,5 +131,4 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() SftpSessionMock.Verify(p => p.RequestOpenAsync(_path, Flags.Write | Flags.Truncate, _cancellationToken), Times.Once); } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs index 13f3e1255..d3b5983be 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -155,5 +154,4 @@ public async Task ReadShouldReturnAllRemaningBytesFromReadBufferAndReadAgainWhen SftpSessionMock.Verify(p => p.RequestReadAsync(_handle, (ulong)(_serverData1Length + _serverData2Length), _readBufferSize, default)); } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs index 2da0a4385..29121639c 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -149,4 +148,3 @@ public async Task SubsequentReadShouldReadAgainFromCurrentPositionFromServerAndN } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs index 80895217e..d95ffd0a0 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.IO; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -140,4 +139,3 @@ public async Task SubsequentReadShouldReturnAllRemaningBytesFromReadBufferAndRea } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs index dcbfedf63..a9f4587b0 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.Globalization; using System.IO; using System.Threading; @@ -140,4 +139,3 @@ public async Task FlushShouldFlushBuffer() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs index 75602ea2c..df7a8f0b6 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.Net.Sockets; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -44,5 +43,4 @@ public async Task ConnectAsync_ProxyHostNameInvalid_ShouldThrowSocketExceptionWi } } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFileAsync.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFileAsync.cs index 20e68e812..9d8464377 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFileAsync.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFileAsync.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Tests.Properties; using System; using System.Threading.Tasks; @@ -23,5 +22,4 @@ public async Task Test_Sftp_DeleteFileAsync_Null() } } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFileAsync.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFileAsync.cs index 38d651f97..a24ec0942 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFileAsync.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFileAsync.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Tests.Properties; using System; using System.IO; @@ -63,4 +62,3 @@ public async Task Test_Sftp_RenameFileAsync_Null() } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs b/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs index 8fa81a301..78319f76f 100644 --- a/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs +++ b/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs @@ -3,9 +3,6 @@ using System.Net; using System.Net.Sockets; using System.Threading; -#if !FEATURE_SOCKET_DISPOSE -using Renci.SshNet.Common; -#endif // !FEATURE_SOCKET_DISPOSE namespace Renci.SshNet.Tests.Common { diff --git a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index b577179e2..80c36aa70 100644 --- a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -7,7 +7,7 @@ - FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_TPL;FEATURE_TAP + FEATURE_TPL diff --git a/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs b/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs index ff9e50a52..2c7d38b0c 100644 --- a/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs @@ -5,9 +5,7 @@ namespace Renci.SshNet.Abstractions { internal static class CryptoAbstraction { -#if FEATURE_RNG_CREATE || FEATURE_RNG_CSP private static readonly System.Security.Cryptography.RandomNumberGenerator Randomizer = CreateRandomNumberGenerator(); -#endif /// /// Generates a array of the specified length, and fills it with a @@ -31,105 +29,38 @@ public static byte[] GenerateRandom(int length) /// public static void GenerateRandom(byte[] data) { -#if FEATURE_RNG_CREATE || FEATURE_RNG_CSP Randomizer.GetBytes(data); -#else - if(data == null) - throw new ArgumentNullException("data"); - - var buffer = Windows.Security.Cryptography.CryptographicBuffer.GenerateRandom((uint) data.Length); - System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions.CopyTo(buffer, data); -#endif } -#if FEATURE_RNG_CREATE || FEATURE_RNG_CSP public static System.Security.Cryptography.RandomNumberGenerator CreateRandomNumberGenerator() { -#if FEATURE_RNG_CREATE return System.Security.Cryptography.RandomNumberGenerator.Create(); -#elif FEATURE_RNG_CSP - return new System.Security.Cryptography.RNGCryptoServiceProvider(); -#else -#error Creation of RandomNumberGenerator is not implemented. -#endif } -#endif // FEATURE_RNG_CREATE || FEATURE_RNG_CSP -#if FEATURE_HASH_MD5 public static System.Security.Cryptography.MD5 CreateMD5() { return System.Security.Cryptography.MD5.Create(); } -#else - public static global::SshNet.Security.Cryptography.MD5 CreateMD5() - { - return new global::SshNet.Security.Cryptography.MD5(); - } -#endif // FEATURE_HASH_MD5 -#if FEATURE_HASH_SHA1_CREATE || FEATURE_HASH_SHA1_MANAGED public static System.Security.Cryptography.SHA1 CreateSHA1() { -#if FEATURE_HASH_SHA1_CREATE return System.Security.Cryptography.SHA1.Create(); -#elif FEATURE_HASH_SHA1_MANAGED - return new System.Security.Cryptography.SHA1Managed(); -#endif } -#else - public static global::SshNet.Security.Cryptography.SHA1 CreateSHA1() - { - return new global::SshNet.Security.Cryptography.SHA1(); - } -#endif -#if FEATURE_HASH_SHA256_CREATE || FEATURE_HASH_SHA256_MANAGED public static System.Security.Cryptography.SHA256 CreateSHA256() { -#if FEATURE_HASH_SHA256_CREATE return System.Security.Cryptography.SHA256.Create(); -#elif FEATURE_HASH_SHA256_MANAGED - return new System.Security.Cryptography.SHA256Managed(); -#endif } -#else - public static global::SshNet.Security.Cryptography.SHA256 CreateSHA256() - { - return new global::SshNet.Security.Cryptography.SHA256(); - } -#endif -#if FEATURE_HASH_SHA384_CREATE || FEATURE_HASH_SHA384_MANAGED public static System.Security.Cryptography.SHA384 CreateSHA384() { -#if FEATURE_HASH_SHA384_CREATE return System.Security.Cryptography.SHA384.Create(); -#elif FEATURE_HASH_SHA384_MANAGED - return new System.Security.Cryptography.SHA384Managed(); -#endif - } -#else - public static global::SshNet.Security.Cryptography.SHA384 CreateSHA384() - { - return new global::SshNet.Security.Cryptography.SHA384(); } -#endif -#if FEATURE_HASH_SHA512_CREATE || FEATURE_HASH_SHA512_MANAGED public static System.Security.Cryptography.SHA512 CreateSHA512() { -#if FEATURE_HASH_SHA512_CREATE return System.Security.Cryptography.SHA512.Create(); -#elif FEATURE_HASH_SHA512_MANAGED - return new System.Security.Cryptography.SHA512Managed(); -#endif } -#else - public static global::SshNet.Security.Cryptography.SHA512 CreateSHA512() - { - return new global::SshNet.Security.Cryptography.SHA512(); - } -#endif #if FEATURE_HASH_RIPEMD160_CREATE || FEATURE_HASH_RIPEMD160_MANAGED public static System.Security.Cryptography.RIPEMD160 CreateRIPEMD160() @@ -147,7 +78,6 @@ public static System.Security.Cryptography.RIPEMD160 CreateRIPEMD160() } #endif // FEATURE_HASH_RIPEMD160 -#if FEATURE_HMAC_MD5 public static System.Security.Cryptography.HMACMD5 CreateHMACMD5(byte[] key) { return new System.Security.Cryptography.HMACMD5(key); @@ -157,19 +87,7 @@ public static HMACMD5 CreateHMACMD5(byte[] key, int hashSize) { return new HMACMD5(key, hashSize); } -#else - public static global::SshNet.Security.Cryptography.HMACMD5 CreateHMACMD5(byte[] key) - { - return new global::SshNet.Security.Cryptography.HMACMD5(key); - } - - public static global::SshNet.Security.Cryptography.HMACMD5 CreateHMACMD5(byte[] key, int hashSize) - { - return new global::SshNet.Security.Cryptography.HMACMD5(key, hashSize); - } -#endif // FEATURE_HMAC_MD5 -#if FEATURE_HMAC_SHA1 public static System.Security.Cryptography.HMACSHA1 CreateHMACSHA1(byte[] key) { return new System.Security.Cryptography.HMACSHA1(key); @@ -179,19 +97,7 @@ public static HMACSHA1 CreateHMACSHA1(byte[] key, int hashSize) { return new HMACSHA1(key, hashSize); } -#else - public static global::SshNet.Security.Cryptography.HMACSHA1 CreateHMACSHA1(byte[] key) - { - return new global::SshNet.Security.Cryptography.HMACSHA1(key); - } - public static global::SshNet.Security.Cryptography.HMACSHA1 CreateHMACSHA1(byte[] key, int hashSize) - { - return new global::SshNet.Security.Cryptography.HMACSHA1(key, hashSize); - } -#endif // FEATURE_HMAC_SHA1 - -#if FEATURE_HMAC_SHA256 public static System.Security.Cryptography.HMACSHA256 CreateHMACSHA256(byte[] key) { return new System.Security.Cryptography.HMACSHA256(key); @@ -201,19 +107,7 @@ public static HMACSHA256 CreateHMACSHA256(byte[] key, int hashSize) { return new HMACSHA256(key, hashSize); } -#else - public static global::SshNet.Security.Cryptography.HMACSHA256 CreateHMACSHA256(byte[] key) - { - return new global::SshNet.Security.Cryptography.HMACSHA256(key); - } - public static global::SshNet.Security.Cryptography.HMACSHA256 CreateHMACSHA256(byte[] key, int hashSize) - { - return new global::SshNet.Security.Cryptography.HMACSHA256(key, hashSize); - } -#endif // FEATURE_HMAC_SHA256 - -#if FEATURE_HMAC_SHA384 public static System.Security.Cryptography.HMACSHA384 CreateHMACSHA384(byte[] key) { return new System.Security.Cryptography.HMACSHA384(key); @@ -223,19 +117,7 @@ public static HMACSHA384 CreateHMACSHA384(byte[] key, int hashSize) { return new HMACSHA384(key, hashSize); } -#else - public static global::SshNet.Security.Cryptography.HMACSHA384 CreateHMACSHA384(byte[] key) - { - return new global::SshNet.Security.Cryptography.HMACSHA384(key); - } - - public static global::SshNet.Security.Cryptography.HMACSHA384 CreateHMACSHA384(byte[] key, int hashSize) - { - return new global::SshNet.Security.Cryptography.HMACSHA384(key, hashSize); - } -#endif // FEATURE_HMAC_SHA384 -#if FEATURE_HMAC_SHA512 public static System.Security.Cryptography.HMACSHA512 CreateHMACSHA512(byte[] key) { return new System.Security.Cryptography.HMACSHA512(key); @@ -245,17 +127,6 @@ public static HMACSHA512 CreateHMACSHA512(byte[] key, int hashSize) { return new HMACSHA512(key, hashSize); } -#else - public static global::SshNet.Security.Cryptography.HMACSHA512 CreateHMACSHA512(byte[] key) - { - return new global::SshNet.Security.Cryptography.HMACSHA512(key); - } - - public static global::SshNet.Security.Cryptography.HMACSHA512 CreateHMACSHA512(byte[] key, int hashSize) - { - return new global::SshNet.Security.Cryptography.HMACSHA512(key, hashSize); - } -#endif // FEATURE_HMAC_SHA512 #if FEATURE_HMAC_RIPEMD160 public static System.Security.Cryptography.HMACRIPEMD160 CreateHMACRIPEMD160(byte[] key) diff --git a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs index 6fc1308ee..16ee1c0ab 100644 --- a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs @@ -1,14 +1,10 @@ 锘縰sing System.Diagnostics; -#if FEATURE_DIAGNOSTICS_TRACESOURCE using System.Threading; -#endif // FEATURE_DIAGNOSTICS_TRACESOURCE namespace Renci.SshNet.Abstractions { internal static class DiagnosticAbstraction { -#if FEATURE_DIAGNOSTICS_TRACESOURCE - private static readonly SourceSwitch SourceSwitch = new SourceSwitch("SshNetSwitch"); public static bool IsEnabled(TraceEventType traceEventType) @@ -22,14 +18,11 @@ public static bool IsEnabled(TraceEventType traceEventType) #else new TraceSource("SshNet.Logging"); #endif // DEBUG -#endif // FEATURE_DIAGNOSTICS_TRACESOURCE [Conditional("DEBUG")] public static void Log(string text) { -#if FEATURE_DIAGNOSTICS_TRACESOURCE Loggging.TraceEvent(TraceEventType.Verbose, Thread.CurrentThread.ManagedThreadId, text); -#endif // FEATURE_DIAGNOSTICS_TRACESOURCE } } } diff --git a/src/Renci.SshNet/Abstractions/DnsAbstraction.cs b/src/Renci.SshNet/Abstractions/DnsAbstraction.cs index a2ac9d58f..707521eae 100644 --- a/src/Renci.SshNet/Abstractions/DnsAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/DnsAbstraction.cs @@ -1,10 +1,7 @@ 锘縰sing System; using System.Net; using System.Net.Sockets; - -#if FEATURE_TAP using System.Threading.Tasks; -#endif #if FEATURE_DNS_SYNC #elif FEATURE_DNS_APM @@ -92,7 +89,6 @@ public static IPAddress[] GetHostAddresses(string hostNameOrAddress) #endif } -#if FEATURE_TAP /// /// Returns the Internet Protocol (IP) addresses for the specified host. /// @@ -107,7 +103,5 @@ public static Task GetHostAddressesAsync(string hostNameOrAddress) { return Dns.GetHostAddressesAsync(hostNameOrAddress); } -#endif - } } diff --git a/src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs b/src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs index 0c7abf5c6..1140c9a60 100644 --- a/src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs @@ -1,10 +1,6 @@ 锘縰sing System; using System.Collections.Generic; -#if FEATURE_REFLECTION_TYPEINFO -using System.Reflection; -#else using System.Linq; -#endif // FEATURE_REFLECTION_TYPEINFO namespace Renci.SshNet.Abstractions { @@ -13,12 +9,8 @@ internal static class ReflectionAbstraction public static IEnumerable GetCustomAttributes(this Type type, bool inherit) where T:Attribute { -#if FEATURE_REFLECTION_TYPEINFO - return type.GetTypeInfo().GetCustomAttributes(inherit); -#else var attributes = type.GetCustomAttributes(typeof(T), inherit); return attributes.Cast(); -#endif } } } diff --git a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs index e358767a1..e7740d574 100644 --- a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs @@ -3,9 +3,8 @@ using System.Net; using System.Net.Sockets; using System.Threading; -#if FEATURE_TAP using System.Threading.Tasks; -#endif + using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; @@ -17,11 +16,7 @@ public static bool CanRead(Socket socket) { if (socket.Connected) { -#if FEATURE_SOCKET_POLL return socket.Poll(-1, SelectMode.SelectRead) && socket.Available > 0; -#else - return true; -#endif // FEATURE_SOCKET_POLL } return false; @@ -40,11 +35,7 @@ public static bool CanWrite(Socket socket) { if (socket != null && socket.Connected) { -#if FEATURE_SOCKET_POLL return socket.Poll(-1, SelectMode.SelectWrite); -#else - return true; -#endif // FEATURE_SOCKET_POLL } return false; @@ -62,12 +53,10 @@ public static void Connect(Socket socket, IPEndPoint remoteEndpoint, TimeSpan co ConnectCore(socket, remoteEndpoint, connectTimeout, false); } -#if FEATURE_TAP public static async Task ConnectAsync(Socket socket, IPEndPoint remoteEndpoint, CancellationToken cancellationToken) { await socket.ConnectAsync(remoteEndpoint, cancellationToken).ConfigureAwait(false); } -#endif private static void ConnectCore(Socket socket, IPEndPoint remoteEndpoint, TimeSpan connectTimeout, bool ownsSocket) { @@ -153,7 +142,6 @@ public static void ClearReadBuffer(Socket socket) public static int ReadPartial(Socket socket, byte[] buffer, int offset, int size, TimeSpan timeout) { -#if FEATURE_SOCKET_SYNC socket.ReceiveTimeout = (int) timeout.TotalMilliseconds; try @@ -167,53 +155,10 @@ public static int ReadPartial(Socket socket, byte[] buffer, int offset, int size "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds)); throw; } -#elif FEATURE_SOCKET_EAP - var receiveCompleted = new ManualResetEvent(false); - var sendReceiveToken = new PartialSendReceiveToken(socket, receiveCompleted); - var args = new SocketAsyncEventArgs - { - RemoteEndPoint = socket.RemoteEndPoint, - UserToken = sendReceiveToken - }; - args.Completed += ReceiveCompleted; - args.SetBuffer(buffer, offset, size); - - try - { - if (socket.ReceiveAsync(args)) - { - if (!receiveCompleted.WaitOne(timeout)) - throw new SshOperationTimeoutException( - string.Format( - CultureInfo.InvariantCulture, - "Socket read operation has timed out after {0:F0} milliseconds.", - timeout.TotalMilliseconds)); - } - else - { - sendReceiveToken.Process(args); - } - - if (args.SocketError != SocketError.Success) - throw new SocketException((int) args.SocketError); - - return args.BytesTransferred; - } - finally - { - // initialize token to avoid the waithandle getting used after it's disposed - args.UserToken = null; - args.Dispose(); - receiveCompleted.Dispose(); - } -#else - #error Receiving data from a Socket is not implemented. -#endif } public static void ReadContinuous(Socket socket, byte[] buffer, int offset, int size, Action processReceivedBytesAction) { -#if FEATURE_SOCKET_SYNC // do not time-out receive socket.ReceiveTimeout = 0; @@ -247,30 +192,6 @@ public static void ReadContinuous(Socket socket, byte[] buffer, int offset, int } } } -#elif FEATURE_SOCKET_EAP - var completionWaitHandle = new ManualResetEvent(false); - var readToken = new ContinuousReceiveToken(socket, processReceivedBytesAction, completionWaitHandle); - var args = new SocketAsyncEventArgs - { - RemoteEndPoint = socket.RemoteEndPoint, - UserToken = readToken - }; - args.Completed += ReceiveCompleted; - args.SetBuffer(buffer, offset, size); - - if (!socket.ReceiveAsync(args)) - { - ReceiveCompleted(null, args); - } - - completionWaitHandle.WaitOne(); - completionWaitHandle.Dispose(); - - if (readToken.Exception != null) - throw readToken.Exception; -#else - #error Receiving data from a Socket is not implemented. -#endif } /// @@ -327,12 +248,10 @@ public static byte[] Read(Socket socket, int size, TimeSpan timeout) return buffer; } -#if FEATURE_TAP public static Task ReadAsync(Socket socket, byte[] buffer, int offset, int length, CancellationToken cancellationToken) { return socket.ReceiveAsync(buffer, offset, length, cancellationToken); } -#endif /// /// Receives data from a bound into a receive buffer. @@ -358,7 +277,6 @@ public static Task ReadAsync(Socket socket, byte[] buffer, int offset, int /// public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeSpan readTimeout) { -#if FEATURE_SOCKET_SYNC var totalBytesRead = 0; var totalBytesToRead = size; @@ -386,52 +304,12 @@ public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeS throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture, "Socket read operation has timed out after {0:F0} milliseconds.", readTimeout.TotalMilliseconds)); - throw; + throw; } } while (totalBytesRead < totalBytesToRead); return totalBytesRead; -#elif FEATURE_SOCKET_EAP - var receiveCompleted = new ManualResetEvent(false); - var sendReceiveToken = new BlockingSendReceiveToken(socket, buffer, offset, size, receiveCompleted); - - var args = new SocketAsyncEventArgs - { - UserToken = sendReceiveToken, - RemoteEndPoint = socket.RemoteEndPoint - }; - args.Completed += ReceiveCompleted; - args.SetBuffer(buffer, offset, size); - - try - { - if (socket.ReceiveAsync(args)) - { - if (!receiveCompleted.WaitOne(readTimeout)) - throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture, - "Socket read operation has timed out after {0:F0} milliseconds.", readTimeout.TotalMilliseconds)); - } - else - { - sendReceiveToken.Process(args); - } - - if (args.SocketError != SocketError.Success) - throw new SocketException((int) args.SocketError); - - return sendReceiveToken.TotalBytesTransferred; - } - finally - { - // initialize token to avoid the waithandle getting used after it's disposed - args.UserToken = null; - args.Dispose(); - receiveCompleted.Dispose(); - } -#else -#error Receiving data from a Socket is not implemented. -#endif } public static void Send(Socket socket, byte[] data) @@ -441,7 +319,6 @@ public static void Send(Socket socket, byte[] data) public static void Send(Socket socket, byte[] data, int offset, int size) { -#if FEATURE_SOCKET_SYNC var totalBytesSent = 0; // how many bytes are already sent var totalBytesToSend = size; @@ -467,46 +344,6 @@ public static void Send(Socket socket, byte[] data, int offset, int size) throw; // any serious error occurr } } while (totalBytesSent < totalBytesToSend); -#elif FEATURE_SOCKET_EAP - var sendCompleted = new ManualResetEvent(false); - var sendReceiveToken = new BlockingSendReceiveToken(socket, data, offset, size, sendCompleted); - var socketAsyncSendArgs = new SocketAsyncEventArgs - { - RemoteEndPoint = socket.RemoteEndPoint, - UserToken = sendReceiveToken - }; - socketAsyncSendArgs.SetBuffer(data, offset, size); - socketAsyncSendArgs.Completed += SendCompleted; - - try - { - if (socket.SendAsync(socketAsyncSendArgs)) - { - if (!sendCompleted.WaitOne()) - throw new SocketException((int) SocketError.TimedOut); - } - else - { - sendReceiveToken.Process(socketAsyncSendArgs); - } - - if (socketAsyncSendArgs.SocketError != SocketError.Success) - throw new SocketException((int) socketAsyncSendArgs.SocketError); - - if (sendReceiveToken.TotalBytesTransferred == 0) - throw new SshConnectionException("An established connection was aborted by the server.", - DisconnectReason.ConnectionLost); - } - finally - { - // initialize token to avoid the completion waithandle getting used after it's disposed - socketAsyncSendArgs.UserToken = null; - socketAsyncSendArgs.Dispose(); - sendCompleted.Dispose(); - } -#else - #error Sending data to a Socket is not implemented. -#endif } public static bool IsErrorResumable(SocketError socketError) @@ -531,199 +368,5 @@ private static void ConnectCompleted(object sender, SocketAsyncEventArgs e) } #endif // FEATURE_SOCKET_EAP -#if FEATURE_SOCKET_EAP && !FEATURE_SOCKET_SYNC - private static void ReceiveCompleted(object sender, SocketAsyncEventArgs e) - { - var sendReceiveToken = (Token) e.UserToken; - if (sendReceiveToken != null) - sendReceiveToken.Process(e); - } - - private static void SendCompleted(object sender, SocketAsyncEventArgs e) - { - var sendReceiveToken = (Token) e.UserToken; - if (sendReceiveToken != null) - sendReceiveToken.Process(e); - } - - private interface Token - { - void Process(SocketAsyncEventArgs args); - } - - private class BlockingSendReceiveToken : Token - { - public BlockingSendReceiveToken(Socket socket, byte[] buffer, int offset, int size, EventWaitHandle completionWaitHandle) - { - _socket = socket; - _buffer = buffer; - _offset = offset; - _bytesToTransfer = size; - _completionWaitHandle = completionWaitHandle; - } - - public void Process(SocketAsyncEventArgs args) - { - if (args.SocketError == SocketError.Success) - { - TotalBytesTransferred += args.BytesTransferred; - - if (TotalBytesTransferred == _bytesToTransfer) - { - // finished transferring specified bytes - _completionWaitHandle.Set(); - return; - } - - if (args.BytesTransferred == 0) - { - // remote server closed the connection - _completionWaitHandle.Set(); - return; - } - - _offset += args.BytesTransferred; - args.SetBuffer(_buffer, _offset, _bytesToTransfer - TotalBytesTransferred); - ResumeOperation(args); - return; - } - - if (IsErrorResumable(args.SocketError)) - { - ThreadAbstraction.Sleep(30); - ResumeOperation(args); - return; - } - - // we're dealing with a (fatal) error - _completionWaitHandle.Set(); - } - - private void ResumeOperation(SocketAsyncEventArgs args) - { - switch (args.LastOperation) - { - case SocketAsyncOperation.Receive: - _socket.ReceiveAsync(args); - break; - case SocketAsyncOperation.Send: - _socket.SendAsync(args); - break; - } - } - - private readonly int _bytesToTransfer; - public int TotalBytesTransferred { get; private set; } - private readonly EventWaitHandle _completionWaitHandle; - private readonly Socket _socket; - private readonly byte[] _buffer; - private int _offset; - } - - private class PartialSendReceiveToken : Token - { - public PartialSendReceiveToken(Socket socket, EventWaitHandle completionWaitHandle) - { - _socket = socket; - _completionWaitHandle = completionWaitHandle; - } - - public void Process(SocketAsyncEventArgs args) - { - if (args.SocketError == SocketError.Success) - { - _completionWaitHandle.Set(); - return; - } - - if (IsErrorResumable(args.SocketError)) - { - ThreadAbstraction.Sleep(30); - ResumeOperation(args); - return; - } - - // we're dealing with a (fatal) error - _completionWaitHandle.Set(); - } - - private void ResumeOperation(SocketAsyncEventArgs args) - { - switch (args.LastOperation) - { - case SocketAsyncOperation.Receive: - _socket.ReceiveAsync(args); - break; - case SocketAsyncOperation.Send: - _socket.SendAsync(args); - break; - } - } - - private readonly EventWaitHandle _completionWaitHandle; - private readonly Socket _socket; - } - - private class ContinuousReceiveToken : Token - { - public ContinuousReceiveToken(Socket socket, Action processReceivedBytesAction, EventWaitHandle completionWaitHandle) - { - _socket = socket; - _processReceivedBytesAction = processReceivedBytesAction; - _completionWaitHandle = completionWaitHandle; - } - - public Exception Exception { get; private set; } - - public void Process(SocketAsyncEventArgs args) - { - if (args.SocketError == SocketError.Success) - { - if (args.BytesTransferred == 0) - { - // remote socket was closed - _completionWaitHandle.Set(); - return; - } - - _processReceivedBytesAction(args.Buffer, args.Offset, args.BytesTransferred); - ResumeOperation(args); - return; - } - - if (IsErrorResumable(args.SocketError)) - { - ThreadAbstraction.Sleep(30); - ResumeOperation(args); - return; - } - - if (args.SocketError != SocketError.OperationAborted) - { - Exception = new SocketException((int) args.SocketError); - } - - // we're dealing with a (fatal) error - _completionWaitHandle.Set(); - } - - private void ResumeOperation(SocketAsyncEventArgs args) - { - switch (args.LastOperation) - { - case SocketAsyncOperation.Receive: - _socket.ReceiveAsync(args); - break; - case SocketAsyncOperation.Send: - _socket.SendAsync(args); - break; - } - } - - private readonly EventWaitHandle _completionWaitHandle; - private readonly Socket _socket; - private readonly Action _processReceivedBytesAction; - } -#endif // FEATURE_SOCKET_EAP && !FEATURE_SOCKET_SYNC } } diff --git a/src/Renci.SshNet/Abstractions/SocketExtensions.cs b/src/Renci.SshNet/Abstractions/SocketExtensions.cs index d763e1a34..7d3c30f93 100644 --- a/src/Renci.SshNet/Abstractions/SocketExtensions.cs +++ b/src/Renci.SshNet/Abstractions/SocketExtensions.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_TAP -using System; +锘縰sing System; using System.Net; using System.Net.Sockets; using System.Runtime.CompilerServices; @@ -116,4 +115,3 @@ public static async Task ReceiveAsync(this Socket socket, byte[] buffer, in } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs b/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs index 8c344404b..35824ee10 100644 --- a/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs @@ -10,13 +10,7 @@ internal static class ThreadAbstraction /// The number of milliseconds for which the thread is suspended. public static void Sleep(int millisecondsTimeout) { -#if FEATURE_THREAD_SLEEP System.Threading.Thread.Sleep(millisecondsTimeout); -#elif FEATURE_THREAD_TAP - System.Threading.Tasks.Task.Delay(millisecondsTimeout).GetAwaiter().GetResult(); -#else - #error Suspend of the current thread is not implemented. -#endif } public static void ExecuteThreadLongRunning(Action action) @@ -24,15 +18,8 @@ public static void ExecuteThreadLongRunning(Action action) if (action == null) throw new ArgumentNullException("action"); -#if FEATURE_THREAD_TAP var taskCreationOptions = System.Threading.Tasks.TaskCreationOptions.LongRunning; System.Threading.Tasks.Task.Factory.StartNew(action, taskCreationOptions); -#else - new System.Threading.Thread(() => action()) - { - IsBackground = true - }.Start(); -#endif } /// @@ -41,16 +28,10 @@ public static void ExecuteThreadLongRunning(Action action) /// The action to execute. public static void ExecuteThread(Action action) { -#if FEATURE_THREAD_THREADPOOL if (action == null) throw new ArgumentNullException("action"); System.Threading.ThreadPool.QueueUserWorkItem(o => action()); -#elif FEATURE_THREAD_TAP - System.Threading.Tasks.Task.Run(action); -#else - #error Execution of action in a separate thread is not implemented. -#endif } } } diff --git a/src/Renci.SshNet/BaseClient.cs b/src/Renci.SshNet/BaseClient.cs index 754396108..fdc4e3a39 100644 --- a/src/Renci.SshNet/BaseClient.cs +++ b/src/Renci.SshNet/BaseClient.cs @@ -1,9 +1,8 @@ 锘縰sing System; using System.Net.Sockets; using System.Threading; -#if FEATURE_TAP using System.Threading.Tasks; -#endif + using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; @@ -242,7 +241,6 @@ public void Connect() StartKeepAliveTimer(); } -#if FEATURE_TAP /// /// Asynchronously connects client to the server. /// @@ -297,7 +295,6 @@ public async Task ConnectAsync(CancellationToken cancellationToken) } StartKeepAliveTimer(); } -#endif /// /// Disconnects client from the server. @@ -533,7 +530,6 @@ private ISession CreateAndConnectSession() } } -#if FEATURE_TAP private async Task CreateAndConnectSessionAsync(CancellationToken cancellationToken) { var session = _serviceFactory.CreateSession(ConnectionInfo, _serviceFactory.CreateSocketFactory()); @@ -551,7 +547,6 @@ private async Task CreateAndConnectSessionAsync(CancellationToken canc throw; } } -#endif private void DisposeSession(ISession session) { diff --git a/src/Renci.SshNet/Common/ASCIIEncoding.cs b/src/Renci.SshNet/Common/ASCIIEncoding.cs deleted file mode 100644 index f41c49de8..000000000 --- a/src/Renci.SshNet/Common/ASCIIEncoding.cs +++ /dev/null @@ -1,167 +0,0 @@ -锘#if !FEATURE_ENCODING_ASCII - -using System; -using System.Text; - -namespace Renci.SshNet.Common -{ - /// - /// Implementation of ASCII Encoding - /// - public class ASCIIEncoding : Encoding - { - private readonly char _fallbackChar; - - private static readonly char[] ByteToChar; - - static ASCIIEncoding() - { - if (ByteToChar == null) - { - ByteToChar = new char[128]; - var ch = '\0'; - for (byte i = 0; i < 128; i++) - { - ByteToChar[i] = ch++; - } - } - } - - /// - /// Initializes a new instance of the class. - /// - public ASCIIEncoding() - { - _fallbackChar = '?'; - } - - /// - /// Calculates the number of bytes produced by encoding a set of characters from the specified character array. - /// - /// The character array containing the set of characters to encode. - /// The index of the first character to encode. - /// The number of characters to encode. - /// - /// The number of bytes produced by encoding the specified characters. - /// - /// is null. - /// or is less than zero.-or- and do not denote a valid range in . - public override int GetByteCount(char[] chars, int index, int count) - { - return count; - } - - /// - /// Encodes a set of characters from the specified character array into the specified byte array. - /// - /// The character array containing the set of characters to encode. - /// The index of the first character to encode. - /// The number of characters to encode. - /// The byte array to contain the resulting sequence of bytes. - /// The index at which to start writing the resulting sequence of bytes. - /// - /// The actual number of bytes written into . - /// - /// is null.-or- is null. - /// or or is less than zero.-or- and do not denote a valid range in .-or- is not a valid index in . - /// does not have enough capacity from to the end of the array to accommodate the resulting bytes. - public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) - { - for (var i = 0; i < charCount && i < chars.Length; i++) - { - var b = (byte)chars[i + charIndex]; - - if (b > 127) - b = (byte) _fallbackChar; - - bytes[i + byteIndex] = b; - } - return charCount; - } - - /// - /// Calculates the number of characters produced by decoding a sequence of bytes from the specified byte array. - /// - /// The byte array containing the sequence of bytes to decode. - /// The index of the first byte to decode. - /// The number of bytes to decode. - /// - /// The number of characters produced by decoding the specified sequence of bytes. - /// - /// is null. - /// or is less than zero.-or- and do not denote a valid range in . - public override int GetCharCount(byte[] bytes, int index, int count) - { - return count; - } - - /// - /// Decodes a sequence of bytes from the specified byte array into the specified character array. - /// - /// The byte array containing the sequence of bytes to decode. - /// The index of the first byte to decode. - /// The number of bytes to decode. - /// The character array to contain the resulting set of characters. - /// The index at which to start writing the resulting set of characters. - /// - /// The actual number of characters written into . - /// - /// is null.-or- is null. - /// or or is less than zero.-or- and do not denote a valid range in .-or- is not a valid index in . - /// does not have enough capacity from to the end of the array to accommodate the resulting characters. - public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) - { - for (var i = 0; i < byteCount; i++) - { - var b = bytes[i + byteIndex]; - char ch; - - if (b > 127) - { - ch = _fallbackChar; - } - else - { - ch = ByteToChar[b]; - } - - chars[i + charIndex] = ch; - } - return byteCount; - } - - /// - /// Calculates the maximum number of bytes produced by encoding the specified number of characters. - /// - /// The number of characters to encode. - /// - /// The maximum number of bytes produced by encoding the specified number of characters. - /// - /// is less than zero. - public override int GetMaxByteCount(int charCount) - { - if (charCount < 0) - throw new ArgumentOutOfRangeException("charCount", "Non-negative number required."); - - return charCount + 1; - } - - /// - /// Calculates the maximum number of characters produced by decoding the specified number of bytes. - /// - /// The number of bytes to decode. - /// - /// The maximum number of characters produced by decoding the specified number of bytes. - /// - /// is less than zero. - public override int GetMaxCharCount(int byteCount) - { - if (byteCount < 0) - throw new ArgumentOutOfRangeException("byteCount", "Non-negative number required."); - - return byteCount; - } - } -} - -#endif // !FEATURE_ENCODING_ASCII \ No newline at end of file diff --git a/src/Renci.SshNet/Common/CountdownEvent.cs b/src/Renci.SshNet/Common/CountdownEvent.cs deleted file mode 100644 index 7387a786f..000000000 --- a/src/Renci.SshNet/Common/CountdownEvent.cs +++ /dev/null @@ -1,171 +0,0 @@ -锘#if !FEATURE_THREAD_COUNTDOWNEVENT - -using System; -using System.Threading; - -namespace Renci.SshNet.Common -{ - /// - /// Represents a synchronization primitive that is signaled when its count reaches zero. - /// - internal class CountdownEvent : IDisposable - { - private int _count; - private ManualResetEvent _event; - private bool _disposed; - - /// - /// Initializes a new instance of class with the specified count. - /// - /// The number of signals initially required to set the . - /// is less than zero. - /// - /// If is zero, the event is created in a signaled state. - /// - public CountdownEvent(int initialCount) - { - if (initialCount < 0) - { - throw new ArgumentOutOfRangeException("initialCount"); - } - - _count = initialCount; - - var initialState = _count == 0; - _event = new ManualResetEvent(initialState); - } - - /// - /// Gets the number of remaining signals required to set the event. - /// - /// - /// The number of remaining signals required to set the event. - /// - public int CurrentCount - { - get { return _count; } - } - - /// - /// Indicates whether the 's current count has reached zero. - /// - /// - /// true if the current count is zero; otherwise, false. - /// - public bool IsSet - { - get { return _count == 0; } - } - - /// - /// Gets a that is used to wait for the event to be set. - /// - /// - /// A that is used to wait for the event to be set. - /// - /// The current instance has already been disposed. - public WaitHandle WaitHandle - { - get - { - EnsureNotDisposed(); - - return _event; - } - } - - - /// - /// Registers a signal with the , decrementing the value of . - /// - /// - /// true if the signal caused the count to reach zero and the event was set; otherwise, false. - /// - /// The current instance has already been disposed. - /// The current instance is already set. - public bool Signal() - { - EnsureNotDisposed(); - - if (_count <= 0) - throw new InvalidOperationException("Invalid attempt made to decrement the event's count below zero."); - - var newCount = Interlocked.Decrement(ref _count); - if (newCount == 0) - { - _event.Set(); - return true; - } - - return false; - } - - /// - /// Increments the 's current count by one. - /// - /// The current instance has already been disposed. - /// The current instance is already set. - /// is equal to or greather than . - public void AddCount() - { - EnsureNotDisposed(); - - if (_count == int.MaxValue) - throw new InvalidOperationException("TODO"); - - Interlocked.Increment(ref _count); - } - - /// - /// Blocks the current thread until the is set, using a - /// to measure the timeout. - /// - /// A that represents the number of milliseconds to wait, or a that represents -1 milliseconds to wait indefinitely. - /// - /// true if the was set; otherwise, false. - /// - /// The current instance has already been disposed. - public bool Wait(TimeSpan timeout) - { - EnsureNotDisposed(); - - return _event.WaitOne(timeout); - } - - /// - /// Releases all resources used by the current instance of the class. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Releases the unmanaged resources used by the , and optionally releases the managed resources. - /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - var theEvent = _event; - if (theEvent != null) - { - _event = null; - theEvent.Dispose(); - } - - _disposed = true; - } - } - - private void EnsureNotDisposed() - { - if (_disposed) - throw new ObjectDisposedException(GetType().Name); - } - } -} - -#endif // FEATURE_THREAD_COUNTDOWNEVENT \ No newline at end of file diff --git a/src/Renci.SshNet/Common/Extensions.cs b/src/Renci.SshNet/Common/Extensions.cs index 17d72d7fb..3a5311f07 100644 --- a/src/Renci.SshNet/Common/Extensions.cs +++ b/src/Renci.SshNet/Common/Extensions.cs @@ -5,9 +5,6 @@ using System.Net; using System.Net.Sockets; using System.Text; -#if !FEATURE_WAITHANDLE_DISPOSE -using System.Threading; -#endif // !FEATURE_WAITHANDLE_DISPOSE using Renci.SshNet.Abstractions; using Renci.SshNet.Messages; @@ -305,62 +302,5 @@ internal static bool IsConnected(this Socket socket) return false; return socket.Connected; } - -#if !FEATURE_SOCKET_DISPOSE - /// - /// Disposes the specified socket. - /// - /// The socket. - [DebuggerNonUserCode] - internal static void Dispose(this Socket socket) - { - if (socket == null) - throw new NullReferenceException(); - - socket.Close(); - } -#endif // !FEATURE_SOCKET_DISPOSE - -#if !FEATURE_WAITHANDLE_DISPOSE - /// - /// Disposes the specified handle. - /// - /// The handle. - [DebuggerNonUserCode] - internal static void Dispose(this WaitHandle handle) - { - if (handle == null) - throw new NullReferenceException(); - - handle.Close(); - } -#endif // !FEATURE_WAITHANDLE_DISPOSE - -#if !FEATURE_HASHALGORITHM_DISPOSE - /// - /// Disposes the specified algorithm. - /// - /// The algorithm. - [DebuggerNonUserCode] - internal static void Dispose(this System.Security.Cryptography.HashAlgorithm algorithm) - { - if (algorithm == null) - throw new NullReferenceException(); - - algorithm.Clear(); - } -#endif // FEATURE_HASHALGORITHM_DISPOSE - -#if !FEATURE_STRINGBUILDER_CLEAR - /// - /// Clears the contents of the string builder. - /// - /// The to clear. - public static void Clear(this StringBuilder value) - { - value.Length = 0; - value.Capacity = 16; - } -#endif // !FEATURE_STRINGBUILDER_CLEAR } } diff --git a/src/Renci.SshNet/Common/PacketDump.cs b/src/Renci.SshNet/Common/PacketDump.cs index 7b50582cb..cd68549d6 100644 --- a/src/Renci.SshNet/Common/PacketDump.cs +++ b/src/Renci.SshNet/Common/PacketDump.cs @@ -79,13 +79,9 @@ private static string AsHex(byte[] data, int length) private static string AsAscii(byte[] data, int length) { -#if FEATURE_ENCODING_ASCII - var encoding = Encoding.ASCII; -#else - var encoding = new ASCIIEncoding(); -#endif + var encoding = Encoding.ASCII; - var ascii = new StringBuilder(); + var ascii = new StringBuilder(); const char dot = '.'; for (var i = 0; i < length; i++) diff --git a/src/Renci.SshNet/Common/SshData.cs b/src/Renci.SshNet/Common/SshData.cs index 8e4eca406..844bace7a 100644 --- a/src/Renci.SshNet/Common/SshData.cs +++ b/src/Renci.SshNet/Common/SshData.cs @@ -11,11 +11,8 @@ public abstract class SshData { internal const int DefaultCapacity = 64; -#if FEATURE_ENCODING_ASCII internal static readonly Encoding Ascii = Encoding.ASCII; -#else - internal static readonly Encoding Ascii = new ASCIIEncoding(); -#endif + internal static readonly Encoding Utf8 = Encoding.UTF8; private SshDataStream _stream; diff --git a/src/Renci.SshNet/Common/SshDataStream.cs b/src/Renci.SshNet/Common/SshDataStream.cs index 010800c3e..0e024491c 100644 --- a/src/Renci.SshNet/Common/SshDataStream.cs +++ b/src/Renci.SshNet/Common/SshDataStream.cs @@ -252,13 +252,7 @@ public override byte[] ToArray() { if (Capacity == Length) { -#if FEATURE_MEMORYSTREAM_GETBUFFER return GetBuffer(); -#elif FEATURE_MEMORYSTREAM_TRYGETBUFFER - ArraySegment buffer; - if (TryGetBuffer(out buffer)) - return buffer.Array; -#endif } return base.ToArray(); } diff --git a/src/Renci.SshNet/Connection/ConnectorBase.cs b/src/Renci.SshNet/Connection/ConnectorBase.cs index ffa026750..6bcd556fd 100644 --- a/src/Renci.SshNet/Connection/ConnectorBase.cs +++ b/src/Renci.SshNet/Connection/ConnectorBase.cs @@ -5,10 +5,7 @@ using System.Net; using System.Net.Sockets; using System.Threading; - -#if FEATURE_TAP using System.Threading.Tasks; -#endif namespace Renci.SshNet.Connection { @@ -26,9 +23,7 @@ protected ConnectorBase(ISocketFactory socketFactory) public abstract Socket Connect(IConnectionInfo connectionInfo); -#if FEATURE_TAP public abstract Task ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken); -#endif /// /// Establishes a socket connection to the specified host and port. @@ -63,7 +58,6 @@ protected Socket SocketConnect(string host, int port, TimeSpan timeout) } } -#if FEATURE_TAP /// /// Establishes a socket connection to the specified host and port. /// @@ -97,7 +91,6 @@ protected async Task SocketConnectAsync(string host, int port, Cancellat throw; } } -#endif protected static byte SocketReadByte(Socket socket) { diff --git a/src/Renci.SshNet/Connection/DirectConnector.cs b/src/Renci.SshNet/Connection/DirectConnector.cs index 0d07bb936..0f428fc31 100644 --- a/src/Renci.SshNet/Connection/DirectConnector.cs +++ b/src/Renci.SshNet/Connection/DirectConnector.cs @@ -14,11 +14,9 @@ public override Socket Connect(IConnectionInfo connectionInfo) return SocketConnect(connectionInfo.Host, connectionInfo.Port, connectionInfo.Timeout); } -#if FEATURE_TAP public override System.Threading.Tasks.Task ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken) { return SocketConnectAsync(connectionInfo.Host, connectionInfo.Port, cancellationToken); } -#endif } } diff --git a/src/Renci.SshNet/Connection/IConnector.cs b/src/Renci.SshNet/Connection/IConnector.cs index 9eccabe62..e49587b74 100644 --- a/src/Renci.SshNet/Connection/IConnector.cs +++ b/src/Renci.SshNet/Connection/IConnector.cs @@ -7,8 +7,6 @@ internal interface IConnector { Socket Connect(IConnectionInfo connectionInfo); -#if FEATURE_TAP System.Threading.Tasks.Task ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken); -#endif } } diff --git a/src/Renci.SshNet/Connection/IProtocolVersionExchange.cs b/src/Renci.SshNet/Connection/IProtocolVersionExchange.cs index c804c291f..252cda986 100644 --- a/src/Renci.SshNet/Connection/IProtocolVersionExchange.cs +++ b/src/Renci.SshNet/Connection/IProtocolVersionExchange.cs @@ -19,8 +19,6 @@ internal interface IProtocolVersionExchange /// SshIdentification Start(string clientVersion, Socket socket, TimeSpan timeout); -#if FEATURE_TAP System.Threading.Tasks.Task StartAsync(string clientVersion, Socket socket, System.Threading.CancellationToken cancellationToken); -#endif } } diff --git a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs index 4e6957c10..716b8a42c 100644 --- a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs +++ b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs @@ -8,9 +8,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading; -#if FEATURE_TAP using System.Threading.Tasks; -#endif namespace Renci.SshNet.Connection { @@ -24,11 +22,7 @@ internal class ProtocolVersionExchange : IProtocolVersionExchange { private const byte Null = 0x00; -#if FEATURE_REGEX_COMPILE private static readonly Regex ServerVersionRe = new Regex("^SSH-(?[^-]+)-(?.+?)([ ](?.+))?$", RegexOptions.Compiled); -#else - private static readonly Regex ServerVersionRe = new Regex("^SSH-(?[^-]+)-(?.+?)([ ](?.+))?$"); -#endif /// /// Performs the SSH protocol version exchange. @@ -82,7 +76,6 @@ public SshIdentification Start(string clientVersion, Socket socket, TimeSpan tim } } -#if FEATURE_TAP public async Task StartAsync(string clientVersion, Socket socket, CancellationToken cancellationToken) { // Immediately send the identification string since the spec states both sides MUST send an identification string @@ -125,7 +118,6 @@ public async Task StartAsync(string clientVersion, Socket soc } } } -#endif private static string GetGroupValue(Match match, string groupName) { @@ -203,7 +195,6 @@ private static string SocketReadLine(Socket socket, TimeSpan timeout, List return null; } -#if FEATURE_TAP private static async Task SocketReadLineAsync(Socket socket, CancellationToken cancellationToken, List buffer) { var data = new byte[1]; @@ -254,7 +245,5 @@ private static async Task SocketReadLineAsync(Socket socket, Cancellatio } } } -#endif - } } diff --git a/src/Renci.SshNet/Connection/ProxyConnector.cs b/src/Renci.SshNet/Connection/ProxyConnector.cs index 6cc2ac9d4..164ae4835 100644 --- a/src/Renci.SshNet/Connection/ProxyConnector.cs +++ b/src/Renci.SshNet/Connection/ProxyConnector.cs @@ -1,12 +1,8 @@ -锘#if !FEATURE_SOCKET_DISPOSE -using Renci.SshNet.Common; -#endif -using System; +锘縰sing System; using System.Net.Sockets; -#if FEATURE_TAP using System.Threading; using System.Threading.Tasks; -#endif + namespace Renci.SshNet.Connection { @@ -19,7 +15,6 @@ public ProxyConnector(ISocketFactory socketFactory) : protected abstract void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket); -#if FEATURE_TAP // ToDo: Performs async/sync fallback, true async version should be implemented in derived classes protected virtual Task HandleProxyConnectAsync(IConnectionInfo connectionInfo, Socket socket, CancellationToken cancellationToken) { @@ -31,7 +26,6 @@ protected virtual Task HandleProxyConnectAsync(IConnectionInfo connectionInfo, S } return Task.CompletedTask; } -#endif public override Socket Connect(IConnectionInfo connectionInfo) { @@ -51,7 +45,6 @@ public override Socket Connect(IConnectionInfo connectionInfo) } } -#if FEATURE_TAP public override async Task ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken) { var socket = await SocketConnectAsync(connectionInfo.ProxyHost, connectionInfo.ProxyPort, cancellationToken).ConfigureAwait(false); @@ -69,6 +62,5 @@ public override async Task ConnectAsync(IConnectionInfo connectionInfo, throw; } } -#endif } } diff --git a/src/Renci.SshNet/Connection/Socks4Connector.cs b/src/Renci.SshNet/Connection/Socks4Connector.cs index ccf4e1456..d507872c6 100644 --- a/src/Renci.SshNet/Connection/Socks4Connector.cs +++ b/src/Renci.SshNet/Connection/Socks4Connector.cs @@ -125,11 +125,7 @@ private static byte[] GetProxyUserBytes(string proxyUser) return Array.Empty; } -#if FEATURE_ENCODING_ASCII return Encoding.ASCII.GetBytes(proxyUser); -#else - return new ASCIIEncoding().GetBytes(proxyUser); -#endif } } } diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index af8e1ca5c..f0f8b57c7 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -382,11 +382,9 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy HostKeyAlgorithms = new Dictionary> { {"ssh-ed25519", data => new KeyHostAlgorithm("ssh-ed25519", new ED25519Key(), data)}, -#if FEATURE_ECDSA {"ecdsa-sha2-nistp256", data => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(), data)}, {"ecdsa-sha2-nistp384", data => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(), data)}, {"ecdsa-sha2-nistp521", data => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(), data)}, -#endif {"ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data)}, {"ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(), data)}, //{"x509v3-sign-rsa", () => { ... }, diff --git a/src/Renci.SshNet/IBaseClient.cs b/src/Renci.SshNet/IBaseClient.cs index bd9518ac4..c11adb4f6 100644 --- a/src/Renci.SshNet/IBaseClient.cs +++ b/src/Renci.SshNet/IBaseClient.cs @@ -2,9 +2,7 @@ using System; using System.Net.Sockets; using System.Threading; -#if FEATURE_TAP using System.Threading.Tasks; -#endif namespace Renci.SshNet { @@ -68,7 +66,6 @@ public interface IBaseClient /// Failed to establish proxy connection. void Connect(); -#if FEATURE_TAP /// /// Asynchronously connects client to the server. /// @@ -82,7 +79,6 @@ public interface IBaseClient /// Authentication of SSH session failed. /// Failed to establish proxy connection. Task ConnectAsync(CancellationToken cancellationToken); -#endif /// /// Disconnects client from the server. diff --git a/src/Renci.SshNet/ISession.cs b/src/Renci.SshNet/ISession.cs index cde647a46..bc123c776 100644 --- a/src/Renci.SshNet/ISession.cs +++ b/src/Renci.SshNet/ISession.cs @@ -6,9 +6,7 @@ using Renci.SshNet.Messages; using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Messages.Connection; -#if FEATURE_TAP using System.Threading.Tasks; -#endif namespace Renci.SshNet { @@ -57,7 +55,6 @@ internal interface ISession : IDisposable /// Failed to establish proxy connection. void Connect(); -#if FEATURE_TAP /// /// Asynchronously connects to the server. /// @@ -68,7 +65,6 @@ internal interface ISession : IDisposable /// Authentication of SSH session failed. /// Failed to establish proxy connection. Task ConnectAsync(CancellationToken cancellationToken); -#endif /// /// Create a new SSH session channel. diff --git a/src/Renci.SshNet/ISftpClient.cs b/src/Renci.SshNet/ISftpClient.cs index eda042eff..99e1e7b06 100644 --- a/src/Renci.SshNet/ISftpClient.cs +++ b/src/Renci.SshNet/ISftpClient.cs @@ -4,10 +4,8 @@ using System.Text; using Renci.SshNet.Sftp; using Renci.SshNet.Common; -#if FEATURE_TAP using System.Threading; using System.Threading.Tasks; -#endif namespace Renci.SshNet { @@ -492,7 +490,6 @@ public interface ISftpClient : IBaseClient, IDisposable /// The method was called after the client was disposed. void DeleteFile(string path); -#if FEATURE_TAP /// /// Asynchronously deletes remote file specified by path. /// @@ -506,7 +503,6 @@ public interface ISftpClient : IBaseClient, IDisposable /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. Task DeleteFileAsync(string path, CancellationToken cancellationToken); -#endif /// /// Downloads remote file specified by the path into the stream. @@ -673,7 +669,6 @@ public interface ISftpClient : IBaseClient, IDisposable /// The method was called after the client was disposed. SftpFileSytemInformation GetStatus(string path); -#if FEATURE_TAP /// /// Asynchronously gets status using statvfs@openssh.com request. /// @@ -687,7 +682,6 @@ public interface ISftpClient : IBaseClient, IDisposable /// is null. /// The method was called after the client was disposed. Task GetStatusAsync(string path, CancellationToken cancellationToken); -#endif /// /// Retrieves list of files in remote directory. @@ -704,8 +698,6 @@ public interface ISftpClient : IBaseClient, IDisposable /// The method was called after the client was disposed. IEnumerable ListDirectory(string path, Action listCallback = null); -#if FEATURE_TAP - /// /// Asynchronously retrieves list of files in remote directory. /// @@ -721,7 +713,6 @@ public interface ISftpClient : IBaseClient, IDisposable /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. Task> ListDirectoryAsync(string path, CancellationToken cancellationToken); -#endif /// /// Opens a on the specified path with read/write access. @@ -750,7 +741,6 @@ public interface ISftpClient : IBaseClient, IDisposable /// The method was called after the client was disposed. SftpFileStream Open(string path, FileMode mode, FileAccess access); -#if FEATURE_TAP /// /// Asynchronously opens a on the specified path, with the specified mode and access. /// @@ -766,7 +756,6 @@ public interface ISftpClient : IBaseClient, IDisposable /// Client is not connected. /// The method was called after the client was disposed. Task OpenAsync(string path, FileMode mode, FileAccess access, CancellationToken cancellationToken); -#endif /// /// Opens an existing file for reading. @@ -906,7 +895,6 @@ public interface ISftpClient : IBaseClient, IDisposable /// The method was called after the client was disposed. void RenameFile(string oldPath, string newPath); -#if FEATURE_TAP /// /// Asynchronously renames remote file from old path to new path. /// @@ -920,7 +908,6 @@ public interface ISftpClient : IBaseClient, IDisposable /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. Task RenameFileAsync(string oldPath, string newPath, CancellationToken cancellationToken); -#endif /// /// Renames remote file from old path to new path. diff --git a/src/Renci.SshNet/NoneAuthenticationMethod.cs b/src/Renci.SshNet/NoneAuthenticationMethod.cs index a5d842fd7..93586ade9 100644 --- a/src/Renci.SshNet/NoneAuthenticationMethod.cs +++ b/src/Renci.SshNet/NoneAuthenticationMethod.cs @@ -1,8 +1,5 @@ 锘縰sing System; using System.Threading; -#if !FEATURE_WAITHANDLE_DISPOSE -using Renci.SshNet.Common; -#endif // !FEATURE_WAITHANDLE_DISPOSE using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Messages; diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index f29b3e958..5ec7f248d 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -66,11 +66,8 @@ namespace Renci.SshNet public class PrivateKeyFile : IPrivateKeySource, IDisposable { private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?[A-Z0-9-]+),(?[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?([a-zA-Z0-9/+=]{1,80}\r?\n)+)-+ *END \k PRIVATE KEY *-+", -#if FEATURE_REGEX_COMPILE RegexOptions.Compiled | RegexOptions.Multiline); -#else - RegexOptions.Multiline); -#endif + private Key _key; @@ -221,12 +218,10 @@ private void Open(Stream privateKey, string passPhrase) _key = new DsaKey(decryptedData); HostKey = new KeyHostAlgorithm("ssh-dss", _key); break; -#if FEATURE_ECDSA case "EC": _key = new EcdsaKey(decryptedData); HostKey = new KeyHostAlgorithm(_key.ToString(), _key); break; -#endif case "OPENSSH": _key = ParseOpenSshV1Key(decryptedData, passPhrase); HostKey = new KeyHostAlgorithm(_key.ToString(), _key); @@ -497,7 +492,6 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) unencryptedPrivateKey = privateKeyReader.ReadBignum2(); parsedKey = new ED25519Key(publicKey.Reverse(), unencryptedPrivateKey); break; -#if FEATURE_ECDSA case "ecdsa-sha2-nistp256": case "ecdsa-sha2-nistp384": case "ecdsa-sha2-nistp521": @@ -510,7 +504,6 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) unencryptedPrivateKey = privateKeyReader.ReadBignum2(); parsedKey = new EcdsaKey(curve, publicKey, unencryptedPrivateKey.TrimLeadingZeros()); break; -#endif case "ssh-rsa": var modulus = privateKeyReader.ReadBignum(); //n var exponent = privateKeyReader.ReadBignum(); //e diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index d9399877b..2f39c80ec 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -11,7 +11,7 @@ - FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_REGEX_COMPILE;FEATURE_BINARY_SERIALIZATION;FEATURE_RNG_CREATE;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_SOCKET_DISPOSE;FEATURE_STREAM_APM;FEATURE_DNS_SYNC;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_HMAC_RIPEMD160;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_ENCODING_ASCII;FEATURE_ECDSA;FEATURE_TAP + FEATURE_BINARY_SERIALIZATION;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_DNS_SYNC;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160 @@ -19,6 +19,6 @@ - FEATURE_STRINGBUILDER_CLEAR;FEATURE_HASHALGORITHM_DISPOSE;FEATURE_ENCODING_ASCII;FEATURE_DIAGNOSTICS_TRACESOURCE;FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_MEMORYSTREAM_GETBUFFER;FEATURE_MEMORYSTREAM_TRYGETBUFFER;FEATURE_RNG_CREATE;FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_SOCKET_SYNC;FEATURE_SOCKET_SELECT;FEATURE_SOCKET_POLL;FEATURE_SOCKET_DISPOSE;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP;FEATURE_STREAM_APM;FEATURE_STREAM_TAP;FEATURE_THREAD_COUNTDOWNEVENT;FEATURE_THREAD_TAP;FEATURE_THREAD_THREADPOOL;FEATURE_THREAD_SLEEP;FEATURE_WAITHANDLE_DISPOSE;FEATURE_HASH_MD5;FEATURE_HASH_SHA1_CREATE;FEATURE_HASH_SHA256_CREATE;FEATURE_HASH_SHA384_CREATE;FEATURE_HASH_SHA512_CREATE;FEATURE_HMAC_MD5;FEATURE_HMAC_SHA1;FEATURE_HMAC_SHA256;FEATURE_HMAC_SHA384;FEATURE_HMAC_SHA512;FEATURE_ECDSA;FEATURE_TAP + FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/CryptoApiRandomGenerator.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/CryptoApiRandomGenerator.cs index 5dd468b04..50ae6f38d 100644 --- a/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/CryptoApiRandomGenerator.cs +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/CryptoApiRandomGenerator.cs @@ -9,9 +9,7 @@ internal class CryptoApiRandomGenerator private readonly RandomNumberGenerator rndProv; public CryptoApiRandomGenerator() -#if FEATURE_RNG_CREATE || FEATURE_RNG_CSP : this(Abstractions.CryptoAbstraction.CreateRandomNumberGenerator()) -#endif { } @@ -34,15 +32,7 @@ public virtual void AddSeedMaterial(long seed) public virtual void NextBytes(byte[] bytes) { -#if FEATURE_RNG_CREATE || FEATURE_RNG_CSP rndProv.GetBytes(bytes); -#else - if (bytes == null) - throw new ArgumentNullException("bytes"); - - var buffer = Windows.Security.Cryptography.CryptographicBuffer.GenerateRandom((uint)bytes.Length); - System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeBufferExtensions.CopyTo(buffer, bytes); -#endif } public virtual void NextBytes(byte[] bytes, int start, int len) diff --git a/src/Renci.SshNet/Security/Cryptography/Bcrypt.cs b/src/Renci.SshNet/Security/Cryptography/Bcrypt.cs index 837d00318..14f6169a5 100644 --- a/src/Renci.SshNet/Security/Cryptography/Bcrypt.cs +++ b/src/Renci.SshNet/Security/Cryptography/Bcrypt.cs @@ -499,14 +499,10 @@ public static string GenerateSalt(int workFactor) throw new ArgumentOutOfRangeException("workFactor", "The work factor must be between 4 and 31 (inclusive)"); byte[] rnd = new byte[BCRYPT_SALT_LEN]; -#if FEATURE_RNG_CREATE + RandomNumberGenerator rng = RandomNumberGenerator.Create(); -#elif FEATURE_RNG_CSP - RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); -#endif -#if FEATURE_RNG_CREATE || FEATURE_RNG_CSP + rng.GetBytes(rnd); -#endif StringBuilder rs = new StringBuilder(); rs.AppendFormat("$2a${0:00}$", workFactor); diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs index 920614672..b5561b5da 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_ECDSA -using System; +锘縰sing System; using Renci.SshNet.Common; using System.Globalization; using System.Security.Cryptography; @@ -186,4 +185,3 @@ protected override int BufferCapacity } } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs index 46f1dcc65..1674a6677 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -1,5 +1,4 @@ -锘#if FEATURE_ECDSA -using System; +锘縰sing System; using System.IO; using System.Text; using System.Runtime.InteropServices; @@ -467,4 +466,3 @@ protected virtual void Dispose(bool disposing) #endregion } } -#endif \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Cryptography/HMACMD5.cs b/src/Renci.SshNet/Security/Cryptography/HMACMD5.cs index 86b246432..cd129fe69 100644 --- a/src/Renci.SshNet/Security/Cryptography/HMACMD5.cs +++ b/src/Renci.SshNet/Security/Cryptography/HMACMD5.cs @@ -1,6 +1,4 @@ -锘#if FEATURE_HMAC_MD5 - -using System.Security.Cryptography; +锘縰sing System.Security.Cryptography; using Renci.SshNet.Common; namespace Renci.SshNet.Security.Cryptography @@ -57,5 +55,3 @@ protected override byte[] HashFinal() } } } - -#endif // FEATURE_HMAC_MD5 diff --git a/src/Renci.SshNet/Security/Cryptography/HMACSHA1.cs b/src/Renci.SshNet/Security/Cryptography/HMACSHA1.cs index d8f47af12..49ad384d4 100644 --- a/src/Renci.SshNet/Security/Cryptography/HMACSHA1.cs +++ b/src/Renci.SshNet/Security/Cryptography/HMACSHA1.cs @@ -1,6 +1,4 @@ -锘#if FEATURE_HMAC_SHA1 - -using System.Security.Cryptography; +锘縰sing System.Security.Cryptography; using Renci.SshNet.Common; namespace Renci.SshNet.Security.Cryptography @@ -57,5 +55,3 @@ protected override byte[] HashFinal() } } } - -#endif // FEATURE_HMAC_SHA1 diff --git a/src/Renci.SshNet/Security/Cryptography/HMACSHA256.cs b/src/Renci.SshNet/Security/Cryptography/HMACSHA256.cs index cb1c31859..2598704e4 100644 --- a/src/Renci.SshNet/Security/Cryptography/HMACSHA256.cs +++ b/src/Renci.SshNet/Security/Cryptography/HMACSHA256.cs @@ -1,6 +1,4 @@ -锘#if FEATURE_HMAC_SHA256 - -using System.Security.Cryptography; +锘縰sing System.Security.Cryptography; using Renci.SshNet.Common; namespace Renci.SshNet.Security.Cryptography @@ -58,5 +56,3 @@ protected override byte[] HashFinal() } } } - -#endif // FEATURE_HMAC_SHA256 diff --git a/src/Renci.SshNet/Security/Cryptography/HMACSHA384.cs b/src/Renci.SshNet/Security/Cryptography/HMACSHA384.cs index 142e51ed7..f5f0b26c5 100644 --- a/src/Renci.SshNet/Security/Cryptography/HMACSHA384.cs +++ b/src/Renci.SshNet/Security/Cryptography/HMACSHA384.cs @@ -1,6 +1,4 @@ -锘#if FEATURE_HMAC_SHA384 - -using System.Security.Cryptography; +锘縰sing System.Security.Cryptography; using Renci.SshNet.Common; namespace Renci.SshNet.Security.Cryptography @@ -57,5 +55,3 @@ protected override byte[] HashFinal() } } } - -#endif // FEATURE_HMAC_SHA384 diff --git a/src/Renci.SshNet/Security/Cryptography/HMACSHA512.cs b/src/Renci.SshNet/Security/Cryptography/HMACSHA512.cs index a297ed088..72e758155 100644 --- a/src/Renci.SshNet/Security/Cryptography/HMACSHA512.cs +++ b/src/Renci.SshNet/Security/Cryptography/HMACSHA512.cs @@ -1,6 +1,4 @@ -锘#if FEATURE_HMAC_SHA512 - -using System.Security.Cryptography; +锘縰sing System.Security.Cryptography; using Renci.SshNet.Common; namespace Renci.SshNet.Security.Cryptography @@ -57,5 +55,3 @@ protected override byte[] HashFinal() } } } - -#endif // FEATURE_HMAC_SHA512 diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index 0846cb2cd..13764e386 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -16,9 +16,7 @@ using System.Linq; using Renci.SshNet.Abstractions; using Renci.SshNet.Security.Cryptography; -#if FEATURE_TAP using System.Threading.Tasks; -#endif namespace Renci.SshNet { @@ -172,13 +170,11 @@ public class Session : ISession /// private Socket _socket; -#if FEATURE_SOCKET_POLL /// /// Holds an object that is used to ensure only a single thread can read from /// at any given time. /// private readonly object _socketReadLock = new object(); -#endif // FEATURE_SOCKET_POLL /// /// Holds an object that is used to ensure only a single thread can write to @@ -673,7 +669,6 @@ public void Connect() } } -#if FEATURE_TAP /// /// Asynchronously connects to the server. /// @@ -777,7 +772,6 @@ public async Task ConnectAsync(CancellationToken cancellationToken) RegisterMessage("SSH_MSG_CHANNEL_EOF"); RegisterMessage("SSH_MSG_CHANNEL_CLOSE"); } -#endif /// /// Disconnects from the server. @@ -1150,13 +1144,11 @@ private Message ReceiveMessage(Socket socket) byte[] data; uint packetLength; -#if FEATURE_SOCKET_POLL // avoid reading from socket while IsSocketConnected is attempting to determine whether the // socket is still connected by invoking Socket.Poll(...) and subsequently verifying value of // Socket.Available lock (_socketReadLock) { -#endif // FEATURE_SOCKET_POLL // Read first block - which starts with the packet length var firstBlock = new byte[blockSize]; if (TrySocketRead(socket, firstBlock, 0, blockSize) == 0) @@ -1204,9 +1196,7 @@ private Message ReceiveMessage(Socket socket) return null; } } -#if FEATURE_SOCKET_POLL } -#endif // FEATURE_SOCKET_POLL if (_serverCipher != null) { @@ -1767,7 +1757,6 @@ internal static string ToHex(byte[] bytes) #endregion -#if FEATURE_SOCKET_POLL /// /// Gets a value indicating whether the socket is connected. /// @@ -1807,23 +1796,10 @@ internal static string ToHex(byte[] bytes) /// we synchronize reads from the . /// /// -#else - /// - /// Gets a value indicating whether the socket is connected. - /// - /// - /// true if the socket is connected; otherwise, false. - /// - /// - /// We verify whether is true. However, this only returns the state - /// of the socket as of the last I/O operation. - /// -#endif private bool IsSocketConnected() { lock (_socketDisposeLock) { -#if FEATURE_SOCKET_POLL if (!_socket.IsConnected()) { return false; @@ -1834,9 +1810,6 @@ private bool IsSocketConnected() var connectionClosedOrDataAvailable = _socket.Poll(0, SelectMode.SelectRead); return !(connectionClosedOrDataAvailable && _socket.Available == 0); } -#else - return _socket.IsConnected(); -#endif // FEATURE_SOCKET_POLL } } @@ -1915,10 +1888,8 @@ private void MessageListener() break; } -#if FEATURE_SOCKET_POLL || FEATURE_SOCKET_SELECT try { -#if FEATURE_SOCKET_POLL // Block until either data is available or the socket is closed var connectionClosedOrDataAvailable = socket.Poll(-1, SelectMode.SelectRead); if (connectionClosedOrDataAvailable && socket.Available == 0) @@ -1926,43 +1897,6 @@ private void MessageListener() // connection with SSH server was closed or connection was reset break; } -#elif FEATURE_SOCKET_SELECT - var readSockets = new List { socket }; - - // if the socket is already disposed when Select is invoked, then a SocketException - // stating "An operation was attempted on something that is not a socket" is thrown; - // we attempt to avoid this exception by having an IsConnected() that can break the - // message loop - // - // note that there's no guarantee that the socket will not be disposed between the - // IsConnected() check and the Select invocation; we can't take a "dispose" lock - // that includes the Select invocation as we want Dispose() to be able to interrupt - // the Select - - // perform a blocking select to determine whether there's is data available to be - // read; we do not use a blocking read to allow us to use Socket.Poll to determine - // if the connection is still available (in IsSocketConnected) - - Socket.Select(readSockets, null, null, -1); - - // the Select invocation will be interrupted in one of the following conditions: - // * data is available to be read - // => the socket will not be removed from "readSockets" - // * the socket connection is closed during the Select invocation - // => the socket will be removed from "readSockets" - // * the socket is disposed during the Select invocation - // => the socket will not be removed from "readSocket" - // - // since we handle the second and third condition the same way and Socket.Connected - // allows us to check for both conditions, we use that instead of both checking for - // the removal from "readSockets" and the Connection check - if (!socket.IsConnected()) - { - // connection with SSH server was closed or socket was disposed; - // break out of the message loop - break; - } -#endif // FEATURE_SOCKET_SELECT } catch (ObjectDisposedException) { @@ -1972,7 +1906,6 @@ private void MessageListener() // * a SSH_MSG_DISCONNECT received from server break; } -#endif // FEATURE_SOCKET_POLL || FEATURE_SOCKET_SELECT var message = ReceiveMessage(socket); if (message == null) diff --git a/src/Renci.SshNet/Sftp/ISftpSession.cs b/src/Renci.SshNet/Sftp/ISftpSession.cs index 4a3648bd4..8971bd571 100644 --- a/src/Renci.SshNet/Sftp/ISftpSession.cs +++ b/src/Renci.SshNet/Sftp/ISftpSession.cs @@ -2,9 +2,7 @@ using System.Collections.Generic; using System.Threading; using Renci.SshNet.Sftp.Responses; -#if FEATURE_TAP using System.Threading.Tasks; -#endif namespace Renci.SshNet.Sftp { @@ -41,9 +39,7 @@ internal interface ISftpSession : ISubsystemSession /// string GetCanonicalPath(string path); -#if FEATURE_TAP Task GetCanonicalPathAsync(string path, CancellationToken cancellationToken); -#endif /// /// Performs SSH_FXP_FSTAT request. @@ -55,9 +51,7 @@ internal interface ISftpSession : ISubsystemSession /// SftpFileAttributes RequestFStat(byte[] handle, bool nullOnError); -#if FEATURE_TAP Task RequestFStatAsync(byte[] handle, CancellationToken cancellationToken); -#endif /// /// Performs SSH_FXP_STAT request. @@ -135,9 +129,7 @@ internal interface ISftpSession : ISubsystemSession /// File handle. byte[] RequestOpen(string path, Flags flags, bool nullOnError = false); -#if FEATURE_TAP Task RequestOpenAsync(string path, Flags flags, CancellationToken cancellationToken); -#endif /// /// Performs SSH_FXP_OPEN request @@ -173,9 +165,7 @@ internal interface ISftpSession : ISubsystemSession /// File handle. byte[] RequestOpenDir(string path, bool nullOnError = false); -#if FEATURE_TAP Task RequestOpenDirAsync(string path, CancellationToken cancellationToken); -#endif /// /// Performs posix-rename@openssh.com extended request. @@ -220,9 +210,7 @@ internal interface ISftpSession : ISubsystemSession /// is null. byte[] EndRead(SftpReadAsyncResult asyncResult); -#if FEATURE_TAP Task RequestReadAsync(byte[] handle, ulong offset, uint length, CancellationToken cancellationToken); -#endif /// /// Performs SSH_FXP_READDIR request @@ -231,9 +219,7 @@ internal interface ISftpSession : ISubsystemSession /// KeyValuePair[] RequestReadDir(byte[] handle); -#if FEATURE_TAP Task[]> RequestReadDirAsync(byte[] handle, CancellationToken cancellationToken); -#endif /// /// Performs SSH_FXP_REALPATH request. @@ -262,9 +248,7 @@ internal interface ISftpSession : ISubsystemSession /// The path. void RequestRemove(string path); -#if FEATURE_TAP Task RequestRemoveAsync(string path, CancellationToken cancellationToken); -#endif /// /// Performs SSH_FXP_RENAME request. @@ -273,9 +257,7 @@ internal interface ISftpSession : ISubsystemSession /// The new path. void RequestRename(string oldPath, string newPath); -#if FEATURE_TAP Task RequestRenameAsync(string oldPath, string newPath, CancellationToken cancellationToken); -#endif /// /// Performs SSH_FXP_RMDIR request. @@ -298,9 +280,7 @@ internal interface ISftpSession : ISubsystemSession /// SftpFileSytemInformation RequestStatVfs(string path, bool nullOnError = false); -#if FEATURE_TAP Task RequestStatVfsAsync(string path, CancellationToken cancellationToken); -#endif /// /// Performs SSH_FXP_SYMLINK request. @@ -334,9 +314,7 @@ void RequestWrite(byte[] handle, AutoResetEvent wait, Action writeCompleted = null); -#if FEATURE_TAP Task RequestWriteAsync(byte[] handle, ulong serverOffset, byte[] data, int offset, int length, CancellationToken cancellationToken); -#endif /// /// Performs SSH_FXP_CLOSE request. @@ -344,9 +322,7 @@ void RequestWrite(byte[] handle, /// The handle. void RequestClose(byte[] handle); -#if FEATURE_TAP Task RequestCloseAsync(byte[] handle, CancellationToken cancellationToken); -#endif /// /// Performs SSH_FXP_CLOSE request. diff --git a/src/Renci.SshNet/Sftp/SftpFileStream.cs b/src/Renci.SshNet/Sftp/SftpFileStream.cs index b47023687..a266b35b8 100644 --- a/src/Renci.SshNet/Sftp/SftpFileStream.cs +++ b/src/Renci.SshNet/Sftp/SftpFileStream.cs @@ -3,9 +3,7 @@ using System.Threading; using System.Diagnostics.CodeAnalysis; using Renci.SshNet.Common; -#if FEATURE_TAP using System.Threading.Tasks; -#endif namespace Renci.SshNet.Sftp { @@ -293,7 +291,6 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc } } -#if FEATURE_TAP internal static async Task OpenAsync(ISftpSession session, string path, FileMode mode, FileAccess access, int bufferSize, CancellationToken cancellationToken) { if (session == null) @@ -390,7 +387,6 @@ internal static async Task OpenAsync(ISftpSession session, strin return new SftpFileStream(session, path, access, bufferSize, handle, position); } -#endif /// /// Releases unmanaged resources and performs other cleanup operations before the @@ -423,7 +419,6 @@ public override void Flush() } } -#if FEATURE_TAP /// /// Asynchronously clears all buffers for this stream and causes any buffered data to be written to the file. /// @@ -446,7 +441,6 @@ public override Task FlushAsync(CancellationToken cancellationToken) return Task.CompletedTask; } -#endif /// /// Reads a sequence of bytes from the current stream and advances the position within the stream by the @@ -588,7 +582,6 @@ public override int Read(byte[] buffer, int offset, int count) return readLen; } -#if FEATURE_TAP /// /// Asynchronously reads a sequence of bytes from the current stream and advances the position within the stream by the /// number of bytes read. @@ -700,7 +693,6 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, // return the number of bytes that were read to the caller. return readLen; } -#endif /// /// Reads a byte from the stream and advances the position within the stream by one byte, or returns -1 if at the end of the stream. @@ -986,7 +978,7 @@ public override void Write(byte[] buffer, int offset, int count) } } -#if FEATURE_TAP + /// /// Asynchronously writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. /// @@ -1062,7 +1054,6 @@ public override async Task WriteAsync(byte[] buffer, int offset, int count, Canc _bufferPosition = 0; } } -#endif /// /// Writes a byte to the current position in the stream and advances the position within the stream by one byte. @@ -1181,7 +1172,6 @@ private void FlushWriteBuffer() } } -#if FEATURE_TAP private async Task FlushWriteBufferAsync(CancellationToken cancellationToken) { if (_bufferPosition > 0) @@ -1190,7 +1180,6 @@ private async Task FlushWriteBufferAsync(CancellationToken cancellationToken) _bufferPosition = 0; } } -#endif /// /// Setups the read. diff --git a/src/Renci.SshNet/Sftp/SftpSession.cs b/src/Renci.SshNet/Sftp/SftpSession.cs index c33c70e34..dd38bd36e 100644 --- a/src/Renci.SshNet/Sftp/SftpSession.cs +++ b/src/Renci.SshNet/Sftp/SftpSession.cs @@ -6,9 +6,7 @@ using System.Globalization; using Renci.SshNet.Sftp.Responses; using Renci.SshNet.Sftp.Requests; -#if FEATURE_TAP using System.Threading.Tasks; -#endif namespace Renci.SshNet.Sftp { @@ -139,7 +137,6 @@ public string GetCanonicalPath(string path) return string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", canonizedPath, slash, pathParts[pathParts.Length - 1]); } -#if FEATURE_TAP public async Task GetCanonicalPathAsync(string path, CancellationToken cancellationToken) { var fullPath = GetFullRemotePath(path); @@ -185,7 +182,6 @@ public async Task GetCanonicalPathAsync(string path, CancellationToken c slash = "/"; return canonizedPath + slash + pathParts[pathParts.Length - 1]; } -#endif public ISftpFileReader CreateFileReader(byte[] handle, ISftpSession sftpSession, uint chunkSize, int maxPendingReads, long? fileSize) { @@ -436,7 +432,6 @@ public byte[] RequestOpen(string path, Flags flags, bool nullOnError = false) return handle; } -#if FEATURE_TAP public async Task RequestOpenAsync(string path, Flags flags, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -452,7 +447,6 @@ public async Task RequestOpenAsync(string path, Flags flags, Cancellatio return await tcs.Task.ConfigureAwait(false); } } -#endif /// /// Performs SSH_FXP_OPEN request @@ -541,7 +535,6 @@ public void RequestClose(byte[] handle) } } -#if FEATURE_TAP public async Task RequestCloseAsync(byte[] handle, CancellationToken cancellationToken) { TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -566,8 +559,6 @@ public async Task RequestCloseAsync(byte[] handle, CancellationToken cancellatio await tcs.Task.ConfigureAwait(false); } } -#endif - /// /// Performs SSH_FXP_CLOSE request. @@ -732,7 +723,6 @@ public byte[] RequestRead(byte[] handle, ulong offset, uint length) return data; } -#if FEATURE_TAP public async Task RequestReadAsync(byte[] handle, ulong offset, uint length, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -758,7 +748,6 @@ public async Task RequestReadAsync(byte[] handle, ulong offset, uint len return await tcs.Task.ConfigureAwait(false); } } -#endif /// /// Performs SSH_FXP_WRITE request. @@ -804,7 +793,6 @@ public void RequestWrite(byte[] handle, } } -#if FEATURE_TAP public async Task RequestWriteAsync(byte[] handle, ulong serverOffset, byte[] data, int offset, int length, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -829,7 +817,6 @@ public async Task RequestWriteAsync(byte[] handle, ulong serverOffset, byte[] da await tcs.Task.ConfigureAwait(false); } } -#endif /// /// Performs SSH_FXP_LSTAT request. @@ -963,7 +950,6 @@ public SftpFileAttributes RequestFStat(byte[] handle, bool nullOnError) return attributes; } -#if FEATURE_TAP public async Task RequestFStatAsync(byte[] handle, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -979,7 +965,6 @@ public async Task RequestFStatAsync(byte[] handle, Cancellat return await tcs.Task.ConfigureAwait(false); } } -#endif /// /// Performs SSH_FXP_SETSTAT request. @@ -1078,7 +1063,6 @@ public byte[] RequestOpenDir(string path, bool nullOnError = false) return handle; } -#if FEATURE_TAP public async Task RequestOpenDirAsync(string path, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -1094,7 +1078,6 @@ public async Task RequestOpenDirAsync(string path, CancellationToken can return await tcs.Task.ConfigureAwait(false); } } -#endif /// /// Performs SSH_FXP_READDIR request @@ -1137,7 +1120,6 @@ public KeyValuePair[] RequestReadDir(byte[] handle) return result; } -#if FEATURE_TAP public async Task[]> RequestReadDirAsync(byte[] handle, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -1163,8 +1145,6 @@ public async Task[]> RequestReadDirAsyn return await tcs.Task.ConfigureAwait(false); } } -#endif - /// /// Performs SSH_FXP_REMOVE request. @@ -1194,7 +1174,6 @@ public void RequestRemove(string path) } } -#if FEATURE_TAP public async Task RequestRemoveAsync(string path, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -1219,8 +1198,6 @@ public async Task RequestRemoveAsync(string path, CancellationToken cancellation await tcs.Task.ConfigureAwait(false); } } -#endif - /// /// Performs SSH_FXP_MKDIR request. @@ -1319,7 +1296,6 @@ internal KeyValuePair[] RequestRealPath(string path, return result; } -#if FEATURE_TAP internal async Task[]> RequestRealPathAsync(string path, bool nullOnError, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -1345,7 +1321,6 @@ internal async Task[]> RequestRealPathA return await tcs.Task.ConfigureAwait(false); } } -#endif /// /// Performs SSH_FXP_REALPATH request. @@ -1528,8 +1503,6 @@ public void RequestRename(string oldPath, string newPath) } } - -#if FEATURE_TAP public async Task RequestRenameAsync(string oldPath, string newPath, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); @@ -1554,7 +1527,6 @@ public async Task RequestRenameAsync(string oldPath, string newPath, Cancellatio await tcs.Task.ConfigureAwait(false); } } -#endif /// /// Performs SSH_FXP_READLINK request. @@ -1722,8 +1694,6 @@ public SftpFileSytemInformation RequestStatVfs(string path, bool nullOnError = f return information; } - -#if FEATURE_TAP public async Task RequestStatVfsAsync(string path, CancellationToken cancellationToken) { if (ProtocolVersion < 3) @@ -1744,7 +1714,6 @@ public async Task RequestStatVfsAsync(string path, Can return await tcs.Task.ConfigureAwait(false); } } -#endif /// /// Performs fstatvfs@openssh.com extended request. diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index a7ce34538..2705382ad 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -10,9 +10,7 @@ using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Sftp; -#if FEATURE_TAP using System.Threading.Tasks; -#endif namespace Renci.SshNet { @@ -376,7 +374,6 @@ public void DeleteFile(string path) _sftpSession.RequestRemove(fullPath); } -#if FEATURE_TAP /// /// Asynchronously deletes remote file specified by path. /// @@ -401,7 +398,6 @@ public async Task DeleteFileAsync(string path, CancellationToken cancellationTok var fullPath = await _sftpSession.GetCanonicalPathAsync(path, cancellationToken).ConfigureAwait(false); await _sftpSession.RequestRemoveAsync(fullPath, cancellationToken).ConfigureAwait(false); } -#endif /// /// Renames remote file from old path to new path. @@ -418,7 +414,6 @@ public void RenameFile(string oldPath, string newPath) RenameFile(oldPath, newPath, false); } -#if FEATURE_TAP /// /// Asynchronously renames remote file from old path to new path. /// @@ -446,7 +441,6 @@ public async Task RenameFileAsync(string oldPath, string newPath, CancellationTo var newFullPath = await _sftpSession.GetCanonicalPathAsync(newPath, cancellationToken).ConfigureAwait(false); await _sftpSession.RequestRenameAsync(oldFullPath, newFullPath, cancellationToken).ConfigureAwait(false); } -#endif /// /// Renames remote file from old path to new path. @@ -536,8 +530,6 @@ public IEnumerable ListDirectory(string path, Action listCallbac return InternalListDirectory(path, listCallback); } -#if FEATURE_TAP - /// /// Asynchronously retrieves list of files in remote directory. /// @@ -594,8 +586,6 @@ public async Task> ListDirectoryAsync(string path, Cancel return result; } -#endif - /// /// Begins an asynchronous operation of retrieving list of files in remote directory. /// @@ -1129,7 +1119,6 @@ public SftpFileSytemInformation GetStatus(string path) return _sftpSession.RequestStatVfs(fullPath); } -#if FEATURE_TAP /// /// Asynchronously gets status using statvfs@openssh.com request. /// @@ -1154,7 +1143,6 @@ public async Task GetStatusAsync(string path, Cancella var fullPath = await _sftpSession.GetCanonicalPathAsync(path, cancellationToken).ConfigureAwait(false); return await _sftpSession.RequestStatVfsAsync(fullPath, cancellationToken).ConfigureAwait(false); } -#endif #region File Methods @@ -1503,7 +1491,6 @@ public SftpFileStream Open(string path, FileMode mode, FileAccess access) return new SftpFileStream(_sftpSession, path, mode, access, (int) _bufferSize); } -#if FEATURE_TAP /// /// Asynchronously opens a on the specified path, with the specified mode and access. /// @@ -1529,7 +1516,6 @@ public Task OpenAsync(string path, FileMode mode, FileAccess acc return SftpFileStream.OpenAsync(_sftpSession, path, mode, access, (int)_bufferSize, cancellationToken); } -#endif /// /// Opens an existing file for reading. diff --git a/src/Renci.SshNet/Shell.cs b/src/Renci.SshNet/Shell.cs index c508be896..3e68e6b12 100644 --- a/src/Renci.SshNet/Shell.cs +++ b/src/Renci.SshNet/Shell.cs @@ -129,7 +129,6 @@ public void Start() while (_channel.IsOpen) { -#if FEATURE_STREAM_TAP var readTask = _input.ReadAsync(buffer, 0, buffer.Length); var readWaitHandle = ((IAsyncResult) readTask).AsyncWaitHandle; @@ -139,24 +138,7 @@ public void Start() _channel.SendData(buffer, 0, read); continue; } -#elif FEATURE_STREAM_APM - var asyncResult = _input.BeginRead(buffer, 0, buffer.Length, result => - { - // If input stream is closed and disposed already don't finish reading the stream - if (_input == null) - return; - var read = _input.EndRead(result); - _channel.SendData(buffer, 0, read); - }, null); - - WaitHandle.WaitAny(new[] { asyncResult.AsyncWaitHandle, _channelClosedWaitHandle }); - - if (asyncResult.IsCompleted) - continue; -#else - #error Async receive is not implemented. -#endif break; } } From 072ba7e01323659d5ee12a59b6cb4f7cf583d64e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Mon, 22 May 2023 09:47:09 +0200 Subject: [PATCH 19/96] Remove FEATURE_DIRECTORYINFO_ENUMERATEFILES (#1119) * Remove FEATURE_DIRECTORYINFO_ENUMERATEFILES * Add exception documentation --- .../Abstractions/FileSystemAbstraction.cs | 32 ------- src/Renci.SshNet/Renci.SshNet.csproj | 4 +- src/Renci.SshNet/SftpClient.cs | 90 +++++++++++-------- 3 files changed, 54 insertions(+), 72 deletions(-) delete mode 100644 src/Renci.SshNet/Abstractions/FileSystemAbstraction.cs diff --git a/src/Renci.SshNet/Abstractions/FileSystemAbstraction.cs b/src/Renci.SshNet/Abstractions/FileSystemAbstraction.cs deleted file mode 100644 index 1bce391ed..000000000 --- a/src/Renci.SshNet/Abstractions/FileSystemAbstraction.cs +++ /dev/null @@ -1,32 +0,0 @@ -锘縰sing System; -using System.Collections.Generic; -using System.IO; - -namespace Renci.SshNet.Abstractions -{ - internal class FileSystemAbstraction - { - /// - /// Returns an enumerable collection of file information that matches a search pattern. - /// - /// - /// The search string to match against the names of files. - /// - /// An enumerable collection of files that matches . - /// - /// is null. - /// is null. - /// The path represented by does not exist or is not valid. - public static IEnumerable EnumerateFiles(DirectoryInfo directoryInfo, string searchPattern) - { - if (directoryInfo == null) - throw new ArgumentNullException("directoryInfo"); - -#if FEATURE_DIRECTORYINFO_ENUMERATEFILES - return directoryInfo.EnumerateFiles(searchPattern); -#else - return directoryInfo.GetFiles(searchPattern); -#endif - } - } -} diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index 2f39c80ec..21b0128a8 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -5,7 +5,7 @@ false Renci.SshNet ../Renci.SshNet.snk - 6 + 7.3 true net462;netstandard2.0;net6.0;net7.0 @@ -19,6 +19,6 @@ - FEATURE_DIRECTORYINFO_ENUMERATEFILES;FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP + FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 2705382ad..937f4a1a0 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -1996,6 +1996,7 @@ public void SetAttributes(string path, SftpFileAttributes fileAttributes) /// is null. /// is null or contains only whitespace. /// was not found on the remote host. + /// If a problem occurs while copying the file public IEnumerable SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern) { if (sourcePath == null) @@ -2019,6 +2020,7 @@ public IEnumerable SynchronizeDirectories(string sourcePath, string de /// /// is null. /// is null or contains only whitespace. + /// If a problem occurs while copying the file public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback asyncCallback, object state) { if (sourcePath == null) @@ -2074,60 +2076,72 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, var sourceDirectory = new DirectoryInfo(sourcePath); - var sourceFiles = FileSystemAbstraction.EnumerateFiles(sourceDirectory, searchPattern).ToList(); - if (sourceFiles.Count == 0) - return uploadedFiles; + using (var sourceFiles = sourceDirectory.EnumerateFiles(searchPattern).GetEnumerator()) + { + if (!sourceFiles.MoveNext()) + { + return uploadedFiles; + } - #region Existing Files at The Destination + #region Existing Files at The Destination - var destFiles = InternalListDirectory(destinationPath, null); - var destDict = new Dictionary(); - foreach (var destFile in destFiles) - { - if (destFile.IsDirectory) - continue; - destDict.Add(destFile.Name, destFile); - } + var destFiles = InternalListDirectory(destinationPath, null); + var destDict = new Dictionary(); + foreach (var destFile in destFiles) + { + if (destFile.IsDirectory) + { + continue; + } - #endregion + destDict.Add(destFile.Name, destFile); + } - #region Upload the difference + #endregion - const Flags uploadFlag = Flags.Write | Flags.Truncate | Flags.CreateNewOrOpen; - foreach (var localFile in sourceFiles) - { - var isDifferent = !destDict.ContainsKey(localFile.Name); + #region Upload the difference - if (!isDifferent) + const Flags uploadFlag = Flags.Write | Flags.Truncate | Flags.CreateNewOrOpen; + do { - var temp = destDict[localFile.Name]; - // TODO: Use md5 to detect a difference - //ltang: File exists at the destination => Using filesize to detect the difference - isDifferent = localFile.Length != temp.Length; - } + var localFile = sourceFiles.Current; + if (localFile == null) + { + continue; + } - if (isDifferent) - { - var remoteFileName = string.Format(CultureInfo.InvariantCulture, @"{0}/{1}", destinationPath, localFile.Name); - try + var isDifferent = true; + if (destDict.TryGetValue(localFile.Name, out var remoteFile)) { - using (var file = File.OpenRead(localFile.FullName)) + // TODO: Use md5 to detect a difference + //ltang: File exists at the destination => Using filesize to detect the difference + isDifferent = localFile.Length != remoteFile.Length; + } + + if (isDifferent) + { + var remoteFileName = string.Format(CultureInfo.InvariantCulture, @"{0}/{1}", destinationPath, localFile.Name); + try { - InternalUploadFile(file, remoteFileName, uploadFlag, null, null); - } + using (var file = File.OpenRead(localFile.FullName)) + { + InternalUploadFile(file, remoteFileName, uploadFlag, null, null); + } - uploadedFiles.Add(localFile); + uploadedFiles.Add(localFile); - if (asynchResult != null) + if (asynchResult != null) + { + asynchResult.Update(uploadedFiles.Count); + } + } + catch (Exception ex) { - asynchResult.Update(uploadedFiles.Count); + throw new SshException($"Failed to upload {localFile.FullName} to {remoteFileName}", ex); } } - catch (Exception ex) - { - throw new Exception(string.Format("Failed to upload {0} to {1}", localFile.FullName, remoteFileName), ex); - } } + while (sourceFiles.MoveNext()); } #endregion From 3ecbd1071d653bbf04254c08d14d7ce75d60688b Mon Sep 17 00:00:00 2001 From: Gert Driesen Date: Wed, 24 May 2023 20:37:46 +0200 Subject: [PATCH 20/96] Fix some (lots of) issues reported by analyzers. (#1125) Fix some (lots of) issues reported by analyzers. --- .editorconfig_soon | 1235 +++++++++++++++++ Directory.Build.props | 48 + README.md | 0 .../Classes/Common/ObjectIdentifierTest.cs | 39 +- ...ectionClosedByServer_NoDataSentByServer.cs | 12 +- .../Classes/MessageEventArgsTest.cs | 1 - .../Classes/Security/Cryptography/HMacTest.cs | 1 - .../Sftp/SftpStatVfsResponseBuilder.cs | 22 +- .../Common/AsyncSocketListener.cs | 2 +- .../Renci.SshNet.Tests.csproj | 15 +- src/Renci.SshNet.sln | 24 +- src/Renci.SshNet/.editorconfig | 25 + .../Abstractions/CryptoAbstraction.cs | 2 +- .../Abstractions/SocketAbstraction.cs | 43 +- .../Abstractions/SocketExtensions.cs | 40 +- .../Abstractions/ThreadAbstraction.cs | 12 +- src/Renci.SshNet/AuthenticationMethod.cs | 11 +- src/Renci.SshNet/BaseClient.cs | 94 +- src/Renci.SshNet/Channels/Channel.cs | 147 +- .../Channels/ChannelDirectTcpip.cs | 38 +- .../Channels/ChannelForwardedTcpip.cs | 6 + src/Renci.SshNet/Channels/ChannelSession.cs | 60 +- src/Renci.SshNet/Channels/ClientChannel.cs | 17 +- src/Renci.SshNet/Channels/ServerChannel.cs | 14 +- src/Renci.SshNet/CipherInfo.cs | 2 +- src/Renci.SshNet/ClientAuthentication.cs | 29 +- src/Renci.SshNet/CommandAsyncResult.cs | 26 +- src/Renci.SshNet/Common/AsyncResult.cs | 98 +- .../Common/AuthenticationBannerEventArgs.cs | 2 +- .../Common/AuthenticationEventArgs.cs | 10 +- .../AuthenticationPasswordChangeEventArgs.cs | 18 +- .../Common/AuthenticationPrompt.cs | 36 +- .../Common/AuthenticationPromptEventArgs.cs | 32 +- src/Renci.SshNet/Common/BigInteger.cs | 1102 +++++++++++---- .../Common/ChannelDataEventArgs.cs | 12 +- src/Renci.SshNet/Common/ChannelEventArgs.cs | 13 +- .../Common/ChannelExtendedDataEventArgs.cs | 10 +- .../Common/ChannelOpenConfirmedEventArgs.cs | 6 +- .../Common/ChannelOpenFailedEventArgs.cs | 32 +- .../Common/ChannelRequestEventArgs.cs | 16 +- src/Renci.SshNet/Common/DerData.cs | 85 +- src/Renci.SshNet/Common/ExceptionEventArgs.cs | 13 +- src/Renci.SshNet/Common/Extensions.cs | 86 +- src/Renci.SshNet/Common/HostKeyEventArgs.cs | 5 +- .../Common/NetConfServerException.cs | 4 +- src/Renci.SshNet/Common/ObjectIdentifier.cs | 16 +- src/Renci.SshNet/Common/PacketDump.cs | 40 +- src/Renci.SshNet/Common/PipeStream.cs | 206 +-- .../Common/PortForwardEventArgs.cs | 30 +- src/Renci.SshNet/Common/PosixPath.cs | 58 +- src/Renci.SshNet/Common/ProxyException.cs | 10 +- .../Common/ScpDownloadEventArgs.cs | 30 +- src/Renci.SshNet/Common/ScpException.cs | 4 +- src/Renci.SshNet/Common/ScpUploadEventArgs.cs | 30 +- src/Renci.SshNet/Common/SemaphoreLight.cs | 56 +- .../Common/SftpPathNotFoundException.cs | 4 +- .../Common/SftpPermissionDeniedException.cs | 4 +- src/Renci.SshNet/Common/ShellDataEventArgs.cs | 22 +- .../Common/SshAuthenticationException.cs | 6 +- src/Renci.SshNet/Common/SshData.cs | 60 +- src/Renci.SshNet/Common/SshDataStream.cs | 60 +- .../Common/SshOperationTimeoutException.cs | 4 +- .../SshPassPhraseNullOrEmptyException.cs | 8 +- src/Renci.SshNet/Common/TerminalModes.cs | 26 +- src/Renci.SshNet/Compression/Compressor.cs | 23 +- src/Renci.SshNet/Connection/ConnectorBase.cs | 18 +- .../Connection/DirectConnector.cs | 3 +- src/Renci.SshNet/Connection/HttpConnector.cs | 38 +- .../Connection/ProtocolVersionExchange.cs | 129 +- src/Renci.SshNet/Connection/ProxyConnector.cs | 8 +- .../Connection/Socks4Connector.cs | 18 +- .../Connection/Socks5Connector.cs | 48 +- .../Connection/SshIdentification.cs | 33 +- src/Renci.SshNet/ConnectionInfo.cs | 194 +-- src/Renci.SshNet/ExpectAction.cs | 18 +- src/Renci.SshNet/ExpectAsyncResult.cs | 9 +- src/Renci.SshNet/ForwardedPort.cs | 26 +- src/Renci.SshNet/ForwardedPortDynamic.NET.cs | 32 +- src/Renci.SshNet/ForwardedPortDynamic.cs | 49 +- src/Renci.SshNet/ForwardedPortLocal.NET.cs | 23 +- src/Renci.SshNet/ForwardedPortLocal.cs | 53 +- src/Renci.SshNet/ForwardedPortRemote.cs | 72 +- src/Renci.SshNet/ForwardedPortStatus.cs | 24 +- src/Renci.SshNet/IBaseClient.cs | 7 +- src/Renci.SshNet/IConnectionInfo.cs | 7 +- src/Renci.SshNet/IRemotePathTransformation.cs | 2 - src/Renci.SshNet/IServiceFactory.cs | 4 +- src/Renci.SshNet/ISession.cs | 3 +- src/Renci.SshNet/ISftpClient.cs | 9 +- ...KeyboardInteractiveAuthenticationMethod.cs | 48 +- .../KeyboardInteractiveConnectionInfo.cs | 37 +- src/Renci.SshNet/MessageEventArgs.cs | 8 +- .../Authentication/RequestMessageHost.cs | 20 +- .../Messages/Connection/ChannelDataMessage.cs | 16 +- .../Messages/Connection/ChannelMessage.cs | 8 +- .../ChannelOpen/ChannelOpenMessage.cs | 6 +- .../ChannelOpen/DirectTcpipChannelInfo.cs | 2 +- .../ChannelOpen/ForwardedTcpipChannelInfo.cs | 2 +- .../ChannelOpen/SessionChannelOpenInfo.cs | 2 +- .../ChannelOpen/X11ChannelOpenInfo.cs | 2 +- .../ChannelRequest/BreakRequestInfo.cs | 2 +- .../ChannelRequest/ExecRequestInfo.cs | 13 +- .../ChannelRequest/PseudoTerminalInfo.cs | 13 +- .../ChannelRequest/ShellRequestInfo.cs | 2 +- .../ChannelRequest/SignalRequestInfo.cs | 2 +- .../ChannelRequest/SubsystemRequestInfo.cs | 2 +- .../ChannelRequest/WindowChangeRequestInfo.cs | 2 +- .../X11ForwardingRequestInfo.cs | 8 +- .../ChannelRequest/XonXoffRequestInfo.cs | 4 +- .../Connection/ChannelWindowAdjustMessage.cs | 3 +- .../Connection/RequestFailureMessage.cs | 3 +- .../Connection/RequestSuccessMessage.cs | 9 +- .../TcpIpForwardGlobalRequestMessage.cs | 2 +- src/Renci.SshNet/Messages/Message.cs | 30 +- .../Messages/Transport/IgnoreMessage.cs | 4 +- .../KeyExchangeDhGroupExchangeInit.cs | 2 +- .../KeyExchangeDhGroupExchangeReply.cs | 12 +- .../KeyExchangeDhGroupExchangeRequest.cs | 8 +- .../Transport/KeyExchangeDhInitMessage.cs | 2 +- .../Transport/KeyExchangeEcdhInitMessage.cs | 4 +- src/Renci.SshNet/NetConfClient.cs | 52 +- src/Renci.SshNet/Netconf/NetConfSession.cs | 63 +- src/Renci.SshNet/NoneAuthenticationMethod.cs | 38 +- .../PasswordAuthenticationMethod.cs | 60 +- src/Renci.SshNet/PasswordConnectionInfo.cs | 33 +- .../PrivateKeyAuthenticationMethod.cs | 55 +- src/Renci.SshNet/PrivateKeyConnectionInfo.cs | 42 +- src/Renci.SshNet/PrivateKeyFile.cs | 169 ++- src/Renci.SshNet/Properties/AssemblyInfo.cs | 2 +- .../RemotePathDoubleQuoteTransformation.cs | 15 +- .../RemotePathNoneTransformation.cs | 2 +- .../RemotePathShellQuoteTransformation.cs | 56 +- src/Renci.SshNet/Renci.SshNet.csproj | 5 - src/Renci.SshNet/ScpClient.NET.cs | 102 +- src/Renci.SshNet/ScpClient.cs | 73 +- .../Security/BouncyCastle/.editorconfig | 7 + .../crypto/prng/IRandomGenerator.cs | 2 +- .../math/ec/endo/GlvEndomorphism.cs | 2 +- .../Security/Chaos.NaCl/.editorconfig | 7 + .../Security/Cryptography/.editorconfig | 12 + .../Security/Cryptography/BlockCipher.cs | 1 + .../Cryptography/CipherDigitalSignature.cs | 12 +- .../Cryptography/Ciphers/AesCipher.cs | 34 +- .../Cryptography/Ciphers/Arc4Cipher.cs | 7 +- .../Cryptography/Ciphers/BlowfishCipher.cs | 3 + .../Cryptography/Ciphers/DesCipher.cs | 58 +- .../Ciphers/Modes/CbcCipherMode.cs | 20 +- .../Ciphers/Modes/CfbCipherMode.cs | 20 +- .../Ciphers/Modes/CtrCipherMode.cs | 24 +- .../Ciphers/Modes/OfbCipherMode.cs | 20 +- .../Ciphers/Paddings/PKCS5Padding.cs | 4 +- .../Ciphers/Paddings/PKCS7Padding.cs | 2 + .../Cryptography/Ciphers/RsaCipher.cs | 26 +- .../Cryptography/Ciphers/SerpentCipher.cs | 959 +++++++++---- .../Cryptography/Ciphers/TripleDesCipher.cs | 12 +- .../Cryptography/Ciphers/TwofishCipher.cs | 35 +- .../Cryptography/DsaDigitalSignature.cs | 71 +- .../Security/Cryptography/DsaKey.cs | 30 +- .../Cryptography/ED25519DigitalSignature.cs | 22 +- .../Security/Cryptography/ED25519Key.cs | 32 +- .../Cryptography/EcdsaDigitalSignature.cs | 32 +- .../Security/Cryptography/EcdsaKey.cs | 120 +- .../Security/Cryptography/HMACSHA1.cs | 5 +- src/Renci.SshNet/Security/Cryptography/Key.cs | 13 +- .../Security/Cryptography/RsaKey.cs | 3 +- .../Security/Cryptography/SymmetricCipher.cs | 4 +- src/Renci.SshNet/Security/IKeyExchange.cs | 1 + src/Renci.SshNet/Security/KeyExchange.cs | 100 +- .../Security/KeyExchangeDiffieHellman.cs | 20 +- .../KeyExchangeDiffieHellmanGroup14Sha1.cs | 6 +- .../KeyExchangeDiffieHellmanGroup14Sha256.cs | 6 +- .../KeyExchangeDiffieHellmanGroup16Sha512.cs | 68 +- .../KeyExchangeDiffieHellmanGroup1Sha1.cs | 2 +- ...yExchangeDiffieHellmanGroupExchangeSha1.cs | 4 +- ...xchangeDiffieHellmanGroupExchangeSha256.cs | 4 +- ...changeDiffieHellmanGroupExchangeShaBase.cs | 6 +- .../KeyExchangeDiffieHellmanGroupSha1.cs | 2 +- .../KeyExchangeDiffieHellmanGroupSha256.cs | 4 +- .../KeyExchangeDiffieHellmanGroupSha512.cs | 4 +- .../KeyExchangeDiffieHellmanGroupShaBase.cs | 52 +- src/Renci.SshNet/Security/KeyExchangeEC.cs | 8 +- .../Security/KeyExchangeECCurve25519.cs | 10 +- src/Renci.SshNet/Security/KeyExchangeECDH.cs | 30 +- .../Security/KeyExchangeECDH256.cs | 6 +- .../Security/KeyExchangeECDH384.cs | 4 +- .../Security/KeyExchangeECDH521.cs | 6 +- src/Renci.SshNet/Security/KeyExchangeHash.cs | 7 +- src/Renci.SshNet/Security/KeyHostAlgorithm.cs | 13 +- src/Renci.SshNet/ServiceFactory.cs | 31 +- src/Renci.SshNet/Session.cs | 456 +++--- src/Renci.SshNet/Sftp/ISftpFile.cs | 37 +- src/Renci.SshNet/Sftp/ISftpSession.cs | 15 +- .../ExtendedRequests/FStatVfsRequest.cs | 3 +- .../ExtendedRequests/HardLinkRequest.cs | 4 +- .../ExtendedRequests/PosixRenameRequest.cs | 10 +- .../ExtendedRequests/StatVfsRequest.cs | 10 +- .../Sftp/Requests/SftpBlockRequest.cs | 7 +- .../Sftp/Requests/SftpCloseRequest.cs | 2 +- .../Sftp/Requests/SftpFSetStatRequest.cs | 9 +- .../Sftp/Requests/SftpFStatRequest.cs | 6 +- .../Sftp/Requests/SftpInitRequest.cs | 2 +- .../Sftp/Requests/SftpLStatRequest.cs | 7 +- .../Sftp/Requests/SftpLinkRequest.cs | 9 +- .../Sftp/Requests/SftpMkDirRequest.cs | 3 +- .../Sftp/Requests/SftpOpenDirRequest.cs | 8 +- .../Sftp/Requests/SftpOpenRequest.cs | 11 +- .../Sftp/Requests/SftpReadDirRequest.cs | 6 +- .../Sftp/Requests/SftpReadLinkRequest.cs | 10 +- .../Sftp/Requests/SftpReadRequest.cs | 10 +- .../Sftp/Requests/SftpRealPathRequest.cs | 15 +- .../Sftp/Requests/SftpRemoveRequest.cs | 2 +- .../Sftp/Requests/SftpRenameRequest.cs | 2 +- src/Renci.SshNet/Sftp/Requests/SftpRequest.cs | 10 +- .../Sftp/Requests/SftpRmDirRequest.cs | 2 +- .../Sftp/Requests/SftpSetStatRequest.cs | 2 +- .../Sftp/Requests/SftpStatRequest.cs | 11 +- .../Sftp/Requests/SftpSymLinkRequest.cs | 2 +- .../Sftp/Requests/SftpUnblockRequest.cs | 6 +- .../Sftp/Requests/SftpWriteRequest.cs | 4 +- .../ExtendedReplies/StatVfsReplyInfo.cs | 4 +- .../Sftp/Responses/SftpAttrsResponse.cs | 3 +- .../Sftp/Responses/SftpDataResponse.cs | 2 +- .../Sftp/Responses/SftpHandleResponse.cs | 2 +- .../Sftp/Responses/SftpNameResponse.cs | 12 +- .../Sftp/Responses/SftpStatusResponse.cs | 2 +- .../Sftp/Responses/SftpVersionResponse.cs | 6 +- src/Renci.SshNet/Sftp/SFtpStatAsyncResult.cs | 10 +- src/Renci.SshNet/Sftp/SftpCloseAsyncResult.cs | 10 +- src/Renci.SshNet/Sftp/SftpFile.cs | 83 +- src/Renci.SshNet/Sftp/SftpFileAttributes.cs | 252 ++-- src/Renci.SshNet/Sftp/SftpFileReader.cs | 121 +- src/Renci.SshNet/Sftp/SftpFileStream.cs | 272 ++-- .../Sftp/SftpListDirectoryAsyncResult.cs | 6 +- src/Renci.SshNet/Sftp/SftpMessage.cs | 7 +- src/Renci.SshNet/Sftp/SftpMessageTypes.cs | 91 +- src/Renci.SshNet/Sftp/SftpOpenAsyncResult.cs | 10 +- src/Renci.SshNet/Sftp/SftpReadAsyncResult.cs | 10 +- .../Sftp/SftpRealPathAsyncResult.cs | 10 +- src/Renci.SshNet/Sftp/SftpResponseFactory.cs | 3 +- src/Renci.SshNet/Sftp/SftpSession.cs | 1141 ++++++++------- .../SftpSynchronizeDirectoriesAsyncResult.cs | 7 +- .../Sftp/SftpUploadAsyncResult.cs | 5 +- src/Renci.SshNet/Shell.cs | 88 +- src/Renci.SshNet/ShellStream.cs | 160 ++- src/Renci.SshNet/SshClient.cs | 50 +- src/Renci.SshNet/SshCommand.cs | 145 +- src/Renci.SshNet/SshMessageFactory.cs | 107 +- src/Renci.SshNet/SubsystemSession.cs | 72 +- stylecop.json | 25 + test/.editorconfig | 111 ++ test/Directory.Build.props | 16 + 251 files changed, 7541 insertions(+), 4090 deletions(-) create mode 100644 .editorconfig_soon create mode 100644 Directory.Build.props mode change 100755 => 100644 README.md create mode 100644 src/Renci.SshNet/.editorconfig create mode 100644 src/Renci.SshNet/Security/BouncyCastle/.editorconfig create mode 100644 src/Renci.SshNet/Security/Chaos.NaCl/.editorconfig create mode 100644 src/Renci.SshNet/Security/Cryptography/.editorconfig create mode 100644 stylecop.json create mode 100644 test/.editorconfig create mode 100644 test/Directory.Build.props diff --git a/.editorconfig_soon b/.editorconfig_soon new file mode 100644 index 000000000..d0edd58e3 --- /dev/null +++ b/.editorconfig_soon @@ -0,0 +1,1235 @@ +锘// Avoid looking for .editorconfig files in parent directories +root=true + +[*] + +insert_final_newline = true +indent_style = space +indent_size = 4 +tab_width = 4 +end_of_line = crlf + +[*.cs] + +#### Sonar rules #### + +# S101: Types should be named in PascalCase +# https://rules.sonarsource.com/csharp/RSPEC-101 +# +# TODO: Remove this when code has been updated! +dotnet_diagnostic.S101.severity = none + +# S112: General exceptions should never be thrown +# https://rules.sonarsource.com/csharp/RSPEC-112 +# +# This is a duplicate of CA2201 and MA0012. +dotnet_diagnostic.S112.severity = none + +# S907: Remove use of 'goto' +# https://rules.sonarsource.com/csharp/RSPEC-907 +# +# Limited use of 'goto' is accepted when performance is critical. +dotnet_diagnostic.S907.severity = none + +# S1066: Collapsible "if" statements should be merged +# https://rules.sonarsource.com/csharp/RSPEC-1066 +# +dotnet_diagnostic.S1066.severity = none + +# S1075: URIs should not be hardcoded +# https://rules.sonarsource.com/csharp/RSPEC-1075 +# +# The rule reports false positives for XML namespaces. +dotnet_diagnostic.S1075.severity = none + +# S1104: Fields should not have public accessibility +# https://rules.sonarsource.com/csharp/RSPEC-1104 +# +# This is a duplicate of SA1401 and CA1051. +dotnet_diagnostic.S1104.severity = none + +# S1125: Boolean literals should not be redundant +# https://rules.sonarsource.com/csharp/RSPEC-1125 +# +# This is a duplicate of MA0073. +dotnet_diagnostic.S1125.severity = none + +# S1135: Track uses of "TODO" tags +# +# This is a duplicate of MA0026. +dotnet_diagnostic.S1135.severity = none + +# S1168: Empty arrays and collections should be returned instead of null +# https://rules.sonarsource.com/csharp/RSPEC-1168 +# +# We sometimes return null to avoid allocating an empty List. +dotnet_diagnostic.S1168.severity = none + +# S1172: Unused method parameters should be removed +# https://rules.sonarsource.com/csharp/RSPEC-1172 +# +# This is a duplicate of IDE0060. +dotnet_diagnostic.S1172.severity = none + +# S1481: Unused local variables should be removed +# https://rules.sonarsource.com/csharp/RSPEC-1481 +# +# This is a duplicate of IDE0059. +dotnet_diagnostic.S1481.severity = none + +# S2259: Null pointers should not be dereferenced +# https://rules.sonarsource.com/csharp/RSPEC-2259 +# +# The analysis is not precise enough, leading to false positives. +dotnet_diagnostic.S2259.severity = none + +# S2445: Blocks should be synchronized on read-only fields +# https://rules.sonarsource.com/csharp/RSPEC-2445 +# +# This is a (partial) duplicate of MA0064. +dotnet_diagnostic.S2445.severity = none + +# S2551: Shared resources should not be used for locking +# https://rules.sonarsource.com/csharp/RSPEC-2551 +# +# This is a duplicate of CA2002, and partial duplicate of MA0064. +dotnet_diagnostic.S2551.severity = none + +# S2583: Conditionally executed code should be reachable +# https://rules.sonarsource.com/csharp/RSPEC-2583 +# +# This rule produces false errors in, for example, for loops. +#dotnet_diagnostic.S2583.severity = none + +# S2699: Tests should include assertions +# https://rules.sonarsource.com/csharp/RSPEC-2699 +# +# Sometimes you want a test in which you invoke a method and just want to verify that it does not throw. +# For example: +# [TestMethod] +# public void InvokeDisposeWithoutNotifyObjectShouldNotThrow() +# { +# _timer.Dispose(); +# } +dotnet_diagnostic.S2699.severity = none + +# S2933: Fields that are only assigned in the constructor should be "readonly" +# https://rules.sonarsource.com/csharp/RSPEC-2933 +# +# This is a duplicate of IDE0044, but IDE0044 is not reported when targeting .NET Framework 4.8. +dotnet_diagnostic.S2933.severity = none + +# S2971: "IEnumerable" LINQs should be simplified +# https://rules.sonarsource.com/csharp/RSPEC-2971 +# +# This is a duplicate of MA0020. +dotnet_diagnostic.S2971.severity = none + +# S3218: Inner class members should not shadow outer class "static" or type members +# https://rules.sonarsource.com/csharp/RSPEC-3218 +# +# This is rather harmless. +dotnet_diagnostic.S3218.severity = none + +# S3267: Loops should be simplified with "LINQ" expressions +# https://rules.sonarsource.com/csharp/RSPEC-3267 +# +# LINQ is the root of all evil :p +dotnet_diagnostic.S3267.severity = none + +# S3376: Attribute, EventArgs, and Exception type names should end with the type being extended +# https://rules.sonarsource.com/csharp/RSPEC-3376 +# +# This is a partial duplicate of MA0058. If we enable the Sonar in all repositories, we should +# consider enabling S3376 in favor of MA0058. +dotnet_diagnostic.S3376.severity = none + +# S3871: Exception types should be "public" +# https://rules.sonarsource.com/csharp/RSPEC-3871 +# +# This is a duplicate of CA1064. +dotnet_diagnostic.S3871.severity = none + +# S3925: "ISerializable" should be implemented correctly +# https://rules.sonarsource.com/csharp/RSPEC-3925 +# +# This is a duplicate of CA2229. +dotnet_diagnostic.S3925.severity = none + +# S3928: Parameter names used into ArgumentException constructors should match an existing one +# https://rules.sonarsource.com/csharp/RSPEC-3928 +# +# This is a duplicate of MA0015. +dotnet_diagnostic.S3928.severity = none + +# S3998: Threads should not lock on objects with weak identity +# https://rules.sonarsource.com/csharp/RSPEC-3998 +# +# This is a duplicate of CA2002, and partial duplicate of MA0064. +dotnet_diagnostic.S3998.severity = none + +# S4456: Parameter validation in yielding methods should be wrapped +# https://rules.sonarsource.com/csharp/RSPEC-4456 +# +# This is a duplicate of MA0050. +dotnet_diagnostic.S4456.severity = none + +# S4487: Unread "private" fields should be removed +# https://rules.sonarsource.com/csharp/RSPEC-4487 +# +# This is a duplicate of IDE0052. +dotnet_diagnostic.S4487.severity = none + +# S4581: "new Guid()" should not be used +# https://rules.sonarsource.com/csharp/RSPEC-4581 +# +# This is a partial duplicate of MA0067, and we do not want to report the use of 'default' for a Guid as error. +dotnet_diagnostic.S4581.severity = none + +#### StyleCop rules #### + +# SA1003: Symbols must be spaced correctly +# +# When enabled, a diagnostic is produced when there's a space after a cast. +# For example: +# var x = (int) z; +dotnet_diagnostic.SA1003.severity = none + +# SA1008: Opening parenthesis should not be preceded by a space +# +# When enabled, a diagnostic is produce when a cast precedes braces. +# For example: +# (long) (a * b) +dotnet_diagnostic.SA1008.severity = none + +# SA1009: Closing parenthesis should not be followed by a space +# +# When enabled, a diagnostic is produced when there's a space after a cast. +# For example: +# var x = (int) z; +dotnet_diagnostic.SA1009.severity = none + +# SA1101: Prefix local calls with this +dotnet_diagnostic.SA1101.severity = none + +# SA1116: Split parameters must start on line after declaration +# +# When enabled, a diagnostic is produced when the first parameter is on the same line as the method or constructor. +# For example: +# arrayBuilder.Add(new StatisticsCallInfo(callsByType.Key, +# callsForType.Count); +dotnet_diagnostic.SA1116.severity = none + +# SA1200: Using directives must be placed correctly +# +# This is already verified by the .NET compiler platform analyzers (csharp_using_directive_placement option and IDE0065 rule). +dotnet_diagnostic.SA1200.severity = none + +# SA1201: Elements must appear in the correct order +dotnet_diagnostic.SA1201.severity = none + +# SA1206: Modifiers are not ordered +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1206.md +# +# This is a duplicate of IDE0036, except that it cannot be configured and expects the required modifier to be before the +# accessibility modifier. +dotnet_diagnostic.SA1206.severity = none + +# SA1309: Field names must not begin with underscore +dotnet_diagnostic.SA1309.severity = none + +# SA1405: Debug.Assert should provide message text +# +# To be discussed if we want to enable this. +dotnet_diagnostic.SA1405.severity = none + +# SA1413: Use trailing comma in multi-line initializers +dotnet_diagnostic.SA1413.severity = none + +# SA1503: Braces should not be omitted +# +# This is a duplicate of IDE0011. +dotnet_diagnostic.SA1503.severity = none + +# SA1516: Elements must be separated by blank line +# +# When enabled, a diagnostic is produced for properties with both a get and set accessor. +# For example: +# public bool EnableStatistics +# { +# get +# { +# return _enableStatistics; +# } +# set +# { +# _enableStatistics = value; +# } +# } +dotnet_diagnostic.SA1516.severity = none + +# SA1520: Use braces consistently +# +# Since we always require braces (configured via csharp_prefer_braces and reported as IDE0011), it does not make sense to check if braces +# are used consistently. +dotnet_diagnostic.SA1520.severity = none + +# SA1633: File must have header +# +# We do not use file headers. +dotnet_diagnostic.SA1633.severity = none + +# SA1648: must be used with inheriting class +# +# This rule is disabled by default, hence we need to explicitly enable it. +dotnet_diagnostic.SA1648.severity = error + +# SX1101: Do not prefix local members with 'this.' +# +# This rule is disabled by default, hence we need to explicitly enable it. +dotnet_diagnostic.SX1101.severity = error + +# SX1309: Field names must begin with underscore +# +# This rule is disabled by default, hence we need to explicitly enable it. +dotnet_diagnostic.SX1309.severity = error + +# SX1309S: Static field names must begin with underscore +# +# This rule is disabled by default, hence we need to explicitly enable it. +dotnet_diagnostic.SX1309S.severity = error + +#### Meziantou.Analyzer rules #### + +# MA0002: Use an overload that has a IEqualityComparer or IComparer parameter +# +# In .NET (Core) there have been quite some optimizations for EqualityComparer.Default (eg. https://github.com/dotnet/coreclr/pull/14125) +# and Comparer.Default (eg. https://github.com/dotnet/runtime/pull/48160). +# +# We'll have to verify impact on performance before we decide to use specific comparers (eg. StringComparer.InvariantCultureIgnoreCase). +dotnet_diagnostic.MA0002.severity = none + +# MA0006: Use string.Equals instead of Equals operator +# +# We almost always want ordinal comparison, and using the explicit overload adds a little overhead +# and is more chatty. +dotnet_diagnostic.MA0006.severity = none + +# MA0007: Add a comma after the last value +# +# We do not add a comma after the last value in multi-line initializers. +# For example: +# public enum Sex +# { +# Male = 1, +# Female = 2 // No comma here +# } +# +# Note: +# This is a duplicate of SA1413. +dotnet_diagnostic.MA0007.severity = none + +# MA0009: Add regex evaluation timeout +# +# We do not see a need guard our regex's against a DOS attack. +dotnet_diagnostic.MA0009.severity = none + +# MA0011: IFormatProvider is missing +# +# Also report diagnostic in ToString(...) methods +MA0011.exclude_tostring_methods = false + +# MA0012: Do not raise reserved exception type +# +# This is a duplicate of CA2201. +dotnet_diagnostic.MA0012.severity = none + +# MA0014: Do not raise System.ApplicationException type +# +# This is a duplicate of CA2201. +dotnet_diagnostic.MA0014.severity = none + +# MA0016: Prefer returning collection abstraction instead of implementation +# +# This is a duplicate of CA1002. +dotnet_diagnostic.MA0016.severity = none + +# MA0018: Do not declare static members on generic types +# +# This is a duplicate of CA1000. +dotnet_diagnostic.MA0018.severity = none + +# MA0021: Use StringComparer.GetHashCode instead of string.GetHashCode +# +# No strong need for this, and may negatively affect performance. +dotnet_diagnostic.MA0021.severity = none + +# MA0031: Optimize Enumerable.Count() usage +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0031.md +# +# The proposed code is less readable. +# +# For example: +# +# the following code fragment: +# enumerable.Count() > 10; +# +# would become: +# enumerable.Skip(10).Any(); +dotnet_diagnostic.MA0031.severity = none + +# MA0036: Make class static +# +# This is a partial duplicate of CA1052. +dotnet_diagnostic.MA0036.severity = none + +# MA0038: Make method static +# +# This is a partial duplicate of, and deprecated in favor of, CA1822. +dotnet_diagnostic.MA0038.severity = none + +# MA0041: Make property static +# +# This is a partial duplicate of, and deprecated in favor of, CA1822. +dotnet_diagnostic.MA0041.severity = none + +# MA0048: File name must match type name +# +# This is a duplicate of SA1649. +dotnet_diagnostic.MA0048.severity = none + +# MA0049: Type name should not match containing namespace +# +# This is a duplicate of CA1724 +dotnet_diagnostic.MA0049.severity = none + +# MA0051: Method is too long +# +# We do not want to limit the number of lines or statements per method. +dotnet_diagnostic.MA0051.severity = none + +# MA0053: Make class sealed +# +# Also report diagnostic for public types. +MA0053.public_class_should_be_sealed = true + +# MA0053: Make class sealed +# +# Also report diagnostic for types that derive from System.Exception. +MA0053.exceptions_should_be_sealed = true + +# MA0053: Make class sealed +# +# Also report diagnostic for types that define (new) virtual members. +MA0053.class_with_virtual_member_shoud_be_sealed = true + +# MA0112: Use 'Count > 0' instead of 'Any()' +# +# This rule is disabled by default, hence we need to explicitly enable it. +dotnet_diagnostic.MA0112.severity = error + +#### .NET Compiler Platform code quality rules #### + +# CA1002: Do not expose generic lists +# +# For performance reasons - to avoid interface dispatch - we expose generic lists +# instead of a base class or interface. +dotnet_diagnostic.CA1002.severity = none + +# CA1008: Enums should have zero value +# +# TODO: To be discussed. Having a zero value offers a performance advantage. +dotnet_diagnostic.CA1008.severity = none + +# CA1014: Mark assemblies with CLSCompliantAttribute +# +# This rule is disabled by default, hence we need to explicitly enable it. +# +# Even when enabled, this diagnostic does not appear to be reported for assemblies without CLSCompliantAttribute. +# We reported this issue as https://github.com/dotnet/roslyn-analyzers/issues/6563. +dotnet_diagnostic.CA1014.severity = error + +# CA1051: Do not declare visible instance fields +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1051 +# +# This is a duplicate of S1104 and SA1401. +dotnet_diagnostic.CA1051.severity = none + +# CA1052: Static holder types should be Static or NotInheritable +# +# By default, this diagnostic is only reported for public types. +dotnet_code_quality.CA1052.api_surface = all + +# CA1303: Do not pass literals as localized parameters +# +# We don't care about localization. +dotnet_diagnostic.CA1303.severity = none + +# CA1305: Specify IFormatProvider +# +# This is a an equivalent of MA0011, except that it does not report a diagnostic for the use of +# DateTime.TryParse(string s, out DateTime result). +# +# Submitted https://github.com/dotnet/roslyn-analyzers/issues/6096 to fix CA1305. +dotnet_diagnostic.CA1305.severity = none + +# CA1510: Use ArgumentNullException throw helper +# +# This is only available in .NET 6.0 and higher. We'd need to use conditional compilation to only +# use these throw helper when targeting a framework that supports it. +dotnet_diagnostic.CA1510.severity = none + +# CA1725: Parameter names should match base declaration +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1725 +# +# This is a duplicate of S927, but contains at least one bug: +# https://github.com/dotnet/roslyn-analyzers/issues/6461 +# +# Since we do not enable any of the Sonar rules by default, we'll leave CA1725 enabled. +dotnet_diagnostic.CA1725.severity = error + +# CA1819: Properties should not return arrays +# +# Arrays offer better performance than collections. +dotnet_diagnostic.CA1819.severity = none + +# CA1828: Mark members as static +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1822 +# +# Documentation does not mention which API surface(s) this rule runs on, so we explictly configure it. +dotnet_code_quality.CA1828.api_surface = all + +# CA1852: Seal internal types +# +# Similar to MA0053, but does not support public types and types that define (new) virtual members. +dotnet_diagnostic.CA1852.severity = none + +# CA1859: Change return type for improved performance +# +# By default, this diagnostic is only reported for private members. +dotnet_code_quality.CA1859.api_surface = all + +# CA2208: Instantiate argument exceptions correctly +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2208 +# +# This is similar to, but less powerful than, MA0015. +dotnet_diagnostic.CA2208.severity = none + +#### Roslyn IDE analyser rules #### + +# IDE0032: Use auto-implemented property +# +# For performance reasons, we do not always want to enforce the use of +# auto-implemented properties. +dotnet_diagnostic.IDE0032.severity = suggestion + +# IDE0045: Use conditional expression for assignment +# +# This does not always result in cleaner/clearer code. +dotnet_diagnostic.IDE0045.severity = none + +# IDE0046: Use conditional expression for return +# +# Using a conditional expression is not always a clear win for readability. +# +# Configured using 'dotnet_style_prefer_conditional_expression_over_return' +dotnet_diagnostic.IDE0046.severity = suggestion + +# IDE0055: Fix formatting +# +# When enabled, diagnostics are reported for indented object initializers. +# For example: +# _content = new Person +# { +# Name = "\u13AAlarm" +# }; +# +# There are no settings to configure this correctly, unless https://github.com/dotnet/roslyn/issues/63256 (or similar) is ever implemented. +dotnet_diagnostic.IDE0055.severity = none + +# IDE0270: Null check can be simplified +# +# var inputPath = originalDossierPathList.Find(x => x.id == updatedPath.id); +# if (inputPath is null) +# { +# throw new PcsException($"Path id ({updatedPath.id}) unknown in PCS for dossier id {dossierFromTs.dossier.id}", updatedPath.id); +# } +# +# We do not want to modify the code using a null coalescing operator: +# +# var inputPath = originalDossierPathList.Find(x => x.id == updatedPath.id) ?? throw new PcsException($"Path id ({updatedPath.id}) unknown in PCS for dossier id {dossierFromTs.dossier.id}", updatedPath.id); +dotnet_diagnostic.IDE0270.severity = none + +#### .NET Compiler Platform code style rules #### + +### Language rules ### + +## Modifier preferences + +dotnet_style_require_accessibility_modifiers = true +dotnet_style_readonly_field = true +csharp_prefer_static_local_function = true + +## Parentheses preferences + +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity +dotnet_style_parentheses_in_other_operators = never_if_unnecessary + +# Expression-level preferences + +dotnet_style_object_initializer = true +csharp_style_inlined_variable_declaration = true +dotnet_style_collection_initializer = true +dotnet_style_prefer_auto_properties = true +dotnet_style_explicit_tuple_names = true +csharp_prefer_simple_default_expression = true +dotnet_style_prefer_inferred_tuple_names = true +dotnet_style_prefer_inferred_anonymous_type_member_names = true +csharp_style_prefer_local_over_anonymous_function = true +csharp_style_deconstructed_variable_declaration = false +dotnet_style_prefer_conditional_expression_over_assignment = true +dotnet_style_prefer_conditional_expression_over_return = true +dotnet_style_prefer_compound_assignment = true +csharp_style_prefer_index_operator = false +csharp_style_prefer_range_operator = false +dotnet_style_prefer_simplified_interpolation = false +dotnet_style_prefer_simplified_boolean_expressions = true +csharp_style_implicit_object_creation_when_type_is_apparent = false +csharp_style_prefer_tuple_swap = false + +# Namespace declaration preferences + +csharp_style_namespace_declarations = block_scoped + +# Null-checking preferences + +csharp_style_throw_expression = false +dotnet_style_coalesce_expression = true +dotnet_style_null_propagation = true +dotnet_style_prefer_is_null_check_over_reference_equality_method = true +csharp_style_prefer_null_check_over_type_check = true +csharp_style_conditional_delegate_call = true + +# 'var' preferences + +csharp_style_var_for_built_in_types = true +csharp_style_var_when_type_is_apparent = true +csharp_style_var_elsewhere = true + +# Expression-bodies members + +csharp_style_expression_bodied_methods = false +csharp_style_expression_bodied_constructors = false +csharp_style_expression_bodied_operators = false +csharp_style_expression_bodied_properties = false +csharp_style_expression_bodied_indexers = false +csharp_style_expression_bodied_accessors = false +csharp_style_expression_bodied_lambdas = false +csharp_style_expression_bodied_local_functions = false + +# Pattern matching preferences + +csharp_style_pattern_matching_over_as_with_null_check = true +csharp_style_pattern_matching_over_is_with_cast_check = true +csharp_style_prefer_switch_expression = false +csharp_style_prefer_pattern_matching = true +csharp_style_prefer_not_pattern = true +csharp_style_prefer_extended_property_pattern = true + +# Code block preferences + +csharp_prefer_braces = true +csharp_prefer_simple_using_statement = false + +# Using directive preferences + +csharp_using_directive_placement = outside_namespace + +# Namespace naming preferences + +dotnet_style_namespace_match_folder = true + +# Undocumented preferences + +csharp_style_prefer_method_group_conversion = false +csharp_style_prefer_top_level_statements = false + +### Formatting rules ### + +## .NET formatting options ## + +# Using directive options + +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = true + +## C# formatting options ## + +# New-line options + +# TNIS-13005: Enabling this setting breaks Resharper indentation for lambdas +#csharp_new_line_before_open_brace = accessors, anonymous_methods, anonymous_types, control_blocks, events, indexers, lambdas, local_functions, methods, object_collection_array_initializers, properties, types +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +# Enabling this setting breaks Resharper formatting for an enum field reference that is +# deeply nested in an object initializer. +# +# For an example, see TDataExchangeGeneralEnricher_CernInfrastructureObstruction. +#csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true + +# Indentation options + +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = one_less_than_current +csharp_indent_block_contents = true +# TNIS-13005: Enabling this setting breaks Resharper indentation for lambdas +#csharp_indent_braces = false +# TNIS-13005: Enabling this setting breaks Resharper indentation for lambdas +#csharp_indent_case_contents_when_block = true + +# Spacing options + +csharp_space_after_cast = true +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_declaration_name_and_open_parenthesis = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_after_comma = true +csharp_space_before_comma = false +csharp_space_after_dot = false +csharp_space_before_dot = false +csharp_space_after_semicolon_in_for_statement = true +csharp_space_before_semicolon_in_for_statement = false +csharp_space_around_declaration_statements = false +csharp_space_before_open_square_brackets = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_square_brackets = false + +# Wrap options + +csharp_preserve_single_line_statements = false +csharp_preserve_single_line_blocks = true + +### Naming styles ### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.private_fields_camel_case_begins_with_underscore.symbols = private_fields +dotnet_naming_rule.private_fields_camel_case_begins_with_underscore.style = camel_case_begins_with_underscore +dotnet_naming_rule.private_fields_camel_case_begins_with_underscore.severity = error + +dotnet_naming_rule.private_static_fields_camel_case_begins_with_underscore.symbols = private_static_fields +dotnet_naming_rule.private_static_fields_camel_case_begins_with_underscore.style = camel_case_begins_with_underscore +dotnet_naming_rule.private_static_fields_camel_case_begins_with_underscore.severity = error + +dotnet_naming_rule.private_static_readonly_fields_pascal_case.symbols = private_static_readonly_fields +dotnet_naming_rule.private_static_readonly_fields_pascal_case.style = pascal_case +dotnet_naming_rule.private_static_readonly_fields_pascal_case.severity = error + +dotnet_naming_rule.private_const_fields_pascal_case.symbols = private_const_fields +dotnet_naming_rule.private_const_fields_pascal_case.style = pascal_case +dotnet_naming_rule.private_const_fields_pascal_case.severity = error + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = * +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = * +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = * +dotnet_naming_symbols.non_field_members.required_modifiers = + +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private +dotnet_naming_symbols.private_fields.required_modifiers = + +dotnet_naming_symbols.private_static_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private +dotnet_naming_symbols.private_static_fields.required_modifiers = static + +dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private +dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = static, readonly + +dotnet_naming_symbols.private_const_fields.applicable_kinds = field +dotnet_naming_symbols.private_const_fields.applicable_accessibilities = private +dotnet_naming_symbols.private_const_fields.required_modifiers = const + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.camel_case_begins_with_underscore.required_prefix = _ +dotnet_naming_style.camel_case_begins_with_underscore.required_suffix = +dotnet_naming_style.camel_case_begins_with_underscore.word_separator = +dotnet_naming_style.camel_case_begins_with_underscore.capitalization = camel_case + +#### .NET Compiler Platform general options #### + +# Change the default rule severity for all analyzer rules that are enabled by default +dotnet_analyzer_diagnostic.severity = error + +#### .NET Compiler Platform code refactoring rules #### + +dotnet_style_operator_placement_when_wrapping = end_of_line + +#### ReSharper code style for C# #### + +## Blank Lines + +resharper_csharp_blank_lines_around_region = 1 +resharper_csharp_blank_lines_inside_region = 1 +resharper_csharp_blank_lines_before_single_line_comment = 1 +resharper_csharp_keep_blank_lines_in_declarations = 1 +resharper_csharp_remove_blank_lines_near_braces_in_declarations = true +resharper_csharp_blank_lines_after_start_comment = 1 +resharper_csharp_blank_lines_between_using_groups = 1 +resharper_csharp_blank_lines_after_using_list = 1 +resharper_csharp_blank_lines_around_namespace = 1 +resharper_csharp_blank_lines_inside_namespace = 0 +resharper_csharp_blank_lines_after_file_scoped_namespace_directive = 1 +resharper_csharp_blank_lines_around_type = 1 +resharper_csharp_blank_lines_around_single_line_type = 1 +resharper_csharp_blank_lines_inside_type = 0 +resharper_csharp_blank_lines_around_field = 0 +resharper_csharp_blank_lines_around_single_line_field = 0 +resharper_csharp_blank_lines_around_property = 1 +resharper_csharp_blank_lines_around_single_line_property = 1 +resharper_csharp_blank_lines_around_auto_property = 1 +resharper_csharp_blank_lines_around_single_line_auto_property = 1 +resharper_csharp_blank_lines_around_accessor = 0 +resharper_csharp_blank_lines_around_single_line_accessor = 0 +resharper_csharp_blank_lines_around_invocable = 1 +resharper_csharp_blank_lines_around_single_line_invocable = 1 +resharper_csharp_keep_blank_lines_in_code = 1 +resharper_csharp_remove_blank_lines_near_braces_in_code = true +resharper_csharp_blank_lines_around_local_method = 1 +resharper_csharp_blank_lines_around_single_line_local_method = 1 +resharper_csharp_blank_lines_before_control_transfer_statements = 0 +resharper_csharp_blank_lines_after_control_transfer_statements = 0 +resharper_csharp_blank_lines_before_block_statements = 0 +resharper_csharp_blank_lines_after_block_statements = 1 +resharper_csharp_blank_lines_before_multiline_statements = 0 +resharper_csharp_blank_lines_after_multiline_statements = 0 +resharper_csharp_blank_lines_around_block_case_section = 0 +resharper_csharp_blank_lines_around_multiline_case_section = 0 +resharper_csharp_blank_lines_before_case = 0 +resharper_csharp_blank_lines_after_case = 0 + +## Braces Layout + +resharper_csharp_type_declaration_braces = next_line +resharper_csharp_indent_inside_namespace = true +resharper_csharp_invocable_declaration_braces = next_line +resharper_csharp_anonymous_method_declaration_braces = next_line_shifted_2 +resharper_csharp_accessor_owner_declaration_braces = next_line +resharper_csharp_accessor_declaration_braces = next_line +resharper_csharp_case_block_braces = next_line_shifted_2 +resharper_csharp_initializer_braces = next_line_shifted_2 +resharper_csharp_use_continuous_indent_inside_initializer_braces = true +resharper_csharp_other_braces = next_line +resharper_csharp_allow_comment_after_lbrace = false +resharper_csharp_empty_block_style = multiline + +## Syntax Style + +# 'var' usage in declarations锘 + +resharper_csharp_for_built_in_types = use_var +resharper_csharp_for_simple_types = use_var +resharper_csharp_for_other_types = use_var + +# Instance members qualification + +resharper_csharp_instance_members_qualify_members = none +resharper_csharp_instance_members_qualify_declared_in = base_class + +# Static members qualification + +resharper_csharp_static_members_qualify_with = declared_type +resharper_csharp_static_members_qualify_members = none + +# Built-in types + +resharper_csharp_builtin_type_reference_style = use_keyword +resharper_csharp_builtin_type_reference_for_member_access_style = use_keyword + +# Reference qualification and 'using' directives + +resharper_csharp_prefer_qualified_reference = false +resharper_csharp_add_imports_to_deepest_scope = false +resharper_csharp_qualified_using_at_nested_scope = false +resharper_csharp_allow_alias = true +resharper_csharp_can_use_global_alias = true + +# Modifiers锘 + +resharper_csharp_default_private_modifier = explicit +resharper_csharp_default_internal_modifier = explicit +resharper_csharp_modifiers_order = public private protected internal file static extern new virtual abstract sealed override readonly unsafe required volatile async + +# Braces + +resharper_csharp_braces_for_ifelse = required +resharper_csharp_braces_for_for = required +resharper_csharp_braces_for_foreach = required +resharper_csharp_braces_for_while = required +resharper_csharp_braces_for_dowhile = required +resharper_csharp_braces_for_using = required +resharper_csharp_braces_for_lock = required +resharper_csharp_braces_for_fixed = required +resharper_csharp_braces_redundant = false + +# Code body + +resharper_csharp_method_or_operator_body = block_body +resharper_csharp_local_function_body = block_body +resharper_csharp_constructor_or_destructor_body = block_body +resharper_csharp_accessor_owner_body = accessors_with_block_body +resharper_csharp_namespace_body = block_scoped +resharper_csharp_use_heuristics_for_body_style = false + +# Trailing comma + +resharper_csharp_trailing_comma_in_multiline_lists = false +resharper_csharp_trailing_comma_in_singleline_lists = false + +# Object creation锘 + +resharper_csharp_object_creation_when_type_evident = explicitly_typed +resharper_csharp_object_creation_when_type_not_evident = explicitly_typed + +# Default value锘 + +resharper_csharp_default_value_when_type_evident = default_literal +resharper_csharp_default_value_when_type_not_evident = default_literal + +## Tabs, Indents, Alignment + +# Nested statements锘 + +resharper_csharp_indent_nested_usings_stmt = false +resharper_csharp_indent_nested_fixed_stmt = false +resharper_csharp_indent_nested_lock_stmt = false +resharper_csharp_indent_nested_for_stmt = true +resharper_csharp_indent_nested_foreach_stmt = true +resharper_csharp_indent_nested_while_stmt = true + +# Parenthesis + +resharper_csharp_use_continuous_indent_inside_parens = true +resharper_csharp_indent_method_decl_pars = outside_and_inside +resharper_csharp_indent_invocation_pars = outside_and_inside +resharper_csharp_indent_statement_pars = outside_and_inside +resharper_csharp_indent_typeparam_angles = outside_and_inside +resharper_csharp_indent_typearg_angles = outside_and_inside +resharper_csharp_indent_pars = outside_and_inside + +# Preprocessor directives + +resharper_csharp_indent_preprocessor_if = no_indent +resharper_csharp_indent_preprocessor_region = usual_indent +resharper_csharp_indent_preprocessor_other = no_indent + +# Other indents + +resharper_indent_switch_labels = true +resharper_csharp_outdent_statement_labels = true +resharper_csharp_indent_type_constraints = true +resharper_csharp_stick_comment = false +resharper_csharp_place_comments_at_first_column = false +resharper_csharp_use_indent_from_previous_element = true +resharper_csharp_indent_braces_inside_statement_conditions = true + +# Align multiline constructs + +resharper_csharp_alignment_tab_fill_style = use_spaces +resharper_csharp_allow_far_alignment = true +resharper_csharp_align_multiline_parameter = true +resharper_csharp_align_multiline_extends_list = true +resharper_csharp_align_linq_query = true +resharper_csharp_align_multiline_binary_expressions_chain = true +resharper_csharp_outdent_binary_ops = false +resharper_csharp_align_multiline_calls_chain = true +resharper_csharp_outdent_dots = false +resharper_csharp_align_multiline_array_and_object_initializer = false +resharper_csharp_align_multiline_switch_expression = false +resharper_csharp_align_multiline_property_pattern = false +resharper_csharp_align_multiline_list_pattern = false +resharper_csharp_align_multiline_binary_patterns = false +resharper_csharp_outdent_binary_pattern_ops = false +resharper_csharp_indent_anonymous_method_block = true +resharper_csharp_align_first_arg_by_paren = false +resharper_csharp_align_multiline_argument = true +resharper_csharp_align_tuple_components = true +resharper_csharp_align_multiline_expression = true +resharper_csharp_align_multiline_statement_conditions = true +resharper_csharp_align_multiline_for_stmt = true +resharper_csharp_align_multiple_declaration = true +resharper_csharp_align_multline_type_parameter_list = true +resharper_csharp_align_multline_type_parameter_constrains = true +resharper_csharp_outdent_commas = false + +## Line Breaks + +# General锘 + +resharper_csharp_keep_user_linebreaks = true +resharper_csharp_max_line_length = 140 +resharper_csharp_wrap_before_comma = false +resharper_csharp_wrap_before_eq = false +resharper_csharp_special_else_if_treatment = true +resharper_csharp_insert_final_newline = true + +# Arrangement of attributes + +resharper_csharp_keep_existing_attribute_arrangement = false +resharper_csharp_place_type_attribute_on_same_line = false +resharper_csharp_place_method_attribute_on_same_line = false +resharper_csharp_place_accessorholder_attribute_on_same_line = false +resharper_csharp_place_accessor_attribute_on_same_line = false +resharper_csharp_place_field_attribute_on_same_line = false +resharper_csharp_place_record_field_attribute_on_same_line = true + +# Arrangement of method signatures + +resharper_csharp_place_constructor_initializer_on_same_line = false +resharper_csharp_place_expr_method_on_single_line = true +resharper_csharp_place_expr_property_on_single_line = true +resharper_csharp_place_expr_accessor_on_single_line = true + +# Arrangement of type parameters, constraints, and base types锘 + +resharper_csharp_place_type_constraints_on_same_line = false +resharper_csharp_wrap_before_first_type_parameter_constraint = true + +# Arrangement of declaration blocks + +resharper_csharp_place_abstract_accessorholder_on_single_line = true + +# Arrangement of statements + +resharper_new_line_before_else = true +resharper_new_line_before_while = true +resharper_new_line_before_catch = true +resharper_new_line_before_finally = true +resharper_wrap_for_stmt_header_style = chop_if_long +resharper_wrap_multiple_declaration_style = chop_always + +## Spaces + +# Preserve existing formatting锘 + +resharper_csharp_extra_spaces = remove_all + +# Before parentheses in statements + +resharper_csharp_space_before_if_parentheses = true +resharper_csharp_space_before_while_parentheses = true +resharper_csharp_space_before_catch_parentheses = true +resharper_csharp_space_before_switch_parentheses = true +resharper_csharp_space_before_for_parentheses = true +resharper_csharp_space_before_foreach_parentheses = true +resharper_csharp_space_before_using_parentheses = true +resharper_csharp_space_before_lock_parentheses = true +resharper_csharp_space_before_fixed_parentheses = true + +# Before other parentheses + +resharper_csharp_space_before_method_call_parentheses = false +resharper_csharp_space_before_empty_method_call_parentheses = false +resharper_csharp_space_before_method_parentheses = false +resharper_csharp_space_before_empty_method_parentheses = false +resharper_csharp_space_before_typeof_parentheses = false +resharper_csharp_space_before_default_parentheses = false +resharper_csharp_space_before_checked_parentheses = false +resharper_csharp_space_before_sizeof_parentheses = false +resharper_csharp_space_before_nameof_parentheses = false +resharper_csharp_space_before_new_parentheses = false +resharper_csharp_space_between_keyword_and_expression = true +resharper_csharp_space_between_keyword_and_type = false + +# Within parentheses in statements + +resharper_csharp_space_within_if_parentheses = false +resharper_csharp_space_within_while_parentheses = false +resharper_csharp_space_within_catch_parentheses = false +resharper_csharp_space_within_switch_parentheses = false +resharper_csharp_space_within_for_parentheses = false +resharper_csharp_space_within_foreach_parentheses = false +resharper_csharp_space_within_using_parentheses = false +resharper_csharp_space_within_lock_parentheses = false +resharper_csharp_space_within_fixed_parentheses = false + +# Within other parentheses + +resharper_csharp_space_within_parentheses = false +resharper_csharp_space_between_typecast_parentheses = false +resharper_csharp_space_between_method_declaration_parameter_list_parentheses = false +resharper_csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +resharper_csharp_space_between_method_call_parameter_list_parentheses = false +resharper_csharp_space_between_method_call_empty_parameter_list_parentheses = false +resharper_csharp_space_within_typeof_parentheses = false +resharper_csharp_space_within_default_parentheses = false +resharper_csharp_space_within_checked_parentheses = false +resharper_csharp_space_within_sizeof_parentheses = false +resharper_csharp_space_within_nameof_parentheses = false +resharper_csharp_space_within_new_parentheses = false + +# Around array brackets + +resharper_csharp_space_before_array_access_brackets = false +resharper_csharp_space_before_open_square_brackets = false +resharper_csharp_space_before_array_rank_brackets = false +resharper_csharp_space_within_array_access_brackets = false +resharper_csharp_space_between_square_brackets = false +resharper_csharp_space_within_array_rank_brackets = false +resharper_csharp_space_within_array_rank_empty_brackets = false +resharper_csharp_space_between_empty_square_bracket = false + +# Around angle brackets + +resharper_csharp_space_before_type_parameter_angle = false +resharper_csharp_space_before_type_argument_angle = false +resharper_csharp_space_within_type_parameter_angles = false +resharper_csharp_space_within_type_argument_angles = false + +### ReSharper code style for XMLDOC ### + +## Tabs and indents锘 + +resharper_xmldoc_indent_style = space +# ReSharper currently ignores this setting. See https://youtrack.jetbrains.com/issue/RSRP-465678/XMLDOC-indent-settings-ignored. +resharper_xmldoc_indent_size = 2 +resharper_xmldoc_tab_width = 2 +resharper_xmldoc_alignment_tab_fill_style = use_spaces +resharper_xmldoc_allow_far_alignment = true + +## Line wrapping锘 + +resharper_xmldoc_max_line_length = 140 +resharper_xmldoc_wrap_tags_and_pi = false + +## Processing instructions锘 + +resharper_xmldoc_spaces_around_eq_in_pi_attribute = false +resharper_xmldoc_space_after_last_pi_attribute = false +resharper_xmldoc_pi_attribute_style = on_single_line +resharper_xmldoc_pi_attributes_indent = align_by_first_attribute +resharper_xmldoc_blank_line_after_pi = false + +## Inside of tag header + +resharper_xmldoc_spaces_around_eq_in_attribute = false +resharper_xmldoc_space_after_last_attribute = false +resharper_xmldoc_space_before_self_closing = false +resharper_xmldoc_attribute_style = do_not_touch +resharper_xmldoc_attribute_indent = align_by_first_attribute + +## Tag content + +resharper_xmldoc_keep_user_linebreaks = true +resharper_xmldoc_linebreaks_inside_tags_for_multiline_elements = true +resharper_xmldoc_linebreaks_inside_tags_for_elements_with_child_elements = false +resharper_xmldoc_spaces_inside_tags = false +resharper_xmldoc_wrap_text = false +resharper_xmldoc_wrap_around_elements = false +# ReSharper currently ignores the 'resharper_xmldoc_indent_size' setting. Once https://youtrack.jetbrains.com/issue/RSRP-465678/XMLDOC-indent-settings-ignored +# is fixed, we should change the value of this setting to 'one_indent'. +resharper_xmldoc_indent_child_elements = zero_indent +resharper_xmldoc_indent_text = zero_indent + +## Around tags + +resharper_xmldoc_max_blank_lines_between_tags = 1 +resharper_xmldoc_linebreak_before_multiline_elements = true +resharper_xmldoc_linebreak_before_singleline_elements = false + +[*.{xml,xsd,csproj,targets,proj,props,runsettings,config}] + +#### ReSharper code style for XML #### + +## Tabs and indents + +resharper_xml_indent_style = space +resharper_xml_indent_size = 4 +resharper_xml_tab_width = 4 +resharper_xml_alignment_tab_fill_style = use_spaces +resharper_xml_allow_far_alignment = true + +## Line wrapping + +resharper_xml_wrap_tags_and_pi = false + +## Processing instructions锘 + +resharper_xml_spaces_around_eq_in_pi_attribute = false +resharper_xml_space_after_last_pi_attribute = false +resharper_xml_pi_attribute_style = on_single_line +resharper_xml_pi_attributes_indent = align_by_first_attribute +resharper_xml_blank_line_after_pi = false + +## Inside of tag header锘 + +resharper_xml_spaces_around_eq_in_attribute = false +resharper_xml_space_after_last_attribute = false +resharper_xml_space_before_self_closing = true +resharper_xml_attribute_style = do_not_touch +resharper_xml_attribute_indent = align_by_first_attribute + +## Tag content锘 + +resharper_xml_keep_user_linebreaks = true +resharper_xml_linebreaks_inside_tags_for_multiline_elements = false +resharper_xml_linebreaks_inside_tags_for_elements_with_child_elements = false +resharper_xml_linebreaks_inside_tags_for_elements_longer_than = false +resharper_xml_spaces_inside_tags = false +resharper_xml_wrap_text = false +resharper_xml_wrap_around_elements = false +resharper_xml_indent_child_elements = one_indent +resharper_xml_indent_text = zero_indent +resharper_xml_max_blank_lines_between_tags = 1 +resharper_xml_linebreak_before_multiline_elements = false +resharper_xml_linebreak_before_singleline_elements = false + +## Other锘 + +resharper_xml_insert_final_newline = true diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 000000000..4fd6964ad --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,48 @@ + + + + + + true + $(MSBuildThisFileDirectory)src\Renci.SshNet.snk + true + latest + + false + + + + + false + preview-All + true + + + + + + + + + + + + + diff --git a/README.md b/README.md old mode 100755 new mode 100644 diff --git a/src/Renci.SshNet.Tests/Classes/Common/ObjectIdentifierTest.cs b/src/Renci.SshNet.Tests/Classes/Common/ObjectIdentifierTest.cs index 5bfbfc29a..608159424 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/ObjectIdentifierTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/ObjectIdentifierTest.cs @@ -1,26 +1,37 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for ObjectIdentifierTest and is intended - ///to contain all ObjectIdentifierTest Unit Tests - /// +{ [TestClass] - [Ignore] // placeholder for actual test public class ObjectIdentifierTest : TestBase { - /// - ///A test for ObjectIdentifier Constructor - /// [TestMethod] - public void ObjectIdentifierConstructorTest() + public void Constructor_IdentifiersIsNull() { - ulong[] identifiers = null; // TODO: Initialize to an appropriate value - ObjectIdentifier target = new ObjectIdentifier(identifiers); - Assert.Inconclusive("TODO: Implement code to verify target"); + const ulong[] identifiers = null; + + var actualException = Assert.ThrowsException(() => new ObjectIdentifier(identifiers)); + + Assert.AreEqual(typeof(ArgumentNullException), actualException.GetType()); + Assert.IsNull(actualException.InnerException); + Assert.AreEqual(nameof(identifiers), actualException.ParamName); + } + + [TestMethod] + public void Constructor_LengthOfIdentifiersIsLessThanTwo() + { + var identifiers = new[] { 5UL }; + + var actualException = Assert.ThrowsException(() => new ObjectIdentifier(identifiers)); + + Assert.AreEqual(typeof(ArgumentException), actualException.GetType()); + Assert.IsNull(actualException.InnerException); + ArgumentExceptionAssert.MessageEquals("Must contain at least two elements.", actualException); + Assert.AreEqual(nameof(identifiers), actualException.ParamName); } } } diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs index fea7a6648..43aa9a3b1 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs @@ -1,13 +1,15 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Connection; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Common; +using Renci.SshNet.Connection; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] diff --git a/src/Renci.SshNet.Tests/Classes/MessageEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/MessageEventArgsTest.cs index 387b5b29e..051fd6c34 100644 --- a/src/Renci.SshNet.Tests/Classes/MessageEventArgsTest.cs +++ b/src/Renci.SshNet.Tests/Classes/MessageEventArgsTest.cs @@ -6,7 +6,6 @@ namespace Renci.SshNet.Tests.Classes /// /// Provides data for message events. /// - /// Message type [TestClass] public class MessageEventArgsTest : TestBase { diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/HMacTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/HMacTest.cs index 13d8f1dda..94e558b2a 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/HMacTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/HMacTest.cs @@ -8,7 +8,6 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography /// /// Provides HMAC algorithm implementation. /// - /// [TestClass] public class HMacTest : TestBase { diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs index 1331160b1..6dc110f74 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs @@ -147,17 +147,17 @@ protected override void LoadData() base.LoadData(); Information = new SftpFileSytemInformation(ReadUInt64(), // FileSystemBlockSize - ReadUInt64(), // BlockSize - ReadUInt64(), // TotalBlocks - ReadUInt64(), // FreeBlocks - ReadUInt64(), // AvailableBlocks - ReadUInt64(), // TotalNodes - ReadUInt64(), // FreeNodes - ReadUInt64(), // AvailableNodes - ReadUInt64(), // Sid - ReadUInt64(), // Flags - ReadUInt64() // MaxNameLenght - ); + ReadUInt64(), // BlockSize + ReadUInt64(), // TotalBlocks + ReadUInt64(), // FreeBlocks + ReadUInt64(), // AvailableBlocks + ReadUInt64(), // TotalNodes + ReadUInt64(), // FreeNodes + ReadUInt64(), // AvailableNodes + ReadUInt64(), // Sid + ReadUInt64(), // Flags + ReadUInt64() // MaxNameLenght + ); } protected override void SaveData() diff --git a/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs b/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs index 78319f76f..6815d1609 100644 --- a/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs +++ b/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs @@ -40,7 +40,7 @@ public AsyncSocketListener(IPEndPoint endPoint) /// /// to invoke on the that is used /// to handle the communication with the remote host, when the remote host has closed the connection; otherwise, - /// . The default is . + /// . The default is . /// public bool ShutdownRemoteCommunicationSocket { get; set; } diff --git a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index 80c36aa70..89a270445 100644 --- a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -1,9 +1,16 @@ 锘 - 7.3 - true - ..\Renci.SshNet.snk - net462;net6.0;net7.0 + net462;net6.0;net7.0 + + $(NoWarn);CS1591 diff --git a/src/Renci.SshNet.sln b/src/Renci.SshNet.sln index bc1f6f6d3..09953551d 100644 --- a/src/Renci.SshNet.sln +++ b/src/Renci.SshNet.sln @@ -1,7 +1,7 @@ 锘 Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29521.150 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33326.253 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D}" ProjectSection(SolutionItems) = preProject @@ -23,6 +23,25 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet", "Renci.SshNe EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.Tests", "Renci.SshNet.Tests\Renci.SshNet.Tests.csproj", "{C45379B9-17B1-4E89-BC2E-6D41726413E8}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{04E8CC26-116E-4116-9558-7ED542548E70}" + ProjectSection(SolutionItems) = preProject + ..\.editorconfig = ..\.editorconfig + ..\.gitattributes = ..\.gitattributes + ..\.gitignore = ..\.gitignore + ..\appveyor.yml = ..\appveyor.yml + ..\CODEOWNERS = ..\CODEOWNERS + ..\Directory.Build.props = ..\Directory.Build.props + ..\LICENSE = ..\LICENSE + ..\README.md = ..\README.md + ..\THIRD-PARTY-NOTICES.TXT = ..\THIRD-PARTY-NOTICES.TXT + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D21A4D03-0AC2-4613-BB6D-74D2D16A72CC}" + ProjectSection(SolutionItems) = preProject + ..\test\.editorconfig = ..\test\.editorconfig + ..\test\Directory.Build.props = ..\test\Directory.Build.props + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -72,6 +91,7 @@ Global GlobalSection(NestedProjects) = preSolution {94EE3919-19FA-4D9B-8DA9-249050B15232} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} {A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} + {D21A4D03-0AC2-4613-BB6D-74D2D16A72CC} = {04E8CC26-116E-4116-9558-7ED542548E70} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BAD6019D-4AF7-4E15-99A0-8036E16FC0E5} diff --git a/src/Renci.SshNet/.editorconfig b/src/Renci.SshNet/.editorconfig new file mode 100644 index 000000000..7c507c75c --- /dev/null +++ b/src/Renci.SshNet/.editorconfig @@ -0,0 +1,25 @@ +锘縖*.cs] + +### StyleCop Analyzers rules ### + +# SA1202: Elements must be ordered by access +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1202.md +dotnet_diagnostic.SA1202.severity = none + +#### .NET Compiler Platform analysers rules #### + +# CA1031: Do not catch general exception types +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1031 +dotnet_diagnostic.CA1031.severity = none + +# CA2213: Disposable fields should be disposed +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2213 +dotnet_diagnostic.CA2213.severity = none + +# IDE0004: Types that own disposable fields should be disposable +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0004 +dotnet_diagnostic.IDE0004.severity = none + +# IDE0048: Add parentheses for clarity +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0047 +dotnet_diagnostic.IDE0048.severity = none diff --git a/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs b/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs index 2c7d38b0c..d46411044 100644 --- a/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs @@ -8,7 +8,7 @@ internal static class CryptoAbstraction private static readonly System.Security.Cryptography.RandomNumberGenerator Randomizer = CreateRandomNumberGenerator(); /// - /// Generates a array of the specified length, and fills it with a + /// Generates a array of the specified length, and fills it with a /// cryptographically strong random sequence of values. /// /// The length of the array generate. diff --git a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs index e7740d574..3c6fb90a3 100644 --- a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs @@ -20,7 +20,6 @@ public static bool CanRead(Socket socket) } return false; - } /// @@ -80,8 +79,10 @@ private static void ConnectCore(Socket socket, IPEndPoint remoteEndpoint, TimeSp // dispose Socket socket.Dispose(); } + // dispose ManualResetEvent connectCompleted.Dispose(); + // dispose SocketAsyncEventArgs args.Dispose(); @@ -151,8 +152,12 @@ public static int ReadPartial(Socket socket, byte[] buffer, int offset, int size catch (SocketException ex) { if (ex.SocketErrorCode == SocketError.TimedOut) + { throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture, - "Socket read operation has timed out after {0:F0} milliseconds.", timeout.TotalMilliseconds)); + "Socket read operation has timed out after {0:F0} milliseconds.", + timeout.TotalMilliseconds)); + } + throw; } } @@ -168,14 +173,18 @@ public static void ReadContinuous(Socket socket, byte[] buffer, int offset, int { var bytesRead = socket.Receive(buffer, offset, size, SocketFlags.None); if (bytesRead == 0) + { break; + } processReceivedBytesAction(buffer, offset, bytesRead); } catch (SocketException ex) { if (IsErrorResumable(ex.SocketErrorCode)) + { continue; + } switch (ex.SocketErrorCode) { @@ -208,7 +217,9 @@ public static int ReadByte(Socket socket, TimeSpan timeout) { var buffer = new byte[1]; if (Read(socket, buffer, 0, 1, timeout) == 0) + { return -1; + } return buffer[0]; } @@ -221,14 +232,14 @@ public static int ReadByte(Socket socket, TimeSpan timeout) /// The write failed. public static void SendByte(Socket socket, byte value) { - var buffer = new[] {value}; + var buffer = new[] { value }; Send(socket, buffer, 0, 1); } /// /// Receives data from a bound . /// - /// + /// The to read from. /// The number of bytes to receive. /// Specifies the amount of time after which the call will time out. /// @@ -244,7 +255,7 @@ public static void SendByte(Socket socket, byte value) public static byte[] Read(Socket socket, int size, TimeSpan timeout) { var buffer = new byte[size]; - Read(socket, buffer, 0, size, timeout); + _ = Read(socket, buffer, 0, size, timeout); return buffer; } @@ -256,7 +267,7 @@ public static Task ReadAsync(Socket socket, byte[] buffer, int offset, int /// /// Receives data from a bound into a receive buffer. /// - /// + /// The to read from. /// An array of type that is the storage location for the received data. /// The position in parameter to store the received data. /// The number of bytes to receive. @@ -288,7 +299,9 @@ public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeS { var bytesRead = socket.Receive(buffer, offset + totalBytesRead, totalBytesToRead - totalBytesRead, SocketFlags.None); if (bytesRead == 0) + { return 0; + } totalBytesRead += bytesRead; } @@ -301,8 +314,11 @@ public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeS } if (ex.SocketErrorCode == SocketError.TimedOut) + { throw new SshOperationTimeoutException(string.Format(CultureInfo.InvariantCulture, - "Socket read operation has timed out after {0:F0} milliseconds.", readTimeout.TotalMilliseconds)); + "Socket read operation has timed out after {0:F0} milliseconds.", + readTimeout.TotalMilliseconds)); + } throw; } @@ -328,8 +344,10 @@ public static void Send(Socket socket, byte[] data, int offset, int size) { var bytesSent = socket.Send(data, offset + totalBytesSent, totalBytesToSend - totalBytesSent, SocketFlags.None); if (bytesSent == 0) + { throw new SshConnectionException("An established connection was aborted by the server.", DisconnectReason.ConnectionLost); + } totalBytesSent += bytesSent; } @@ -341,9 +359,12 @@ public static void Send(Socket socket, byte[] data, int offset, int size) ThreadAbstraction.Sleep(30); } else - throw; // any serious error occurr + { + throw; // any serious error occurr + } } - } while (totalBytesSent < totalBytesToSend); + } + while (totalBytesSent < totalBytesToSend); } public static bool IsErrorResumable(SocketError socketError) @@ -363,10 +384,8 @@ public static bool IsErrorResumable(SocketError socketError) private static void ConnectCompleted(object sender, SocketAsyncEventArgs e) { var eventWaitHandle = (ManualResetEvent) e.UserToken; - if (eventWaitHandle != null) - eventWaitHandle.Set(); + _ = eventWaitHandle?.Set(); } #endif // FEATURE_SOCKET_EAP - } } diff --git a/src/Renci.SshNet/Abstractions/SocketExtensions.cs b/src/Renci.SshNet/Abstractions/SocketExtensions.cs index 7d3c30f93..84c2f03df 100644 --- a/src/Renci.SshNet/Abstractions/SocketExtensions.cs +++ b/src/Renci.SshNet/Abstractions/SocketExtensions.cs @@ -8,15 +8,14 @@ namespace Renci.SshNet.Abstractions { // Async helpers based on https://devblogs.microsoft.com/pfxteam/awaiting-socket-operations/ - internal static class SocketExtensions { - sealed class SocketAsyncEventArgsAwaitable : SocketAsyncEventArgs, INotifyCompletion + private sealed class SocketAsyncEventArgsAwaitable : SocketAsyncEventArgs, INotifyCompletion { - private readonly static Action SENTINEL = () => { }; + private static readonly Action SENTINEL = () => { }; - private bool isCancelled; - private Action continuationAction; + private bool _isCancelled; + private Action _continuationAction; public SocketAsyncEventArgsAwaitable() { @@ -35,7 +34,8 @@ public SocketAsyncEventArgsAwaitable ExecuteAsync(Func @@ -29,9 +31,11 @@ public static void ExecuteThreadLongRunning(Action action) public static void ExecuteThread(Action action) { if (action == null) - throw new ArgumentNullException("action"); + { + throw new ArgumentNullException(nameof(action)); + } - System.Threading.ThreadPool.QueueUserWorkItem(o => action()); + _ = System.Threading.ThreadPool.QueueUserWorkItem(o => action()); } } } diff --git a/src/Renci.SshNet/AuthenticationMethod.cs b/src/Renci.SshNet/AuthenticationMethod.cs index 1a285d8c8..51e49b7ad 100644 --- a/src/Renci.SshNet/AuthenticationMethod.cs +++ b/src/Renci.SshNet/AuthenticationMethod.cs @@ -1,10 +1,11 @@ -锘縰sing Renci.SshNet.Common; -using System; +锘縰sing System; + +using Renci.SshNet.Common; namespace Renci.SshNet { /// - /// Base class for all supported authentication methods + /// Base class for all supported authentication methods. /// public abstract class AuthenticationMethod : IAuthenticationMethod { @@ -22,7 +23,7 @@ public abstract class AuthenticationMethod : IAuthenticationMethod public string Username { get; private set; } /// - /// Gets list of allowed authentications. + /// Gets or sets the list of allowed authentications. /// public string[] AllowedAuthentications { get; protected set; } @@ -34,7 +35,9 @@ public abstract class AuthenticationMethod : IAuthenticationMethod protected AuthenticationMethod(string username) { if (username.IsNullOrWhiteSpace()) + { throw new ArgumentException("username"); + } Username = username; } diff --git a/src/Renci.SshNet/BaseClient.cs b/src/Renci.SshNet/BaseClient.cs index fdc4e3a39..6596ceedb 100644 --- a/src/Renci.SshNet/BaseClient.cs +++ b/src/Renci.SshNet/BaseClient.cs @@ -24,6 +24,7 @@ public abstract class BaseClient : IBaseClient, IDisposable private TimeSpan _keepAliveInterval; private Timer _keepAliveTimer; private ConnectionInfo _connectionInfo; + private bool _isDisposed; /// /// Gets the current session. @@ -101,7 +102,9 @@ public TimeSpan KeepAliveInterval CheckDisposed(); if (value == _keepAliveInterval) + { return; + } if (value == SshNet.Session.InfiniteTimeSpan) { @@ -114,8 +117,7 @@ public TimeSpan KeepAliveInterval { // change the due time and interval of the timer if has already // been created (which means the client is connected) - - _keepAliveTimer.Change(value, value); + _ = _keepAliveTimer.Change(value, value); } else if (IsSessionConnected()) { @@ -127,9 +129,10 @@ public TimeSpan KeepAliveInterval _keepAliveTimer = CreateKeepAliveTimer(value, value); } - // note that if the client is not yet connected, then the timer will be created with the + // note that if the client is not yet connected, then the timer will be created with the // new interval when Connect() is invoked } + _keepAliveInterval = value; } } @@ -180,9 +183,14 @@ protected BaseClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo) internal BaseClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) { if (connectionInfo == null) - throw new ArgumentNullException("connectionInfo"); + { + throw new ArgumentNullException(nameof(connectionInfo)); + } + if (serviceFactory == null) - throw new ArgumentNullException("serviceFactory"); + { + throw new ArgumentNullException(nameof(serviceFactory)); + } ConnectionInfo = connectionInfo; _ownsConnectionInfo = ownsConnectionInfo; @@ -205,26 +213,29 @@ public void Connect() // TODO (see issue #1758): // we're not stopping the keep-alive timer and disposing the session here - // + // // we could do this but there would still be side effects as concrete // implementations may still hang on to the original session - // + // // therefore it would be better to actually invoke the Disconnect method // (and then the Dispose on the session) but even that would have side effects // eg. it would remove all forwarded ports from SshClient - // + // // I think we should modify our concrete clients to better deal with a - // disconnect. In case of SshClient this would mean not removing the + // disconnect. In case of SshClient this would mean not removing the // forwarded ports on disconnect (but only on dispose ?) and link a // forwarded port with a client instead of with a session // // To be discussed with Oleg (or whoever is interested) if (IsSessionConnected()) + { throw new InvalidOperationException("The client is already connected."); + } OnConnecting(); Session = CreateAndConnectSession(); + try { // Even though the method we invoke makes you believe otherwise, at this point only @@ -238,6 +249,7 @@ public void Connect() DisposeSession(); throw; } + StartKeepAliveTimer(); } @@ -260,26 +272,29 @@ public async Task ConnectAsync(CancellationToken cancellationToken) // TODO (see issue #1758): // we're not stopping the keep-alive timer and disposing the session here - // + // // we could do this but there would still be side effects as concrete // implementations may still hang on to the original session - // + // // therefore it would be better to actually invoke the Disconnect method // (and then the Dispose on the session) but even that would have side effects // eg. it would remove all forwarded ports from SshClient - // + // // I think we should modify our concrete clients to better deal with a - // disconnect. In case of SshClient this would mean not removing the + // disconnect. In case of SshClient this would mean not removing the // forwarded ports on disconnect (but only on dispose ?) and link a // forwarded port with a client instead of with a session // // To be discussed with Oleg (or whoever is interested) if (IsSessionConnected()) + { throw new InvalidOperationException("The client is already connected."); + } OnConnecting(); Session = await CreateAndConnectSessionAsync(cancellationToken).ConfigureAwait(false); + try { // Even though the method we invoke makes you believe otherwise, at this point only @@ -293,6 +308,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken) DisposeSession(); throw; } + StartKeepAliveTimer(); } @@ -352,11 +368,7 @@ protected virtual void OnConnected() /// protected virtual void OnDisconnecting() { - var session = Session; - if (session != null) - { - session.OnDisconnecting(); - } + Session?.OnDisconnecting(); } /// @@ -368,26 +380,14 @@ protected virtual void OnDisconnected() private void Session_ErrorOccured(object sender, ExceptionEventArgs e) { - var handler = ErrorOccurred; - if (handler != null) - { - handler(this, e); - } + ErrorOccurred?.Invoke(this, e); } private void Session_HostKeyReceived(object sender, HostKeyEventArgs e) { - var handler = HostKeyReceived; - if (handler != null) - { - handler(this, e); - } + HostKeyReceived?.Invoke(this, e); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// @@ -395,18 +395,20 @@ public void Dispose() { DiagnosticAbstraction.Log("Disposing client."); - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -414,9 +416,10 @@ protected virtual void Dispose(bool disposing) if (_ownsConnectionInfo && _connectionInfo != null) { - var connectionInfoDisposable = _connectionInfo as IDisposable; - if (connectionInfoDisposable != null) + if (_connectionInfo is IDisposable connectionInfoDisposable) + { connectionInfoDisposable.Dispose(); + } _connectionInfo = null; } @@ -431,20 +434,19 @@ protected virtual void Dispose(bool disposing) protected void CheckDisposed() { if (_isDisposed) + { throw new ObjectDisposedException(GetType().FullName); + } } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~BaseClient() { - Dispose(false); + Dispose(disposing: false); } - #endregion - /// /// Stops the keep-alive timer, and waits until all timer callbacks have been /// executed. @@ -452,7 +454,9 @@ protected void CheckDisposed() private void StopKeepAliveTimer() { if (_keepAliveTimer == null) + { return; + } _keepAliveTimer.Dispose(); _keepAliveTimer = null; @@ -464,14 +468,16 @@ private void SendKeepAliveMessage() // do nothing if we have disposed or disconnected if (session == null) + { return; + } // do not send multiple keep-alive messages concurrently if (Monitor.TryEnter(_keepAliveLock)) { try { - session.TrySendMessage(new IgnoreMessage()); + _ = session.TrySendMessage(new IgnoreMessage()); } finally { @@ -490,11 +496,15 @@ private void SendKeepAliveMessage() private void StartKeepAliveTimer() { if (_keepAliveInterval == SshNet.Session.InfiniteTimeSpan) + { return; + } if (_keepAliveTimer != null) + { // timer is already started return; + } _keepAliveTimer = CreateKeepAliveTimer(_keepAliveInterval, _keepAliveInterval); } diff --git a/src/Renci.SshNet/Channels/Channel.cs b/src/Renci.SshNet/Channels/Channel.cs index a6311a981..df76e67cc 100644 --- a/src/Renci.SshNet/Channels/Channel.cs +++ b/src/Renci.SshNet/Channels/Channel.cs @@ -1,11 +1,12 @@ 锘縰sing System; +using System.Globalization; using System.Net.Sockets; using System.Threading; + +using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Messages; using Renci.SshNet.Messages.Connection; -using System.Globalization; -using Renci.SshNet.Abstractions; namespace Renci.SshNet.Channels { @@ -14,14 +15,15 @@ namespace Renci.SshNet.Channels /// internal abstract class Channel : IChannel { - private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(false); - private EventWaitHandle _channelServerWindowAdjustWaitHandle = new ManualResetEvent(false); private readonly object _serverWindowSizeLock = new object(); private readonly uint _initialWindowSize; + private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(initialState: false); + private EventWaitHandle _channelServerWindowAdjustWaitHandle = new ManualResetEvent(initialState: false); private uint? _remoteWindowSize; private uint? _remoteChannelNumber; private uint? _remotePacketSize; private ISession _session; + private bool _isDisposed; /// /// Holds a value indicating whether the SSH_MSG_CHANNEL_CLOSE has been sent to the remote party. @@ -66,7 +68,7 @@ internal abstract class Channel : IChannel public event EventHandler Exception; /// - /// Initializes a new instance. + /// Initializes a new instance of the class. /// /// The session. /// The local channel number. @@ -155,7 +157,10 @@ public uint RemoteChannelNumber get { if (!_remoteChannelNumber.HasValue) + { throw CreateRemoteChannelInfoNotAvailableException(); + } + return _remoteChannelNumber.Value; } private set @@ -177,7 +182,10 @@ public uint RemotePacketSize get { if (!_remotePacketSize.HasValue) + { throw CreateRemoteChannelInfoNotAvailableException(); + } + return _remotePacketSize.Value; } private set @@ -197,7 +205,10 @@ public uint RemoteWindowSize get { if (!_remoteWindowSize.HasValue) + { throw CreateRemoteChannelInfoNotAvailableException(); + } + return _remoteWindowSize.Value; } private set @@ -207,15 +218,13 @@ private set } /// - /// Gets a value indicating whether this channel is open. + /// Gets or sets a value indicating whether this channel is open. /// /// /// true if this channel is open; otherwise, false. /// public bool IsOpen { get; protected set; } - #region Message events - /// /// Occurs when is received. /// @@ -251,8 +260,6 @@ private set /// public event EventHandler RequestFailed; - #endregion - /// /// Gets a value indicating whether the session is connected. /// @@ -282,6 +289,12 @@ protected SemaphoreLight SessionSemaphore get { return _session.SessionSemaphore; } } + /// + /// Initializes the information on the remote channel. + /// + /// The remote channel number. + /// The remote window size. + /// The remote packet size. protected void InitializeRemoteInfo(uint remoteChannelNumber, uint remoteWindowSize, uint remotePacketSize) { RemoteChannelNumber = remoteChannelNumber; @@ -320,7 +333,9 @@ public void SendData(byte[] data, int offset, int size) { // send channel messages only while channel is open if (!IsOpen) + { return; + } var totalBytesToSend = size; while (totalBytesToSend > 0) @@ -338,8 +353,6 @@ public void SendData(byte[] data, int offset, int size) } } - #region Channel virtual methods - /// /// Called when channel window need to be adjust. /// @@ -350,7 +363,8 @@ protected virtual void OnWindowAdjust(uint bytesToAdd) { RemoteWindowSize += bytesToAdd; } - _channelServerWindowAdjustWaitHandle.Set(); + + _ = _channelServerWindowAdjustWaitHandle.Set(); } /// @@ -361,9 +375,7 @@ protected virtual void OnData(byte[] data) { AdjustDataWindow(data); - var dataReceived = DataReceived; - if (dataReceived != null) - dataReceived(this, new ChannelDataEventArgs(LocalChannelNumber, data)); + DataReceived?.Invoke(this, new ChannelDataEventArgs(LocalChannelNumber, data)); } /// @@ -375,9 +387,7 @@ protected virtual void OnExtendedData(byte[] data, uint dataTypeCode) { AdjustDataWindow(data); - var extendedDataReceived = ExtendedDataReceived; - if (extendedDataReceived != null) - extendedDataReceived(this, new ChannelExtendedDataEventArgs(LocalChannelNumber, data, dataTypeCode)); + ExtendedDataReceived?.Invoke(this, new ChannelExtendedDataEventArgs(LocalChannelNumber, data, dataTypeCode)); } /// @@ -387,9 +397,7 @@ protected virtual void OnEof() { _eofMessageReceived = true; - var endOfData = EndOfData; - if (endOfData != null) - endOfData(this, new ChannelEventArgs(LocalChannelNumber)); + EndOfData?.Invoke(this, new ChannelEventArgs(LocalChannelNumber)); } /// @@ -404,7 +412,9 @@ protected virtual void OnClose() // be blocked waiting for this signal. var channelClosedWaitHandle = _channelClosedWaitHandle; if (channelClosedWaitHandle != null) - channelClosedWaitHandle.Set(); + { + _ = channelClosedWaitHandle.Set(); + } // close the channel Close(); @@ -416,19 +426,15 @@ protected virtual void OnClose() /// Channel request information. protected virtual void OnRequest(RequestInfo info) { - var requestReceived = RequestReceived; - if (requestReceived != null) - requestReceived(this, new ChannelRequestEventArgs(info)); + RequestReceived?.Invoke(this, new ChannelRequestEventArgs(info)); } /// - /// Called when channel request was successful + /// Called when channel request was successful. /// protected virtual void OnSuccess() { - var requestSuccessed = RequestSucceeded; - if (requestSuccessed != null) - requestSuccessed(this, new ChannelEventArgs(LocalChannelNumber)); + RequestSucceeded?.Invoke(this, new ChannelEventArgs(LocalChannelNumber)); } /// @@ -436,24 +442,16 @@ protected virtual void OnSuccess() /// protected virtual void OnFailure() { - var requestFailed = RequestFailed; - if (requestFailed != null) - requestFailed(this, new ChannelEventArgs(LocalChannelNumber)); + RequestFailed?.Invoke(this, new ChannelEventArgs(LocalChannelNumber)); } - #endregion // Channel virtual methods - /// /// Raises event. /// /// The exception. private void RaiseExceptionEvent(Exception exception) { - var handlers = Exception; - if (handlers != null) - { - handlers(this, new ExceptionEventArgs(exception)); - } + Exception?.Invoke(this, new ExceptionEventArgs(exception)); } /// @@ -479,9 +477,11 @@ private bool TrySendMessage(Message message) /// The message. protected void SendMessage(Message message) { - // send channel messages only while channel is open + // Send channel messages only while channel is open if (!IsOpen) + { return; + } _session.SendMessage(message); } @@ -493,7 +493,9 @@ protected void SendMessage(Message message) public void SendEof() { if (!IsOpen) + { throw CreateChannelClosedException(); + } lock (this) { @@ -516,14 +518,16 @@ protected void WaitOnHandle(WaitHandle waitHandle) /// protected virtual void Close() { - // synchronize sending SSH_MSG_CHANNEL_EOF and SSH_MSG_CHANNEL_CLOSE to ensure that these messages - // are sent in that other; when both the client and the server attempt to close the channel at the - // same time we would otherwise risk sending the SSH_MSG_CHANNEL_EOF after the SSH_MSG_CHANNEL_CLOSE - // message causing the server to disconnect the session. + /* + * Synchronize sending SSH_MSG_CHANNEL_EOF and SSH_MSG_CHANNEL_CLOSE to ensure that these messages + * are sent in that other; when both the client and the server attempt to close the channel at the + * same time we would otherwise risk sending the SSH_MSG_CHANNEL_EOF after the SSH_MSG_CHANNEL_CLOSE + * message causing the server to disconnect the session. + */ lock (this) { - // send EOF message first the following conditions are met: + // Send EOF message first the following conditions are met: // * we have not sent a SSH_MSG_CHANNEL_EOF message // * remote party has not already sent a SSH_MSG_CHANNEL_EOF message // * remote party has not already sent a SSH_MSG_CHANNEL_CLOSE message @@ -565,11 +569,7 @@ protected virtual void Close() if (_closeMessageReceived) { // raise event signaling that both ends of the channel have been closed - var closed = Closed; - if (closed != null) - { - closed(this, new ChannelEventArgs(LocalChannelNumber)); - } + Closed?.Invoke(this, new ChannelEventArgs(LocalChannelNumber)); } } } @@ -623,8 +623,6 @@ private void Session_ErrorOccured(object sender, ExceptionEventArgs e) } } - #region Channel message event handlers - private void OnChannelWindowAdjust(object sender, MessageEventArgs e) { if (e.Message.LocalChannelNumber == LocalChannelNumber) @@ -706,14 +704,13 @@ private void OnChannelRequest(object sender, MessageEventArgs /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { - if (_isDisposed) - return; - - if (disposing) + if (!_isDisposed && disposing) { Close(); @@ -876,14 +866,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~Channel() { - Dispose(false); + Dispose(disposing: false); } - - #endregion // IDisposable Members } } diff --git a/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs b/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs index b6ba7a0ba..374272b29 100644 --- a/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs +++ b/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs @@ -15,13 +15,13 @@ internal class ChannelDirectTcpip : ClientChannel, IChannelDirectTcpip { private readonly object _socketLock = new object(); - private EventWaitHandle _channelOpen = new AutoResetEvent(false); - private EventWaitHandle _channelData = new AutoResetEvent(false); + private EventWaitHandle _channelOpen = new AutoResetEvent(initialState: false); + private EventWaitHandle _channelData = new AutoResetEvent(initialState: false); private IForwardedPort _forwardedPort; private Socket _socket; /// - /// Initializes a new instance. + /// Initializes a new instance of the class. /// /// The session. /// The local channel number. @@ -46,9 +46,14 @@ public override ChannelTypes ChannelType public void Open(string remoteHost, uint port, IForwardedPort forwardedPort, Socket socket) { if (IsOpen) + { throw new SshException("Channel is already open."); + } + if (!IsConnected) + { throw new SshException("Session is not connected."); + } _socket = socket; _forwardedPort = forwardedPort; @@ -56,10 +61,13 @@ public void Open(string remoteHost, uint port, IForwardedPort forwardedPort, Soc var ep = (IPEndPoint) socket.RemoteEndPoint; - // open channel - SendMessage(new ChannelOpenMessage(LocalChannelNumber, LocalWindowSize, LocalPacketSize, - new DirectTcpipChannelInfo(remoteHost, port, ep.Address.ToString(), (uint) ep.Port))); - // Wait for channel to open + // Open channel + SendMessage(new ChannelOpenMessage(LocalChannelNumber, + LocalWindowSize, + LocalPacketSize, + new DirectTcpipChannelInfo(remoteHost, port, ep.Address.ToString(), (uint) ep.Port))); + + // Wait for channel to open WaitOnHandle(_channelOpen); } @@ -82,9 +90,11 @@ private void ForwardedPort_Closing(object sender, EventArgs eventArgs) /// public void Bind() { - // Cannot bind if channel is not open + // Cannot bind if channel is not open if (!IsOpen) + { return; + } var buffer = new byte[RemotePacketSize]; @@ -104,12 +114,16 @@ public void Bind() private void CloseSocket() { if (_socket == null) + { return; + } lock (_socketLock) { if (_socket == null) + { return; + } // closing a socket actually disposes the socket, so we can safely dereference // the field to avoid entering the lock again later @@ -125,12 +139,16 @@ private void CloseSocket() private void ShutdownSocket(SocketShutdown how) { if (_socket == null) + { return; + } lock (_socketLock) { if (!_socket.IsConnected()) + { return; + } try { @@ -199,14 +217,14 @@ protected override void OnOpenConfirmation(uint remoteChannelNumber, uint initia { base.OnOpenConfirmation(remoteChannelNumber, initialWindowSize, maximumPacketSize); - _channelOpen.Set(); + _ = _channelOpen.Set(); } protected override void OnOpenFailure(uint reasonCode, string description, string language) { base.OnOpenFailure(reasonCode, description, language); - _channelOpen.Set(); + _ = _channelOpen.Set(); } /// diff --git a/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs b/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs index 7d731b9e5..321a00d02 100644 --- a/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs +++ b/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs @@ -120,13 +120,17 @@ private void ForwardedPort_Closing(object sender, EventArgs eventArgs) private void ShutdownSocket(SocketShutdown how) { if (_socket == null) + { return; + } lock (_socketShutdownAndCloseLock) { var socket = _socket; if (!socket.IsConnected()) + { return; + } try { @@ -146,7 +150,9 @@ private void ShutdownSocket(SocketShutdown how) private void CloseSocket() { if (_socket == null) + { return; + } lock (_socketShutdownAndCloseLock) { diff --git a/src/Renci.SshNet/Channels/ChannelSession.cs b/src/Renci.SshNet/Channels/ChannelSession.cs index 38e13096b..3b685c426 100644 --- a/src/Renci.SshNet/Channels/ChannelSession.cs +++ b/src/Renci.SshNet/Channels/ChannelSession.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Globalization; using System.Threading; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; @@ -13,7 +14,7 @@ namespace Renci.SshNet.Channels internal sealed class ChannelSession : ClientChannel, IChannelSession { /// - /// Counts failed channel open attempts + /// Counts failed channel open attempts. /// private int _failedOpenAttempts; @@ -28,16 +29,16 @@ internal sealed class ChannelSession : ClientChannel, IChannelSession private int _sessionSemaphoreObtained; /// - /// Wait handle to signal when response was received to open the channel + /// Wait handle to signal when response was received to open the channel. /// - private EventWaitHandle _channelOpenResponseWaitHandle = new AutoResetEvent(false); + private EventWaitHandle _channelOpenResponseWaitHandle = new AutoResetEvent(initialState: false); - private EventWaitHandle _channelRequestResponse = new ManualResetEvent(false); + private EventWaitHandle _channelRequestResponse = new ManualResetEvent(initialState: false); private bool _channelRequestSucces; /// - /// Initializes a new instance. + /// Initializes a new instance of the class. /// /// The session. /// The local channel number. @@ -64,7 +65,7 @@ public override ChannelTypes ChannelType /// public void Open() { - // Try to open channel several times + // Try to open channel several times while (!IsOpen && _failedOpenAttempts < ConnectionInfo.RetryAttempts) { SendChannelOpenMessage(); @@ -81,7 +82,9 @@ public void Open() } if (!IsOpen) + { throw new SshException(string.Format(CultureInfo.CurrentCulture, "Failed to open a channel after {0} attempts.", _failedOpenAttempts)); + } } /// @@ -93,7 +96,8 @@ public void Open() protected override void OnOpenConfirmation(uint remoteChannelNumber, uint initialWindowSize, uint maximumPacketSize) { base.OnOpenConfirmation(remoteChannelNumber, initialWindowSize, maximumPacketSize); - _channelOpenResponseWaitHandle.Set(); + + _ = _channelOpenResponseWaitHandle.Set(); } /// @@ -106,7 +110,7 @@ protected override void OnOpenFailure(uint reasonCode, string description, strin { _failedOpenAttempts++; ReleaseSemaphore(); - _channelOpenResponseWaitHandle.Set(); + _ = _channelOpenResponseWaitHandle.Set(); } protected override void Close() @@ -129,7 +133,7 @@ protected override void Close() /// public bool SendPseudoTerminalRequest(string environmentVariable, uint columns, uint rows, uint width, uint height, IDictionary terminalModeValues) { - _channelRequestResponse.Reset(); + _ = _channelRequestResponse.Reset(); SendMessage(new ChannelRequestMessage(RemoteChannelNumber, new PseudoTerminalRequestInfo(environmentVariable, columns, rows, width, height, terminalModeValues))); WaitOnHandle(_channelRequestResponse); return _channelRequestSucces; @@ -147,7 +151,7 @@ public bool SendPseudoTerminalRequest(string environmentVariable, uint columns, /// public bool SendX11ForwardingRequest(bool isSingleConnection, string protocol, byte[] cookie, uint screenNumber) { - _channelRequestResponse.Reset(); + _ = _channelRequestResponse.Reset(); SendMessage(new ChannelRequestMessage(RemoteChannelNumber, new X11ForwardingRequestInfo(isSingleConnection, protocol, cookie, screenNumber))); WaitOnHandle(_channelRequestResponse); return _channelRequestSucces; @@ -163,7 +167,7 @@ public bool SendX11ForwardingRequest(bool isSingleConnection, string protocol, b /// public bool SendEnvironmentVariableRequest(string variableName, string variableValue) { - _channelRequestResponse.Reset(); + _ = _channelRequestResponse.Reset(); SendMessage(new ChannelRequestMessage(RemoteChannelNumber, new EnvironmentVariableRequestInfo(variableName, variableValue))); WaitOnHandle(_channelRequestResponse); return _channelRequestSucces; @@ -177,7 +181,7 @@ public bool SendEnvironmentVariableRequest(string variableName, string variableV /// public bool SendShellRequest() { - _channelRequestResponse.Reset(); + _ = _channelRequestResponse.Reset(); SendMessage(new ChannelRequestMessage(RemoteChannelNumber, new ShellRequestInfo())); WaitOnHandle(_channelRequestResponse); return _channelRequestSucces; @@ -192,7 +196,7 @@ public bool SendShellRequest() /// public bool SendExecRequest(string command) { - _channelRequestResponse.Reset(); + _ = _channelRequestResponse.Reset(); SendMessage(new ChannelRequestMessage(RemoteChannelNumber, new ExecRequestInfo(command, ConnectionInfo.Encoding))); WaitOnHandle(_channelRequestResponse); return _channelRequestSucces; @@ -207,7 +211,7 @@ public bool SendExecRequest(string command) /// public bool SendBreakRequest(uint breakLength) { - _channelRequestResponse.Reset(); + _ = _channelRequestResponse.Reset(); SendMessage(new ChannelRequestMessage(RemoteChannelNumber, new BreakRequestInfo(breakLength))); WaitOnHandle(_channelRequestResponse); return _channelRequestSucces; @@ -222,7 +226,7 @@ public bool SendBreakRequest(uint breakLength) /// public bool SendSubsystemRequest(string subsystem) { - _channelRequestResponse.Reset(); + _ = _channelRequestResponse.Reset(); SendMessage(new ChannelRequestMessage(RemoteChannelNumber, new SubsystemRequestInfo(subsystem))); WaitOnHandle(_channelRequestResponse); return _channelRequestSucces; @@ -307,7 +311,7 @@ public bool SendExitSignalRequest(string signalName, bool coreDumped, string err /// public bool SendEndOfWriteRequest() { - _channelRequestResponse.Reset(); + _ = _channelRequestResponse.Reset(); SendMessage(new ChannelRequestMessage(RemoteChannelNumber, new EndOfWriteRequestInfo())); WaitOnHandle(_channelRequestResponse); return _channelRequestSucces; @@ -321,23 +325,21 @@ public bool SendEndOfWriteRequest() /// public bool SendKeepAliveRequest() { - _channelRequestResponse.Reset(); + _ = _channelRequestResponse.Reset(); SendMessage(new ChannelRequestMessage(RemoteChannelNumber, new KeepAliveRequestInfo())); WaitOnHandle(_channelRequestResponse); return _channelRequestSucces; } /// - /// Called when channel request was successful + /// Called when channel request was successful. /// protected override void OnSuccess() { base.OnSuccess(); - _channelRequestSucces = true; - var channelRequestResponse = _channelRequestResponse; - if (channelRequestResponse != null) - channelRequestResponse.Set(); + _channelRequestSucces = true; + _ = _channelRequestResponse?.Set(); } /// @@ -346,11 +348,9 @@ protected override void OnSuccess() protected override void OnFailure() { base.OnFailure(); - _channelRequestSucces = false; - var channelRequestResponse = _channelRequestResponse; - if (channelRequestResponse != null) - channelRequestResponse.Set(); + _channelRequestSucces = false; + _ = _channelRequestResponse?.Set(); } /// @@ -407,9 +407,9 @@ private void SendChannelOpenMessage() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// - /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + /// to release both managed and unmanaged resources; to release only unmanaged resources. protected override void Dispose(bool disposing) { base.Dispose(disposing); @@ -442,7 +442,9 @@ protected override void Dispose(bool disposing) private void ReleaseSemaphore() { if (Interlocked.CompareExchange(ref _sessionSemaphoreObtained, 0, 1) == 1) - SessionSemaphore.Release(); + { + _ = SessionSemaphore.Release(); + } } } } diff --git a/src/Renci.SshNet/Channels/ClientChannel.cs b/src/Renci.SshNet/Channels/ClientChannel.cs index 844c18660..1ec03c6bc 100644 --- a/src/Renci.SshNet/Channels/ClientChannel.cs +++ b/src/Renci.SshNet/Channels/ClientChannel.cs @@ -7,7 +7,7 @@ namespace Renci.SshNet.Channels internal abstract class ClientChannel : Channel { /// - /// Initializes a new instance. + /// Initializes a new instance of the class. /// /// The session. /// The local channel number. @@ -43,9 +43,7 @@ protected virtual void OnOpenConfirmation(uint remoteChannelNumber, uint initial // Channel is consider to be open when confirmation message was received IsOpen = true; - var openConfirmed = OpenConfirmed; - if (openConfirmed != null) - openConfirmed(this, new ChannelOpenConfirmedEventArgs(remoteChannelNumber, initialWindowSize, maximumPacketSize)); + OpenConfirmed?.Invoke(this, new ChannelOpenConfirmedEventArgs(remoteChannelNumber, initialWindowSize, maximumPacketSize)); } /// @@ -68,9 +66,7 @@ protected void SendMessage(ChannelOpenMessage message) /// The language. protected virtual void OnOpenFailure(uint reasonCode, string description, string language) { - var openFailed = OpenFailed; - if (openFailed != null) - openFailed(this, new ChannelOpenFailedEventArgs(LocalChannelNumber, reasonCode, description, language)); + OpenFailed?.Invoke(this, new ChannelOpenFailedEventArgs(LocalChannelNumber, reasonCode, description, language)); } private void OnChannelOpenConfirmation(object sender, MessageEventArgs e) @@ -79,8 +75,9 @@ private void OnChannelOpenConfirmation(object sender, MessageEventArgs - /// Initializes a new instance. + /// Initializes a new instance of the class. /// /// The session. /// The local channel number. @@ -14,7 +14,13 @@ internal abstract class ServerChannel : Channel /// The remote channel number. /// The window size of the remote party. /// The maximum size of a data packet that we can send to the remote party. - protected ServerChannel(ISession session, uint localChannelNumber, uint localWindowSize, uint localPacketSize, uint remoteChannelNumber, uint remoteWindowSize, uint remotePacketSize) + protected ServerChannel(ISession session, + uint localChannelNumber, + uint localWindowSize, + uint localPacketSize, + uint remoteChannelNumber, + uint remoteWindowSize, + uint remotePacketSize) : base(session, localChannelNumber, localWindowSize, localPacketSize) { InitializeRemoteInfo(remoteChannelNumber, remoteWindowSize, remotePacketSize); @@ -22,10 +28,10 @@ protected ServerChannel(ISession session, uint localChannelNumber, uint localWin protected void SendMessage(ChannelOpenConfirmationMessage message) { - // No need to check whether channel is open when trying to open a channel + // No need to check whether channel is open when trying to open a channel Session.SendMessage(message); - // When we act as server, consider the channel open when we've sent the + // When we act as server, consider the channel open when we've sent the // confirmation message to the peer IsOpen = true; } diff --git a/src/Renci.SshNet/CipherInfo.cs b/src/Renci.SshNet/CipherInfo.cs index 2641437b0..81e5e0689 100644 --- a/src/Renci.SshNet/CipherInfo.cs +++ b/src/Renci.SshNet/CipherInfo.cs @@ -30,7 +30,7 @@ public class CipherInfo public CipherInfo(int keySize, Func cipher) { KeySize = keySize; - Cipher = (key, iv) => (cipher(key.Take(KeySize / 8), iv)); + Cipher = (key, iv) => cipher(key.Take(KeySize / 8), iv); } } } diff --git a/src/Renci.SshNet/ClientAuthentication.cs b/src/Renci.SshNet/ClientAuthentication.cs index f0b31f872..a8a6745e2 100644 --- a/src/Renci.SshNet/ClientAuthentication.cs +++ b/src/Renci.SshNet/ClientAuthentication.cs @@ -9,14 +9,16 @@ internal class ClientAuthentication : IClientAuthentication private readonly int _partialSuccessLimit; /// - /// Initializes a new instance. + /// Initializes a new instance of the class. /// /// The number of times an authentication attempt with any given can result in before it is disregarded. /// is less than one. public ClientAuthentication(int partialSuccessLimit) { if (partialSuccessLimit < 1) - throw new ArgumentOutOfRangeException("partialSuccessLimit", "Cannot be less than one."); + { + throw new ArgumentOutOfRangeException(nameof(partialSuccessLimit), "Cannot be less than one."); + } _partialSuccessLimit = partialSuccessLimit; } @@ -43,9 +45,14 @@ internal int PartialSuccessLimit public void Authenticate(IConnectionInfoInternal connectionInfo, ISession session) { if (connectionInfo == null) - throw new ArgumentNullException("connectionInfo"); + { + throw new ArgumentNullException(nameof(connectionInfo)); + } + if (session == null) - throw new ArgumentNullException("session"); + { + throw new ArgumentNullException(nameof(session)); + } session.RegisterMessage("SSH_MSG_USERAUTH_FAILURE"); session.RegisterMessage("SSH_MSG_USERAUTH_SUCCESS"); @@ -122,6 +129,7 @@ private bool TryAuthenticate(ISession session, { authenticationResult = AuthenticationResult.Success; } + break; case AuthenticationResult.Failure: authenticationState.RecordFailure(authenticationMethod); @@ -133,7 +141,9 @@ private bool TryAuthenticate(ISession session, } if (authenticationResult == AuthenticationResult.Success) + { return true; + } } return false; @@ -181,8 +191,7 @@ public void RecordFailure(IAuthenticationMethod authenticationMethod) /// An for which to record the result of an authentication attempt. public void RecordPartialSuccess(IAuthenticationMethod authenticationMethod) { - int partialSuccessCount; - if (_authenticationMethodPartialSuccessRegister.TryGetValue(authenticationMethod, out partialSuccessCount)) + if (_authenticationMethodPartialSuccessRegister.TryGetValue(authenticationMethod, out var partialSuccessCount)) { _authenticationMethodPartialSuccessRegister[authenticationMethod] = ++partialSuccessCount; } @@ -203,11 +212,11 @@ public void RecordPartialSuccess(IAuthenticationMethod authenticationMethod) /// public int GetPartialSuccessCount(IAuthenticationMethod authenticationMethod) { - int partialSuccessCount; - if (_authenticationMethodPartialSuccessRegister.TryGetValue(authenticationMethod, out partialSuccessCount)) + if (_authenticationMethodPartialSuccessRegister.TryGetValue(authenticationMethod, out var partialSuccessCount)) { return partialSuccessCount; } + return 0; } @@ -270,7 +279,9 @@ public IEnumerable GetActiveAuthenticationMethods(List GetActiveAuthenticationMethods(List - /// Provides additional information for asynchronous command execution + /// Provides additional information for asynchronous command execution. /// public class CommandAsyncResult : IAsyncResult { @@ -27,8 +27,6 @@ internal CommandAsyncResult() /// Total bytes sent. public int BytesSent { get; set; } - #region IAsyncResult Members - /// /// Gets a user-defined object that qualifies or contains information about an asynchronous operation. /// @@ -36,27 +34,31 @@ internal CommandAsyncResult() public object AsyncState { get; internal set; } /// - /// Gets a that is used to wait for an asynchronous operation to complete. + /// 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. + /// + /// A that is used to wait for an asynchronous operation to complete. + /// public WaitHandle AsyncWaitHandle { get; internal set; } /// - /// Gets a value that indicates whether the asynchronous operation completed synchronously. + /// Gets a value indicating whether the asynchronous operation completed synchronously. /// - /// true if the asynchronous operation completed synchronously; otherwise, false. + /// + /// true if the asynchronous operation completed synchronously; otherwise, false. + /// public bool CompletedSynchronously { get; internal set; } /// - /// Gets a value that indicates whether the asynchronous operation has completed. + /// Gets a value indicating whether the asynchronous operation has completed. /// - /// true if the operation is complete; otherwise, false. + /// + /// true if the operation is complete; otherwise, false. + /// public bool IsCompleted { get; internal set; } - #endregion - /// - /// Gets a value indicating whether was already called for this + /// Gets or sets a value indicating whether was already called for this /// . /// /// diff --git a/src/Renci.SshNet/Common/AsyncResult.cs b/src/Renci.SshNet/Common/AsyncResult.cs index 3466a030b..ec103552e 100644 --- a/src/Renci.SshNet/Common/AsyncResult.cs +++ b/src/Renci.SshNet/Common/AsyncResult.cs @@ -8,36 +8,18 @@ namespace Renci.SshNet.Common /// public abstract class AsyncResult : IAsyncResult { - // Fields set at construction which never change while operation is pending - private readonly AsyncCallback _asyncCallback; - - private readonly object _asyncState; - - // Field set at construction which do change after operation completes private const int StatePending = 0; private const int StateCompletedSynchronously = 1; private const int StateCompletedAsynchronously = 2; + private readonly AsyncCallback _asyncCallback; + private readonly object _asyncState; private int _completedState = StatePending; - - // Field that may or may not get set depending on usage private ManualResetEvent _asyncWaitHandle; - - // Fields set when operation completes private Exception _exception; - /// - /// Gets or sets a value indicating whether has been called on the current - /// . - /// - /// - /// true if has been called on the current ; - /// otherwise, false. - /// - public bool EndInvokeCalled { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -49,37 +31,43 @@ protected AsyncResult(AsyncCallback asyncCallback, object state) _asyncState = state; } + /// + /// Gets a value indicating whether has been called on the current . + /// + /// + /// true if has been called on the current ; + /// otherwise, false. + /// + public bool EndInvokeCalled { get; private set; } + /// /// Marks asynchronous operation as completed. /// /// The exception. - /// if set to true [completed synchronously]. + /// If set to , completed synchronously. public void SetAsCompleted(Exception exception, bool completedSynchronously) { // Passing null for exception means no error occurred; this is the common case _exception = exception; - // The m_CompletedState field MUST be set prior calling the callback + // The '_completedState' field MUST be set prior calling the callback var prevState = Interlocked.Exchange(ref _completedState, - completedSynchronously ? StateCompletedSynchronously : StateCompletedAsynchronously); + completedSynchronously ? StateCompletedSynchronously : StateCompletedAsynchronously); + if (prevState != StatePending) + { throw new InvalidOperationException("You can set a result only once"); + } // If the event exists, set it - if (_asyncWaitHandle != null) - { - _asyncWaitHandle.Set(); - } + _ = _asyncWaitHandle?.Set(); // If a callback method was set, call it - if (_asyncCallback != null) - { - _asyncCallback(this); - } + _asyncCallback?.Invoke(this); } /// - /// Waits until the asynchronous operation completes, and then returns. + /// Waits until the asynchronous operation completes, and then returns. /// internal void EndInvoke() { @@ -87,7 +75,7 @@ internal void EndInvoke() if (!IsCompleted) { // If the operation isn't done, wait for it - AsyncWaitHandle.WaitOne(); + _ = AsyncWaitHandle.WaitOne(); _asyncWaitHandle = null; // Allow early GC AsyncWaitHandle.Dispose(); } @@ -96,21 +84,28 @@ internal void EndInvoke() // Operation is done: if an exception occurred, throw it if (_exception != null) + { throw _exception; + } } - #region Implementation of IAsyncResult - /// /// 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; } } + /// + /// A user-defined object that qualifies or contains information about an asynchronous operation. + /// + public object AsyncState + { + get { return _asyncState; } + } /// - /// Gets a value that indicates whether the asynchronous operation completed synchronously. + /// Gets a value indicating whether the asynchronous operation completed synchronously. /// - /// true if the asynchronous operation completed synchronously; otherwise, false. + /// + /// if the asynchronous operation completed synchronously; otherwise, . + /// public bool CompletedSynchronously { get { return _completedState == StateCompletedSynchronously; } @@ -119,7 +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. + /// + /// A that is used to wait for an asynchronous operation to complete. + /// public WaitHandle AsyncWaitHandle { get @@ -128,7 +125,7 @@ public WaitHandle AsyncWaitHandle { var done = IsCompleted; var mre = new ManualResetEvent(done); - if (Interlocked.CompareExchange(ref _asyncWaitHandle, mre, null) != null) + if (Interlocked.CompareExchange(ref _asyncWaitHandle, mre, comparand: null) != null) { // Another thread created this object's event; dispose the event we just created mre.Dispose(); @@ -137,27 +134,26 @@ public WaitHandle AsyncWaitHandle { if (!done && IsCompleted) { - // If the operation wasn't done when we created - // the event but now it is done, set the event - _asyncWaitHandle.Set(); + // If the operation wasn't done when we created the event but now it is done, set the event + _ = _asyncWaitHandle.Set(); } } } + return _asyncWaitHandle; } } /// - /// Gets a value that indicates whether the asynchronous operation has completed. + /// Gets a value indicating whether the asynchronous operation has completed. /// /// - /// true if the operation is complete; otherwise, false. + /// if the operation is complete; otherwise, . + /// public bool IsCompleted { get { return _completedState != StatePending; } } - - #endregion } /// @@ -190,7 +186,7 @@ public void SetAsCompleted(TResult result, bool completedSynchronously) _result = result; // Tell the base class that the operation completed successfully (no exception) - SetAsCompleted(null, completedSynchronously); + SetAsCompleted(exception: null, completedSynchronously); } /// @@ -201,8 +197,8 @@ public void SetAsCompleted(TResult result, bool completedSynchronously) /// public new TResult EndInvoke() { - base.EndInvoke(); // Wait until operation has completed + base.EndInvoke(); // Wait until operation has completed return _result; // Return the result (if above didn't throw) } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Common/AuthenticationBannerEventArgs.cs b/src/Renci.SshNet/Common/AuthenticationBannerEventArgs.cs index 308105d4c..790ba034a 100644 --- a/src/Renci.SshNet/Common/AuthenticationBannerEventArgs.cs +++ b/src/Renci.SshNet/Common/AuthenticationBannerEventArgs.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet.Common { /// - /// Provides data for event. + /// Provides data for event. /// public class AuthenticationBannerEventArgs : AuthenticationEventArgs { diff --git a/src/Renci.SshNet/Common/AuthenticationEventArgs.cs b/src/Renci.SshNet/Common/AuthenticationEventArgs.cs index dfeadbcc1..4546d318f 100644 --- a/src/Renci.SshNet/Common/AuthenticationEventArgs.cs +++ b/src/Renci.SshNet/Common/AuthenticationEventArgs.cs @@ -7,11 +7,6 @@ namespace Renci.SshNet.Common /// public abstract class AuthenticationEventArgs : EventArgs { - /// - /// Gets the username. - /// - public string Username { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -20,5 +15,10 @@ protected AuthenticationEventArgs(string username) { Username = username; } + + /// + /// Gets the username. + /// + public string Username { get; } } } diff --git a/src/Renci.SshNet/Common/AuthenticationPasswordChangeEventArgs.cs b/src/Renci.SshNet/Common/AuthenticationPasswordChangeEventArgs.cs index f6d829123..f4b4a3d8e 100644 --- a/src/Renci.SshNet/Common/AuthenticationPasswordChangeEventArgs.cs +++ b/src/Renci.SshNet/Common/AuthenticationPasswordChangeEventArgs.cs @@ -1,18 +1,10 @@ 锘縩amespace Renci.SshNet.Common { /// - /// Provides data for event. + /// Provides data for event. /// public class AuthenticationPasswordChangeEventArgs : AuthenticationEventArgs { - /// - /// Gets or sets the new password. - /// - /// - /// The new password. - /// - public byte[] NewPassword { get; set; } - /// /// Initializes a new instance of the class. /// @@ -21,5 +13,13 @@ public AuthenticationPasswordChangeEventArgs(string username) : base(username) { } + + /// + /// Gets or sets the new password. + /// + /// + /// The new password. + /// + public byte[] NewPassword { get; set; } } } diff --git a/src/Renci.SshNet/Common/AuthenticationPrompt.cs b/src/Renci.SshNet/Common/AuthenticationPrompt.cs index 15d7a982c..5a7a9688b 100644 --- a/src/Renci.SshNet/Common/AuthenticationPrompt.cs +++ b/src/Renci.SshNet/Common/AuthenticationPrompt.cs @@ -1,27 +1,40 @@ 锘縩amespace Renci.SshNet.Common { /// - /// Provides prompt information when is raised + /// Provides prompt information when is raised. /// public class AuthenticationPrompt { + /// + /// Initializes a new instance of the class. + /// + /// The sequence id. + /// if set to true the user input should be echoed. + /// The request. + public AuthenticationPrompt(int id, bool isEchoed, string request) + { + Id = id; + IsEchoed = isEchoed; + Request = request; + } + /// /// Gets the prompt sequence id. /// - public int Id { get; private set; } + public int Id { get; } /// - /// Gets or sets a value indicating whether the user input should be echoed as characters are typed. + /// Gets a value indicating whether the user input should be echoed as characters are typed. /// /// /// true if the user input should be echoed as characters are typed; otherwise, false. /// - public bool IsEchoed { get; private set; } + public bool IsEchoed { get; } /// /// Gets server information request. /// - public string Request { get; private set; } + public string Request { get; } /// /// Gets or sets server information response. @@ -30,18 +43,5 @@ public class AuthenticationPrompt /// The response. /// public string Response { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The sequence id. - /// if set to true the user input should be echoed. - /// The request. - public AuthenticationPrompt(int id, bool isEchoed, string request) - { - Id = id; - IsEchoed = isEchoed; - Request = request; - } } } diff --git a/src/Renci.SshNet/Common/AuthenticationPromptEventArgs.cs b/src/Renci.SshNet/Common/AuthenticationPromptEventArgs.cs index 9e2207289..9c22c340c 100644 --- a/src/Renci.SshNet/Common/AuthenticationPromptEventArgs.cs +++ b/src/Renci.SshNet/Common/AuthenticationPromptEventArgs.cs @@ -3,25 +3,10 @@ namespace Renci.SshNet.Common { /// - /// Provides data for event. + /// Provides data for event. /// public class AuthenticationPromptEventArgs : AuthenticationEventArgs { - /// - /// Gets prompt language. - /// - public string Language { get; private set; } - - /// - /// Gets prompt instruction. - /// - public string Instruction { get; private set; } - - /// - /// Gets server information request prompts. - /// - public IEnumerable Prompts { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -36,5 +21,20 @@ public AuthenticationPromptEventArgs(string username, string instruction, string Language = language; Prompts = prompts; } + + /// + /// Gets prompt language. + /// + public string Language { get; } + + /// + /// Gets prompt instruction. + /// + public string Instruction { get; } + + /// + /// Gets server information request prompts. + /// + public IEnumerable Prompts { get; } } } diff --git a/src/Renci.SshNet/Common/BigInteger.cs b/src/Renci.SshNet/Common/BigInteger.cs index 611b74dde..8e8f7b514 100644 --- a/src/Renci.SshNet/Common/BigInteger.cs +++ b/src/Renci.SshNet/Common/BigInteger.cs @@ -2,8 +2,8 @@ // System.Numerics.BigInteger // // Authors: -// Rodrigo Kumpera (rkumpera@novell.com) -// Marek Safar +// Rodrigo Kumpera (rkumpera@novell.com) +// Marek Safar // // Copyright (C) 2010 Novell, Inc (http://www.novell.com) // Copyright (C) 2014 Xamarin Inc (http://www.xamarin.com) @@ -44,46 +44,39 @@ * * * ***************************************************************************/ -// -// slashdocs based on MSDN using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using System.Globalization; + using Renci.SshNet.Abstractions; /* -Optimization - Have proper popcount function for IsPowerOfTwo - Use unsafe ops to avoid bounds check - CoreAdd could avoid some resizes by checking for equal sized array that top overflow - For bitwise operators, hoist the conditionals out of their main loop - Optimize BitScanBackward - Use a carry variable to make shift opts do half the number of array ops. - Schoolbook multiply is O(n^2), use Karatsuba /Toom-3 for large numbers -*/ + * Optimization: + * - Have proper popcount function for IsPowerOfTwo + * - Use unsafe ops to avoid bounds check + * - CoreAdd could avoid some resizes by checking for equal sized array that top overflow + * - For bitwise operators, hoist the conditionals out of their main loop + * - Optimize BitScanBackward + * - Use a carry variable to make shift opts do half the number of array ops. + * -Schoolbook multiply is O(n^2), use Karatsuba /Toom-3 for large numbers + */ namespace Renci.SshNet.Common { /// /// Represents an arbitrarily large signed integer. /// - [SuppressMessage("ReSharper", "EmptyEmbeddedStatement")] - [SuppressMessage("ReSharper", "RedundantCast")] - [SuppressMessage("ReSharper", "RedundantAssignment")] - [SuppressMessage("ReSharper", "SuggestBaseTypeForParameter")] - [SuppressMessage("ReSharper", "MergeConditionalExpression")] public struct BigInteger : IComparable, IFormattable, IComparable, IEquatable { + private const ulong Base = 0x100000000; + private const int Bias = 1075; + private const int DecimalSignMask = unchecked((int)0x80000000); + private static readonly BigInteger ZeroSingleton = new BigInteger(0); private static readonly BigInteger OneSingleton = new BigInteger(1); private static readonly BigInteger MinusOneSingleton = new BigInteger(-1); - private const ulong Base = 0x100000000; - private const int Bias = 1075; - private const int DecimalSignMask = unchecked((int) 0x80000000); - - //LSB on [0] + // LSB on [0] private readonly uint[] _data; private readonly short _sign; @@ -95,17 +88,21 @@ public struct BigInteger : IComparable, IFormattable, IComparable, I /// /// The number of the bit used. /// - public int BitLength + public readonly int BitLength { get { if (_sign == 0) + { return 0; + } var msbIndex = _data.Length - 1; while (_data[msbIndex] == 0) + { msbIndex--; + } var msbBitCount = BitScanBackward(_data[msbIndex]) + 1; @@ -129,16 +126,22 @@ public static BigInteger ModInverse(BigInteger bi, BigInteger modulus) while (!b.IsZero) { if (b.IsOne) + { return p1; + } p0 += (a / b) * p1; a %= b; if (a.IsZero) + { break; + } if (a.IsOne) + { return modulus - p0; + } p1 += (b / a) * p0; b %= a; @@ -158,8 +161,11 @@ public static BigInteger ModInverse(BigInteger bi, BigInteger modulus) public static BigInteger PositiveMod(BigInteger dividend, BigInteger divisor) { var result = dividend % divisor; + if (result < 0) + { result += divisor; + } return result; } @@ -171,9 +177,9 @@ public static BigInteger PositiveMod(BigInteger dividend, BigInteger divisor) /// A random number of the specified length. public static BigInteger Random(int bitLength) { - var bytesArray = new byte[bitLength / 8 + (((bitLength % 8) > 0) ? 1 : 0)]; + var bytesArray = new byte[(bitLength / 8) + (((bitLength % 8) > 0) ? 1 : 0)]; CryptoAbstraction.GenerateRandom(bytesArray); - bytesArray[bytesArray.Length - 1] = (byte) (bytesArray[bytesArray.Length - 1] & 0x7F); // Ensure not a negative value + bytesArray[bytesArray.Length - 1] = (byte) (bytesArray[bytesArray.Length - 1] & 0x7F); // Ensure not a negative value return new BigInteger(bytesArray); } @@ -199,12 +205,12 @@ public BigInteger(int value) else if (value > 0) { _sign = 1; - _data = new[] {(uint) value}; + _data = new[] { (uint) value }; } else { _sign = -1; - _data = new[] {(uint) -value}; + _data = new[] { (uint) -value }; } } @@ -247,7 +253,9 @@ public BigInteger(long value) _data = new uint[high != 0 ? 2 : 1]; _data[0] = low; if (high != 0) + { _data[1] = high; + } } else { @@ -259,7 +267,9 @@ public BigInteger(long value) _data = new uint[high != 0 ? 2 : 1]; _data[0] = low; if (high != 0) + { _data[1] = high; + } } } @@ -290,7 +300,7 @@ public BigInteger(ulong value) private static bool Negative(byte[] v) { - return ((v[7] & 0x80) != 0); + return (v[7] & 0x80) != 0; } private static ushort Exponent(byte[] v) @@ -300,8 +310,8 @@ private static ushort Exponent(byte[] v) private static ulong Mantissa(byte[] v) { - var i1 = ((uint)v[0] | ((uint)v[1] << 8) | ((uint)v[2] << 16) | ((uint)v[3] << 24)); - var i2 = ((uint)v[4] | ((uint)v[5] << 8) | ((uint)(v[6] & 0xF) << 16)); + var i1 = (uint)v[0] | ((uint)v[1] << 8) | ((uint)v[2] << 16) | ((uint)v[3] << 24); + var i2 = (uint)v[4] | ((uint)v[5] << 8) | ((uint)(v[6] & 0xF) << 16); return (ulong)((ulong)i1 | ((ulong)i2 << 32)); } @@ -313,7 +323,9 @@ private static ulong Mantissa(byte[] v) public BigInteger(double value) { if (double.IsNaN(value) || double.IsInfinity(value)) + { throw new OverflowException(); + } var bytes = BitConverter.GetBytes(value); var mantissa = Mantissa(bytes); @@ -329,7 +341,7 @@ public BigInteger(double value) } var res = Negative(bytes) ? MinusOne : One; - res = res << (exponent - 0x3ff); + res <<= exponent - 0x3ff; _sign = res._sign; _data = res._data; } @@ -350,7 +362,8 @@ public BigInteger(double value) /// Initializes a new instance of the structure using a single-precision floating-point value. /// /// A single-precision floating-point value. - public BigInteger(float value) : this((double)value) + public BigInteger(float value) + : this((double)value) { } @@ -378,9 +391,14 @@ public BigInteger(decimal value) _data = new uint[size]; _data[0] = (uint)bits[0]; if (size > 1) - _data[1] = (uint)bits[1]; + { + _data[1] = (uint) bits[1]; + } + if (size > 2) - _data[2] = (uint)bits[2]; + { + _data[2] = (uint) bits[2]; + } } /// @@ -392,7 +410,9 @@ public BigInteger(decimal value) public BigInteger(byte[] value) { if (value == null) - throw new ArgumentNullException("value"); + { + throw new ArgumentNullException(nameof(value)); + } var len = value.Length; @@ -404,9 +424,13 @@ public BigInteger(byte[] value) } if ((value[len - 1] & 0x80) != 0) + { _sign = -1; + } else + { _sign = 1; + } if (_sign == 1) { @@ -423,7 +447,9 @@ public BigInteger(byte[] value) int size; var fullWords = size = len / 4; if ((len & 0x3) != 0) + { ++size; + } _data = new uint[size]; var j = 0; @@ -434,12 +460,15 @@ public BigInteger(byte[] value) (uint) (value[j++] << 16) | (uint) (value[j++] << 24); } + size = len & 0x3; if (size > 0) { var idx = _data.Length - 1; for (var i = 0; i < size; ++i) - _data[idx] |= (uint)(value[j++] << (i * 8)); + { + _data[idx] |= (uint) (value[j++] << (i * 8)); + } } } else @@ -447,7 +476,9 @@ public BigInteger(byte[] value) int size; var fullWords = size = len / 4; if ((len & 0x3) != 0) + { ++size; + } _data = new uint[size]; @@ -467,6 +498,7 @@ public BigInteger(byte[] value) borrow = (uint)(sub >> 32) & 0x1u; _data[i] = ~word; } + size = len & 0x3; if (size > 0) @@ -484,54 +516,68 @@ public BigInteger(byte[] value) borrow = (uint)(sub >> 32) & 0x1u; if ((~word & storeMask) == 0) + { Array.Resize(ref _data, _data.Length - 1); + } else + { _data[_data.Length - 1] = ~word & storeMask; + } } - if (borrow != 0) //FIXME I believe this can't happen, can someone write a test for it? + + if (borrow != 0) + { + // FIXME I believe this can't happen, can someone write a test for it? throw new Exception("non zero final carry"); + } } } /// - /// Indicates whether the value of the current object is an even number. + /// Gets a value indicating whether the value of the current object is an even number. /// /// /// true if the value of the BigInteger object is an even number; otherwise, false. /// - public bool IsEven + public readonly bool IsEven { get { return _sign == 0 || (_data[0] & 0x1) == 0; } } /// - /// Indicates whether the value of the current object is . + /// Gets a value indicating whether the value of the current object is . /// /// /// true if the value of the object is ; /// otherwise, false. /// - public bool IsOne + public readonly bool IsOne { get { return _sign == 1 && _data.Length == 1 && _data[0] == 1; } } - - //Gem from Hacker's Delight - //Returns the number of bits set in @x - static int PopulationCount(uint x) + // Gem from Hacker's Delight + // Returns the number of bits set in @x + private static int PopulationCount(uint x) { - x = x - ((x >> 1) & 0x55555555); + x -= (x >> 1) & 0x55555555; x = (x & 0x33333333) + ((x >> 2) & 0x33333333); x = (x + (x >> 4)) & 0x0F0F0F0F; - x = x + (x >> 8); - x = x + (x >> 16); - return (int)(x & 0x0000003F); + x += x >> 8; + x += x >> 16; + return (int) (x & 0x0000003F); } - //Based on code by Zilong Tan on Ulib released under MIT license - //Returns the number of bits set in @x - static int PopulationCount(ulong x) + /// + /// Returns the number of bits set in . + /// + /// + /// The number of bits set in . + /// + /// + /// Based on code by Zilong Tan on Ulib released under MIT license. + /// + private static int PopulationCount(ulong x) { x -= (x >> 1) & 0x5555555555555555UL; x = (x & 0x3333333333333333UL) + ((x >> 2) & 0x3333333333333333UL); @@ -539,7 +585,7 @@ static int PopulationCount(ulong x) return (int)((x * 0x0101010101010101UL) >> 56); } - static int LeadingZeroCount(uint value) + private static int LeadingZeroCount(uint value) { value |= value >> 1; value |= value >> 2; @@ -549,7 +595,7 @@ static int LeadingZeroCount(uint value) return 32 - PopulationCount(value); // 32 = bits in uint } - static int LeadingZeroCount(ulong value) + private static int LeadingZeroCount(ulong value) { value |= value >> 1; value |= value >> 2; @@ -560,7 +606,7 @@ static int LeadingZeroCount(ulong value) return 64 - PopulationCount(value); // 64 = bits in ulong } - static double BuildDouble(int sign, ulong mantissa, int exponent) + private static double BuildDouble(int sign, ulong mantissa, int exponent) { const int exponentBias = 1023; const int mantissaLength = 52; @@ -581,6 +627,7 @@ static double BuildDouble(int sign, ulong mantissa, int exponent) { return sign > 0 ? double.PositiveInfinity : double.NegativeInfinity; } + if (offset < 0) { mantissa >>= -offset; @@ -596,7 +643,9 @@ static double BuildDouble(int sign, ulong mantissa, int exponent) mantissa <<= offset; exponent -= offset; } - mantissa = mantissa & mantissaMask; + + mantissa &= mantissaMask; + if ((exponent & exponentMask) == exponent) { unchecked @@ -606,49 +655,59 @@ static double BuildDouble(int sign, ulong mantissa, int exponent) { bits |= negativeMark; } + return BitConverter.Int64BitsToDouble((long)bits); } } + return sign > 0 ? double.PositiveInfinity : double.NegativeInfinity; } /// - /// Indicates whether the value of the current object is a power of two. + /// Gets a value Indicating whether the value of the current object is a power of two. /// /// /// true if the value of the object is a power of two; /// otherwise, false. /// - public bool IsPowerOfTwo + public readonly bool IsPowerOfTwo { get { - var foundBit = false; if (_sign != 1) + { return false; - //This function is pop count == 1 for positive numbers + } + + var foundBit = false; + + // This function is pop count == 1 for positive numbers foreach (var bit in _data) { var p = PopulationCount(bit); if (p > 0) { if (p > 1 || foundBit) + { return false; + } + foundBit = true; } } + return foundBit; } } /// - /// Indicates whether the value of the current object is . + /// Gets a value indicating whether the value of the current object is . /// /// /// true if the value of the object is ; /// otherwise, false. /// - public bool IsZero + public readonly bool IsZero { get { return _sign == 0; } } @@ -659,7 +718,7 @@ public bool IsZero /// /// A number that indicates the sign of the object. /// - public int Sign + public readonly int Sign { get { return _sign; } } @@ -707,21 +766,34 @@ public static BigInteger Zero public static explicit operator int(BigInteger value) { if (value._data == null) + { return 0; + } + if (value._data.Length > 1) + { throw new OverflowException(); + } + var data = value._data[0]; if (value._sign == 1) { - if (data > (uint)int.MaxValue) + if (data > (uint) int.MaxValue) + { throw new OverflowException(); + } + return (int)data; } + if (value._sign == -1) { if (data > 0x80000000u) + { throw new OverflowException(); + } + return -(int)data; } @@ -739,9 +811,15 @@ public static explicit operator int(BigInteger value) public static explicit operator uint(BigInteger value) { if (value._data == null) + { return 0; + } + if (value._data.Length > 1 || value._sign == -1) + { throw new OverflowException(); + } + return value._data[0]; } @@ -754,26 +832,32 @@ public static explicit operator uint(BigInteger value) /// public static explicit operator short(BigInteger value) { - var val = (int)value; - if (val < short.MinValue || val > short.MaxValue) + var val = (int) value; + if (val is < short.MinValue or > short.MaxValue) + { throw new OverflowException(); - return (short)val; + } + + return (short) val; } /// - /// + /// Defines an explicit conversion of a object to a 16-bit unsigned integer value. /// - /// + /// The value to convert to a 16-bit unsigned integer. /// /// An object that contains the value of the parameter. /// - [CLSCompliantAttribute(false)] + [CLSCompliant(false)] public static explicit operator ushort(BigInteger value) { - var val = (uint)value; + var val = (uint) value; if (val > ushort.MaxValue) + { throw new OverflowException(); - return (ushort)val; + } + + return (ushort) val; } /// @@ -785,10 +869,13 @@ public static explicit operator ushort(BigInteger value) /// public static explicit operator byte(BigInteger value) { - var val = (uint)value; + var val = (uint) value; if (val > byte.MaxValue) + { throw new OverflowException(); - return (byte)val; + } + + return (byte) val; } /// @@ -801,10 +888,13 @@ public static explicit operator byte(BigInteger value) [CLSCompliant(false)] public static explicit operator sbyte(BigInteger value) { - var val = (int)value; - if (val < sbyte.MinValue || val > sbyte.MaxValue) + var val = (int) value; + if (val is < sbyte.MinValue or > sbyte.MaxValue) + { throw new OverflowException(); - return (sbyte)val; + } + + return (sbyte) val; } /// @@ -817,17 +907,24 @@ public static explicit operator sbyte(BigInteger value) public static explicit operator long(BigInteger value) { if (value._data == null) + { return 0; + } if (value._data.Length > 2) + { throw new OverflowException(); + } var low = value._data[0]; if (value._data.Length == 1) { if (value._sign == 1) - return (long)low; + { + return (long) low; + } + var res = (long)low; return -res; } @@ -837,7 +934,10 @@ public static explicit operator long(BigInteger value) if (value._sign == 1) { if (high >= 0x80000000u) + { throw new OverflowException(); + } + return (((long)high) << 32) | low; } @@ -853,7 +953,10 @@ long.MinValue works fine since it's bigint encoding looks like a negative var result = -((((long)high) << 32) | (long)low); if (result > 0) + { throw new OverflowException(); + } + return result; } @@ -868,13 +971,20 @@ long.MinValue works fine since it's bigint encoding looks like a negative public static explicit operator ulong(BigInteger value) { if (value._data == null) + { return 0; + } + if (value._data.Length > 2 || value._sign == -1) + { throw new OverflowException(); + } var low = value._data[0]; if (value._data.Length == 1) + { return low; + } var high = value._data[1]; return (((ulong)high) << 32) | low; @@ -890,14 +1000,16 @@ public static explicit operator ulong(BigInteger value) public static explicit operator double(BigInteger value) { if (value._data == null) + { return 0.0; + } switch (value._data.Length) { case 1: return BuildDouble(value._sign, value._data[0], 0); case 2: - return BuildDouble(value._sign, (ulong)value._data[1] << 32 | (ulong)value._data[0], 0); + return BuildDouble(value._sign, (ulong) value._data[1] << 32 | (ulong) value._data[0], 0); default: var index = value._data.Length - 1; var word = value._data[index]; @@ -912,6 +1024,7 @@ public static explicit operator double(BigInteger value) { mantissa >>= -missing; } + return BuildDouble(value._sign, mantissa, ((value._data.Length - 2) * 32) - missing); } } @@ -925,7 +1038,7 @@ public static explicit operator double(BigInteger value) /// public static explicit operator float(BigInteger value) { - return (float)(double)value; + return (float) (double) value; } /// @@ -938,19 +1051,31 @@ public static explicit operator float(BigInteger value) public static explicit operator decimal(BigInteger value) { if (value._data == null) + { return decimal.Zero; + } var data = value._data; if (data.Length > 3) + { throw new OverflowException(); + } int lo = 0, mi = 0, hi = 0; if (data.Length > 2) - hi = (int)data[2]; + { + hi = (int) data[2]; + } + if (data.Length > 1) - mi = (int)data[1]; + { + mi = (int) data[1]; + } + if (data.Length > 0) - lo = (int)data[0]; + { + lo = (int) data[0]; + } return new decimal(lo, mi, hi, value._sign < 0, 0); } @@ -999,7 +1124,7 @@ public static implicit operator BigInteger(short value) /// /// An object that contains the value of the parameter. /// - [CLSCompliantAttribute(false)] + [CLSCompliant(false)] public static implicit operator BigInteger(ushort value) { return new BigInteger(value); @@ -1102,20 +1227,32 @@ public static explicit operator BigInteger(decimal value) public static BigInteger operator +(BigInteger left, BigInteger right) { if (left._sign == 0) + { return right; + } + if (right._sign == 0) + { return left; + } if (left._sign == right._sign) + { return new BigInteger(left._sign, CoreAdd(left._data, right._data)); + } var r = CoreCompare(left._data, right._data); if (r == 0) + { return Zero; + } - if (r > 0) //left > right + if (r > 0) + { + //left > right return new BigInteger(left._sign, CoreSub(left._data, right._data)); + } return new BigInteger(right._sign, CoreSub(right._data, left._data)); } @@ -1131,19 +1268,29 @@ public static explicit operator BigInteger(decimal value) public static BigInteger operator -(BigInteger left, BigInteger right) { if (right._sign == 0) + { return left; + } + if (left._sign == 0) - return new BigInteger((short)-right._sign, right._data); + { + return new BigInteger((short) -right._sign, right._data); + } if (left._sign == right._sign) { var r = CoreCompare(left._data, right._data); if (r == 0) + { return Zero; + } - if (r > 0) //left > right + if (r > 0) + { + // left > right return new BigInteger(left._sign, CoreSub(left._data, right._data)); + } return new BigInteger((short)-right._sign, CoreSub(right._data, left._data)); } @@ -1162,19 +1309,27 @@ public static explicit operator BigInteger(decimal value) public static BigInteger operator *(BigInteger left, BigInteger right) { if (left._sign == 0 || right._sign == 0) + { return Zero; + } if (left._data[0] == 1 && left._data.Length == 1) { if (left._sign == 1) + { return right; + } + return new BigInteger((short)-right._sign, right._data); } if (right._data[0] == 1 && right._data.Length == 1) { if (right._sign == 1) + { return left; + } + return new BigInteger((short)-left._sign, left._data); } @@ -1191,7 +1346,7 @@ public static explicit operator BigInteger(decimal value) ulong carry = 0; for (var j = 0; j < b.Length; ++j) { - carry = carry + ((ulong)ai) * b[j] + res[k]; + carry = carry + ((ulong) ai) * b[j] + res[k]; res[k++] = (uint)carry; carry >>= 32; } @@ -1206,8 +1361,11 @@ public static explicit operator BigInteger(decimal value) int m; for (m = res.Length - 1; m >= 0 && res[m] == 0; --m) ; + if (m < res.Length - 1) + { Array.Resize(ref res, m + 1); + } return new BigInteger((short) (left._sign*right._sign), res); } @@ -1224,22 +1382,29 @@ public static explicit operator BigInteger(decimal value) public static BigInteger operator /(BigInteger dividend, BigInteger divisor) { if (divisor._sign == 0) + { throw new DivideByZeroException(); + } if (dividend._sign == 0) + { return dividend; + } - uint[] quotient; - uint[] remainderValue; - - DivModUnsigned(dividend._data, divisor._data, out quotient, out remainderValue); + DivModUnsigned(dividend._data, divisor._data, out var quotient, out _); int i; for (i = quotient.Length - 1; i >= 0 && quotient[i] == 0; --i) ; + if (i == -1) + { return Zero; + } + if (i < quotient.Length - 1) + { Array.Resize(ref quotient, i + 1); + } return new BigInteger((short)(dividend._sign * divisor._sign), quotient); } @@ -1255,23 +1420,30 @@ public static explicit operator BigInteger(decimal value) public static BigInteger operator %(BigInteger dividend, BigInteger divisor) { if (divisor._sign == 0) + { throw new DivideByZeroException(); + } if (dividend._sign == 0) + { return dividend; + } - uint[] quotient; - uint[] remainderValue; - - DivModUnsigned(dividend._data, divisor._data, out quotient, out remainderValue); + DivModUnsigned(dividend._data, divisor._data, out _, out var remainderValue); int i; for (i = remainderValue.Length - 1; i >= 0 && remainderValue[i] == 0; --i) ; + if (i == -1) + { return Zero; + } if (i < remainderValue.Length - 1) + { Array.Resize(ref remainderValue, i + 1); + } + return new BigInteger(dividend._sign, remainderValue); } @@ -1279,14 +1451,17 @@ public static explicit operator BigInteger(decimal value) /// Negates a specified value. /// /// The value to negate. - /// + /// /// The result of the parameter multiplied by negative one (-1). /// public static BigInteger operator -(BigInteger value) { if (value._data == null) + { return value; - return new BigInteger((short)-value._sign, value._data); + } + + return new BigInteger((short) -value._sign, value._data); } /// @@ -1314,16 +1489,23 @@ public static explicit operator BigInteger(decimal value) public static BigInteger operator ++(BigInteger value) { if (value._data == null) + { return One; + } var sign = value._sign; var data = value._data; if (data.Length == 1) { if (sign == -1 && data[0] == 1) + { return Zero; + } + if (sign == 0) + { return One; + } } data = sign == -1 ? CoreSub(data, 1) : CoreAdd(data, 1); @@ -1341,16 +1523,23 @@ public static explicit operator BigInteger(decimal value) public static BigInteger operator --(BigInteger value) { if (value._data == null) + { return MinusOne; + } var sign = value._sign; var data = value._data; if (data.Length == 1) { if (sign == 1 && data[0] == 1) + { return Zero; + } + if (sign == 0) + { return MinusOne; + } } data = sign == -1 ? CoreAdd(data, 1) : CoreSub(data, 1); @@ -1369,10 +1558,14 @@ public static explicit operator BigInteger(decimal value) public static BigInteger operator &(BigInteger left, BigInteger right) { if (left._sign == 0) + { return left; + } if (right._sign == 0) + { return right; + } var a = left._data; var b = right._data; @@ -1390,7 +1583,10 @@ public static explicit operator BigInteger(decimal value) { uint va = 0; if (i < a.Length) + { va = a[i]; + } + if (ls == -1) { ac = ~va + ac; @@ -1400,7 +1596,10 @@ public static explicit operator BigInteger(decimal value) uint vb = 0; if (i < b.Length) + { vb = b[i]; + } + if (rs == -1) { bc = ~vb + bc; @@ -1421,11 +1620,16 @@ public static explicit operator BigInteger(decimal value) } for (i = result.Length - 1; i >= 0 && result[i] == 0; --i) ; + if (i == -1) + { return Zero; + } if (i < result.Length - 1) + { Array.Resize(ref result, i + 1); + } return new BigInteger(negRes ? (short)-1 : (short)1, result); } @@ -1441,10 +1645,14 @@ public static explicit operator BigInteger(decimal value) public static BigInteger operator |(BigInteger left, BigInteger right) { if (left._sign == 0) + { return right; + } if (right._sign == 0) + { return left; + } var a = left._data; var b = right._data; @@ -1462,7 +1670,10 @@ public static explicit operator BigInteger(decimal value) { uint va = 0; if (i < a.Length) + { va = a[i]; + } + if (ls == -1) { ac = ~va + ac; @@ -1472,7 +1683,10 @@ public static explicit operator BigInteger(decimal value) uint vb = 0; if (i < b.Length) + { vb = b[i]; + } + if (rs == -1) { bc = ~vb + bc; @@ -1493,11 +1707,16 @@ public static explicit operator BigInteger(decimal value) } for (i = result.Length - 1; i >= 0 && result[i] == 0; --i) ; + if (i == -1) + { return Zero; + } if (i < result.Length - 1) + { Array.Resize(ref result, i + 1); + } return new BigInteger(negRes ? (short)-1 : (short)1, result); } @@ -1513,10 +1732,14 @@ public static explicit operator BigInteger(decimal value) public static BigInteger operator ^(BigInteger left, BigInteger right) { if (left._sign == 0) + { return right; + } if (right._sign == 0) + { return left; + } var a = left._data; var b = right._data; @@ -1534,7 +1757,10 @@ public static explicit operator BigInteger(decimal value) { uint va = 0; if (i < a.Length) + { va = a[i]; + } + if (ls == -1) { ac = ~va + ac; @@ -1544,7 +1770,10 @@ public static explicit operator BigInteger(decimal value) uint vb = 0; if (i < b.Length) + { vb = b[i]; + } + if (rs == -1) { bc = ~vb + bc; @@ -1565,11 +1794,16 @@ public static explicit operator BigInteger(decimal value) } for (i = result.Length - 1; i >= 0 && result[i] == 0; --i) ; + if (i == -1) + { return Zero; + } if (i < result.Length - 1) + { Array.Resize(ref result, i + 1); + } return new BigInteger(negRes ? (short)-1 : (short)1, result); } @@ -1584,7 +1818,9 @@ public static explicit operator BigInteger(decimal value) public static BigInteger operator ~(BigInteger value) { if (value._data == null) + { return MinusOne; + } var data = value._data; int sign = value._sign; @@ -1619,11 +1855,16 @@ public static explicit operator BigInteger(decimal value) } for (i = result.Length - 1; i >= 0 && result[i] == 0; --i) ; + if (i == -1) + { return Zero; + } if (i < result.Length - 1) + { Array.Resize(ref result, i + 1); + } return new BigInteger(negRes ? (short)-1 : (short)1, result); } @@ -1636,8 +1877,11 @@ static int BitScanBackward(uint word) { var mask = 1u << i; if ((word & mask) == mask) + { return i; + } } + return 0; } @@ -1652,9 +1896,14 @@ static int BitScanBackward(uint word) public static BigInteger operator <<(BigInteger value, int shift) { if (shift == 0 || value._data == null) + { return value; + } + if (shift < 0) + { return value >> -shift; + } var data = value._data; int sign = value._sign; @@ -1684,7 +1933,9 @@ static int BitScanBackward(uint word) var word = data[i]; res[i + idxShift] |= word << bitShift; if (i + idxShift + 1 < res.Length) + { res[i + idxShift + 1] = word >> carryShift; + } } } @@ -1702,9 +1953,14 @@ static int BitScanBackward(uint word) public static BigInteger operator >>(BigInteger value, int shift) { if (shift == 0 || value._sign == 0) + { return value; + } + if (shift < 0) + { return value << -shift; + } var data = value._data; int sign = value._sign; @@ -1715,14 +1971,15 @@ static int BitScanBackward(uint word) var extraWords = idxShift; if (bitShift > topMostIdx) + { ++extraWords; + } + var size = data.Length - extraWords; if (size <= 0) { - if (sign == 1) - return Zero; - return MinusOne; + return sign == 1 ? Zero : MinusOne; } var res = new uint[size]; @@ -1735,7 +1992,9 @@ static int BitScanBackward(uint word) var word = data[i]; if (i - idxShift < res.Length) + { res[i - idxShift] |= word >> bitShift; + } } } else @@ -1745,14 +2004,18 @@ static int BitScanBackward(uint word) var word = data[i]; if (i - idxShift < res.Length) + { res[i - idxShift] |= word >> bitShift; + } + if (i - idxShift - 1 >= 0) + { res[i - idxShift - 1] = word << carryShift; + } } - } - //Round down instead of toward zero + // Round down instead of toward zero if (sign == -1) { for (var i = 0; i < idxShift; i++) @@ -1764,6 +2027,7 @@ static int BitScanBackward(uint word) return tmp; } } + if (bitShift > 0 && (data[idxShift] << carryShift) != 0u) { var tmp = new BigInteger((short)sign, res); @@ -1771,6 +2035,7 @@ static int BitScanBackward(uint word) return tmp; } } + return new BigInteger((short)sign, res); } @@ -1816,7 +2081,6 @@ static int BitScanBackward(uint word) return right.CompareTo(left) > 0; } - /// /// Returns a value that indicates whether a 64-bit signed integer is less than a value. /// @@ -2226,9 +2490,12 @@ static int BitScanBackward(uint word) /// public override bool Equals(object obj) { - if (!(obj is BigInteger)) + if (obj is not BigInteger other) + { return false; - return Equals((BigInteger)obj); + } + + return Equals(other); } /// @@ -2243,18 +2510,26 @@ public override bool Equals(object obj) public bool Equals(BigInteger other) { if (_sign != other._sign) + { return false; + } var alen = _data != null ? _data.Length : 0; var blen = other._data != null ? other._data.Length : 0; if (alen != blen) + { return false; + } + for (var i = 0; i < alen; ++i) { if (_data[i] != other._data[i]) + { return false; + } } + return true; } @@ -2265,7 +2540,7 @@ public bool Equals(BigInteger other) /// /// true if the signed 64-bit integer and the current instance have the same value; otherwise, false. /// - public bool Equals(long other) + public readonly bool Equals(long other) { return CompareTo(other) == 0; } @@ -2278,7 +2553,7 @@ public bool Equals(long other) /// public override string ToString() { - return ToString(10, null); + return ToString(10, provider: null); } private string ToStringWithPadding(string format, uint radix, IFormatProvider provider) @@ -2294,10 +2569,13 @@ private string ToStringWithPadding(string format, uint radix, IFormatProvider pr { return additional + baseStr; } + return "-" + additional + baseStr.Substring(1); } + return baseStr; } + return ToString(radix, provider); } @@ -2313,12 +2591,12 @@ private string ToStringWithPadding(string format, uint radix, IFormatProvider pr /// is not a valid format string. public string ToString(string format) { - return ToString(format, null); + return ToString(format, provider: null); } /// /// Converts the numeric value of the current object to its equivalent string representation - /// by using the specified culture-specific formatting information. + /// by using the specified culture-specific formatting information. /// /// An object that supplies culture-specific formatting information. /// @@ -2327,7 +2605,7 @@ public string ToString(string format) /// public string ToString(IFormatProvider provider) { - return ToString(null, provider); + return ToString(format: null, provider); } /// @@ -2343,7 +2621,9 @@ public string ToString(IFormatProvider provider) public string ToString(string format, IFormatProvider provider) { if (string.IsNullOrEmpty(format)) + { return ToString(10, provider); + } switch (format[0]) { @@ -2356,7 +2636,7 @@ public string ToString(string format, IFormatProvider provider) return ToStringWithPadding(format, 10, provider); case 'x': case 'X': - return ToStringWithPadding(format, 16, null); + return ToStringWithPadding(format, 16, provider: null); default: throw new FormatException(string.Format("format '{0}' not implemented", format)); } @@ -2380,56 +2660,77 @@ private static uint[] MakeTwoComplement(uint[] v) var idx = FirstNonFfByte(last); uint mask = 0xFF; for (var i = 1; i < idx; ++i) + { mask = (mask << 8) | 0xFF; + } res[res.Length - 1] = last & mask; return res; } - private string ToString(uint radix, IFormatProvider provider) + private readonly string ToString(uint radix, IFormatProvider provider) { const string characterSet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; if (characterSet.Length < radix) + { throw new ArgumentException("charSet length less than radix", "characterSet"); + } + if (radix == 1) - throw new ArgumentException("There is no such thing as radix one notation", "radix"); + { + throw new ArgumentException("There is no such thing as radix one notation", nameof(radix)); + } if (_sign == 0) + { return "0"; + } + if (_data.Length == 1 && _data[0] == 1) + { return _sign == 1 ? "1" : "-1"; + } var digits = new List(1 + _data.Length * 3 / 10); BigInteger a; if (_sign == 1) + { a = this; + } else { var dt = _data; if (radix > 10) + { dt = MakeTwoComplement(dt); + } + a = new BigInteger(1, dt); } while (a != 0) { - BigInteger rem; - a = DivRem(a, radix, out rem); - digits.Add(characterSet[(int)rem]); + a = DivRem(a, radix, out var rem); + digits.Add(characterSet[(int) rem]); } if (_sign == -1 && radix == 10) { NumberFormatInfo info = null; if (provider != null) + { info = provider.GetFormat(typeof(NumberFormatInfo)) as NumberFormatInfo; + } + if (info != null) { var str = info.NegativeSign; for (var i = str.Length - 1; i >= 0; --i) + { digits.Add(str[i]); + } } else { @@ -2439,7 +2740,9 @@ private string ToString(uint radix, IFormatProvider provider) var last = digits[digits.Count - 1]; if (_sign == 1 && radix > 10 && (last < '0' || last > '9')) + { digits.Add('0'); + } digits.Reverse(); @@ -2457,11 +2760,11 @@ private string ToString(uint radix, IFormatProvider provider) /// is not in the correct format. public static BigInteger Parse(string value) { - Exception ex; - BigInteger result; - - if (!Parse(value, false, out result, out ex)) + if (!Parse(value, tryParse: false, out var result, out var ex)) + { throw ex; + } + return result; } @@ -2482,7 +2785,7 @@ public static BigInteger Parse(string value) /// does not comply with the input pattern specified by . public static BigInteger Parse(string value, NumberStyles style) { - return Parse(value, style, null); + return Parse(value, style, provider: null); } /// @@ -2518,11 +2821,10 @@ public static BigInteger Parse(string value, IFormatProvider provider) /// does not comply with the input pattern specified by . public static BigInteger Parse(string value, NumberStyles style, IFormatProvider provider) { - Exception exc; - BigInteger res; - - if (!Parse(value, style, provider, false, out res, out exc)) + if (!Parse(value, style, provider, tryParse: false, out var res, out var exc)) + { throw exc; + } return res; } @@ -2539,8 +2841,7 @@ public static BigInteger Parse(string value, NumberStyles style, IFormatProvider /// is null. public static bool TryParse(string value, out BigInteger result) { - Exception ex; - return Parse(value, true, out result, out ex); + return Parse(value, tryParse: true, out result, out _); } /// @@ -2561,8 +2862,7 @@ public static bool TryParse(string value, out BigInteger result) /// public static bool TryParse(string value, NumberStyles style, IFormatProvider provider, out BigInteger result) { - Exception exc; - if (!Parse(value, style, provider, true, out result, out exc)) + if (!Parse(value, style, provider, tryParse: true, out result, out _)) { result = Zero; return false; @@ -2579,14 +2879,20 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, if (value == null) { if (!tryParse) - exc = new ArgumentNullException("value"); + { + exc = new ArgumentNullException(nameof(value)); + } + return false; } if (value.Length == 0) { if (!tryParse) + { exc = GetFormatException(); + } + return false; } @@ -2596,11 +2902,13 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, var typeNfi = typeof(NumberFormatInfo); nfi = (NumberFormatInfo) fp.GetFormat(typeNfi); } - if (nfi == null) - nfi = NumberFormatInfo.CurrentInfo; + + nfi ??= NumberFormatInfo.CurrentInfo; if (!CheckStyle(style, tryParse, ref exc)) + { return false; + } var allowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0; var allowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0; @@ -2615,8 +2923,10 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, var pos = 0; - if (allowLeadingWhite && !JumpOverWhitespace(ref pos, value, true, tryParse, ref exc)) + if (allowLeadingWhite && !JumpOverWhitespace(ref pos, value, reportError: true, tryParse, ref exc)) + { return false; + } var foundOpenParentheses = false; var negative = false; @@ -2628,23 +2938,31 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, { foundOpenParentheses = true; foundSign = true; - negative = true; // MS always make the number negative when there parentheses - // even when NumberFormatInfo.NumberNegativePattern != 0!!! + negative = true; // MS always make the number negative when there parentheses, even when NumberFormatInfo.NumberNegativePattern != 0 pos++; - if (allowLeadingWhite && !JumpOverWhitespace(ref pos, value, true, tryParse, ref exc)) + + if (allowLeadingWhite && !JumpOverWhitespace(ref pos, value, reportError: true, tryParse, ref exc)) + { return false; + } if (value.Substring(pos, nfi.NegativeSign.Length) == nfi.NegativeSign) { if (!tryParse) + { exc = GetFormatException(); + } + return false; } if (value.Substring(pos, nfi.PositiveSign.Length) == nfi.PositiveSign) { if (!tryParse) + { exc = GetFormatException(); + } + return false; } } @@ -2655,15 +2973,18 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, FindSign(ref pos, value, nfi, ref foundSign, ref negative); if (foundSign) { - if (allowLeadingWhite && !JumpOverWhitespace(ref pos, value, true, tryParse, ref exc)) + if (allowLeadingWhite && !JumpOverWhitespace(ref pos, value, reportError: true, tryParse, ref exc)) + { return false; + } + if (allowCurrencySymbol) { - FindCurrency(ref pos, value, nfi, - ref foundCurrency); - if (foundCurrency && allowLeadingWhite && - !JumpOverWhitespace(ref pos, value, true, tryParse, ref exc)) + FindCurrency(ref pos, value, nfi, ref foundCurrency); + if (foundCurrency && allowLeadingWhite && !JumpOverWhitespace(ref pos, value, reportError: true, tryParse, ref exc)) + { return false; + } } } } @@ -2674,17 +2995,20 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, FindCurrency(ref pos, value, nfi, ref foundCurrency); if (foundCurrency) { - if (allowLeadingWhite && !JumpOverWhitespace(ref pos, value, true, tryParse, ref exc)) + if (allowLeadingWhite && !JumpOverWhitespace(ref pos, value, reportError: true, tryParse, ref exc)) + { return false; + } + if (foundCurrency) { if (!foundSign && allowLeadingSign) { - FindSign(ref pos, value, nfi, ref foundSign, - ref negative); - if (foundSign && allowLeadingWhite && - !JumpOverWhitespace(ref pos, value, true, tryParse, ref exc)) + FindSign(ref pos, value, nfi, ref foundSign, ref negative); + if (foundSign && allowLeadingWhite && !JumpOverWhitespace(ref pos, value, reportError: true, tryParse, ref exc)) + { return false; + } } } } @@ -2698,13 +3022,14 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, // Number stuff while (pos < value.Length) { - if (!ValidDigit(value[pos], allowHexSpecifier)) { if (allowThousands && (FindOther(ref pos, value, nfi.NumberGroupSeparator) || FindOther(ref pos, value, nfi.CurrencyGroupSeparator))) + { continue; + } if (allowDecimalPoint && decimalPointPos < 0 && (FindOther(ref pos, value, nfi.NumberDecimalSeparator) @@ -2724,32 +3049,43 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, var hexDigit = value[pos++]; byte digitValue; if (char.IsDigit(hexDigit)) - digitValue = (byte)(hexDigit - '0'); + { + digitValue = (byte) (hexDigit - '0'); + } else if (char.IsLower(hexDigit)) - digitValue = (byte)(hexDigit - 'a' + 10); + { + digitValue = (byte) (hexDigit - 'a' + 10); + } else - digitValue = (byte)(hexDigit - 'A' + 10); + { + digitValue = (byte) (hexDigit - 'A' + 10); + } if (firstHexDigit && digitValue >= 8) + { negative = true; + } - number = number * 16 + digitValue; + number = (number * 16) + digitValue; firstHexDigit = false; continue; } - number = number * 10 + (byte)(value[pos++] - '0'); + number = (number * 10) + (byte)(value[pos++] - '0'); } // Post number stuff if (nDigits == 0) { if (!tryParse) + { exc = GetFormatException(); + } + return false; } - //Signed hex value (Two's Complement) + // Signed hex value (Two's Complement) if (allowHexSpecifier && negative) { var mask = Pow(16, nDigits) - 1; @@ -2758,8 +3094,12 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, var exponent = 0; if (allowExponent) + { if (FindExponent(ref pos, value, ref exponent, tryParse, ref exc) && exc != null) + { return false; + } + } if (allowTrailingSign && !foundSign) { @@ -2767,65 +3107,86 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, FindSign(ref pos, value, nfi, ref foundSign, ref negative); if (foundSign && pos < value.Length) { - if (allowTrailingWhite && !JumpOverWhitespace(ref pos, value, true, tryParse, ref exc)) + if (allowTrailingWhite && !JumpOverWhitespace(ref pos, value, reportError: true, tryParse, ref exc)) + { return false; + } } } if (allowCurrencySymbol && !foundCurrency) { - if (allowTrailingWhite && pos < value.Length && !JumpOverWhitespace(ref pos, value, false, tryParse, ref exc)) + if (allowTrailingWhite && pos < value.Length && !JumpOverWhitespace(ref pos, value, reportError: false, tryParse, ref exc)) + { return false; + } // Currency + sign FindCurrency(ref pos, value, nfi, ref foundCurrency); if (foundCurrency && pos < value.Length) { - if (allowTrailingWhite && !JumpOverWhitespace(ref pos, value, true, tryParse, ref exc)) + if (allowTrailingWhite && !JumpOverWhitespace(ref pos, value, reportError: true, tryParse, ref exc)) + { return false; + } + if (!foundSign && allowTrailingSign) - FindSign(ref pos, value, nfi, ref foundSign, - ref negative); + { + FindSign(ref pos, value, nfi, ref foundSign, ref negative); + } } } - if (allowTrailingWhite && pos < value.Length && !JumpOverWhitespace(ref pos, value, false, tryParse, ref exc)) + if (allowTrailingWhite && pos < value.Length && !JumpOverWhitespace(ref pos, value, reportError: false, tryParse, ref exc)) + { return false; + } if (foundOpenParentheses) { if (pos >= value.Length || value[pos++] != ')') { if (!tryParse) + { exc = GetFormatException(); + } + return false; } - if (allowTrailingWhite && pos < value.Length && !JumpOverWhitespace(ref pos, value, false, tryParse, ref exc)) + + if (allowTrailingWhite && pos < value.Length && !JumpOverWhitespace(ref pos, value, reportError: false, tryParse, ref exc)) + { return false; + } } if (pos < value.Length && value[pos] != '\u0000') { if (!tryParse) + { exc = GetFormatException(); + } + return false; } if (decimalPointPos >= 0) + { exponent = exponent - nDigits + decimalPointPos; + } if (exponent < 0) { - // // Any non-zero values after decimal point are not allowed - // - BigInteger remainder; - number = DivRem(number, Pow(10, -exponent), out remainder); + number = DivRem(number, Pow(10, -exponent), out var remainder); if (!remainder.IsZero) { if (!tryParse) + { exc = new OverflowException("Value too large or too small. exp=" + exponent + " rem = " + remainder + " pow = " + Pow(10, -exponent)); + } + return false; } } @@ -2835,11 +3196,17 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, } if (number._sign == 0) + { result = number; + } else if (negative) + { result = new BigInteger(-1, number._data); + } else + { result = new BigInteger(1, number._data); + } return true; } @@ -2850,23 +3217,34 @@ private static bool CheckStyle(NumberStyles style, bool tryParse, ref Exception { var ne = style ^ NumberStyles.AllowHexSpecifier; if ((ne & NumberStyles.AllowLeadingWhite) != 0) + { ne ^= NumberStyles.AllowLeadingWhite; + } + if ((ne & NumberStyles.AllowTrailingWhite) != 0) + { ne ^= NumberStyles.AllowTrailingWhite; + } + if (ne != 0) { if (!tryParse) - exc = new ArgumentException( - "With AllowHexSpecifier only " + - "AllowLeadingWhite and AllowTrailingWhite " + - "are permitted."); + { + exc = new ArgumentException("With AllowHexSpecifier only " + + "AllowLeadingWhite and AllowTrailingWhite " + + "are permitted."); + } + return false; } } else if ((uint)style > (uint)NumberStyles.Any) { if (!tryParse) + { exc = new ArgumentException("Not a valid number style"); + } + return false; } @@ -2876,12 +3254,17 @@ private static bool CheckStyle(NumberStyles style, bool tryParse, ref Exception private static bool JumpOverWhitespace(ref int pos, string s, bool reportError, bool tryParse, ref Exception exc) { while (pos < s.Length && char.IsWhiteSpace(s[pos])) + { pos++; + } if (reportError && pos >= s.Length) { if (!tryParse) + { exc = GetFormatException(); + } + return false; } @@ -2960,8 +3343,8 @@ private static bool FindExponent(ref int pos, string s, ref int exponent, bool t } // Reduce the risk of throwing an overflow exc - exp = checked(exp * 10 - (int)(s[i] - '0')); - if (exp < int.MinValue || exp > int.MaxValue) + exp = checked((exp * 10) - (int)(s[i] - '0')); + if (exp is < int.MinValue or > int.MaxValue) { exc = tryParse ? null : new OverflowException("Value too large or too small."); return true; @@ -2970,7 +3353,9 @@ private static bool FindExponent(ref int pos, string s, ref int exponent, bool t // exp value saved as negative if (!negative) + { exp = -exp; + } exc = null; exponent = (int) exp; @@ -2993,7 +3378,9 @@ private static bool FindOther(ref int pos, string s, string other) private static bool ValidDigit(char e, bool allowHex) { if (allowHex) + { return char.IsDigit(e) || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f'); + } return char.IsDigit(e); } @@ -3014,10 +3401,14 @@ private static bool ProcessTrailingWhitespace(bool tryParse, string s, int posit if (c != 0 && !char.IsWhiteSpace(c)) { if (!tryParse) + { exc = GetFormatException(); + } + return false; } } + return true; } @@ -3032,7 +3423,10 @@ private static bool Parse(string value, bool tryParse, out BigInteger result, ou if (value == null) { if (!tryParse) - exc = new ArgumentNullException("value"); + { + exc = new ArgumentNullException(nameof(value)); + } + return false; } @@ -3043,13 +3437,18 @@ private static bool Parse(string value, bool tryParse, out BigInteger result, ou { c = value[i]; if (!char.IsWhiteSpace(c)) + { break; + } } if (i == len) { if (!tryParse) + { exc = GetFormatException(); + } + return false; } @@ -3059,7 +3458,9 @@ private static bool Parse(string value, bool tryParse, out BigInteger result, ou var positive = info.PositiveSign; if (string.CompareOrdinal(value, i, positive, 0, positive.Length) == 0) + { i += positive.Length; + } else if (string.CompareOrdinal(value, i, negative, 0, negative.Length) == 0) { sign = -1; @@ -3077,31 +3478,42 @@ private static bool Parse(string value, bool tryParse, out BigInteger result, ou continue; } - if (c >= '0' && c <= '9') + if (c is >= '0' and <= '9') { - var d = (byte)(c - '0'); + var d = (byte) (c - '0'); - val = val * 10 + d; + val = (val * 10) + d; digitsSeen = true; } else if (!ProcessTrailingWhitespace(tryParse, value, i, ref exc)) + { return false; + } } if (!digitsSeen) { if (!tryParse) + { exc = GetFormatException(); + } + return false; } if (val._sign == 0) + { result = val; + } else if (sign == -1) + { result = new BigInteger(-1, val._data); + } else + { result = new BigInteger(1, val._data); + } return true; } @@ -3120,16 +3532,26 @@ public static BigInteger Min(BigInteger left, BigInteger right) int rs = right._sign; if (ls < rs) + { return left; + } + if (rs < ls) + { return right; + } var r = CoreCompare(left._data, right._data); if (ls == -1) + { r = -r; + } if (r <= 0) + { return left; + } + return right; } @@ -3147,16 +3569,26 @@ public static BigInteger Max(BigInteger left, BigInteger right) int rs = right._sign; if (ls > rs) + { return left; + } + if (rs > ls) + { return right; + } var r = CoreCompare(left._data, right._data); if (ls == -1) + { r = -r; + } if (r >= 0) + { return left; + } + return right; } @@ -3169,7 +3601,7 @@ public static BigInteger Max(BigInteger left, BigInteger right) /// public static BigInteger Abs(BigInteger value) { - return new BigInteger((short)Math.Abs(value._sign), value._data); + return new BigInteger((short) Math.Abs(value._sign), value._data); } /// @@ -3185,7 +3617,9 @@ public static BigInteger Abs(BigInteger value) public static BigInteger DivRem(BigInteger dividend, BigInteger divisor, out BigInteger remainder) { if (divisor._sign == 0) + { throw new DivideByZeroException(); + } if (dividend._sign == 0) { @@ -3193,13 +3627,11 @@ public static BigInteger DivRem(BigInteger dividend, BigInteger divisor, out Big return dividend; } - uint[] quotient; - uint[] remainderValue; - - DivModUnsigned(dividend._data, divisor._data, out quotient, out remainderValue); + DivModUnsigned(dividend._data, divisor._data, out var quotient, out var remainderValue); int i; for (i = remainderValue.Length - 1; i >= 0 && remainderValue[i] == 0; --i) ; + if (i == -1) { remainder = Zero; @@ -3207,15 +3639,24 @@ public static BigInteger DivRem(BigInteger dividend, BigInteger divisor, out Big else { if (i < remainderValue.Length - 1) + { Array.Resize(ref remainderValue, i + 1); + } + remainder = new BigInteger(dividend._sign, remainderValue); } for (i = quotient.Length - 1; i >= 0 && quotient[i] == 0; --i) ; + if (i == -1) + { return Zero; + } + if (i < quotient.Length - 1) + { Array.Resize(ref quotient, i + 1); + } return new BigInteger((short)(dividend._sign * divisor._sign), quotient); } @@ -3231,23 +3672,37 @@ public static BigInteger DivRem(BigInteger dividend, BigInteger divisor, out Big public static BigInteger Pow(BigInteger value, int exponent) { if (exponent < 0) - throw new ArgumentOutOfRangeException("exponent", "exp must be >= 0"); + { + throw new ArgumentOutOfRangeException(nameof(exponent), "exp must be >= 0"); + } + if (exponent == 0) + { return One; + } + if (exponent == 1) + { return value; + } var result = One; while (exponent != 0) { if ((exponent & 1) != 0) - result = result * value; + { + result *= value; + } + if (exponent == 1) + { break; + } - value = value * value; + value *= value; exponent >>= 1; } + return result; } @@ -3265,24 +3720,34 @@ public static BigInteger Pow(BigInteger value, int exponent) public static BigInteger ModPow(BigInteger value, BigInteger exponent, BigInteger modulus) { if (exponent._sign == -1) - throw new ArgumentOutOfRangeException("exponent", "power must be >= 0"); + { + throw new ArgumentOutOfRangeException(nameof(exponent), "power must be >= 0"); + } + if (modulus._sign == 0) + { throw new DivideByZeroException(); + } var result = One % modulus; while (exponent._sign != 0) { if (!exponent.IsEven) { - result = result * value; - result = result % modulus; + result *= value; + result %= modulus; } + if (exponent.IsOne) + { break; - value = value * value; - value = value % modulus; + } + + value *= value; + value %= modulus; exponent >>= 1; } + return result; } @@ -3297,13 +3762,24 @@ public static BigInteger ModPow(BigInteger value, BigInteger exponent, BigIntege public static BigInteger GreatestCommonDivisor(BigInteger left, BigInteger right) { if (left._sign != 0 && left._data.Length == 1 && left._data[0] == 1) + { return One; + } + if (right._sign != 0 && right._data.Length == 1 && right._data[0] == 1) + { return One; + } + if (left.IsZero) + { return Abs(right); + } + if (right.IsZero) + { return Abs(left); + } var x = new BigInteger(1, left._data); var y = new BigInteger(1, right._data); @@ -3317,14 +3793,18 @@ public static BigInteger GreatestCommonDivisor(BigInteger left, BigInteger right y = g; } - if (x.IsZero) return g; + + if (x.IsZero) + { + return g; + } // TODO: should we have something here if we can convert to long? - // - // Now we can just do it with single precision. I am using the binary gcd method, - // as it should be faster. - // + /* + * Now we can just do it with single precision. I am using the binary gcd method, + * as it should be faster. + */ var yy = x._data[0]; var xx = (uint)(y % yy); @@ -3333,24 +3813,40 @@ public static BigInteger GreatestCommonDivisor(BigInteger left, BigInteger right while (((xx | yy) & 1) == 0) { - xx >>= 1; yy >>= 1; t++; + xx >>= 1; + yy >>= 1; + t++; } + while (xx != 0) { - while ((xx & 1) == 0) xx >>= 1; - while ((yy & 1) == 0) yy >>= 1; + while ((xx & 1) == 0) + { + xx >>= 1; + } + + while ((yy & 1) == 0) + { + yy >>= 1; + } + if (xx >= yy) + { xx = (xx - yy) >> 1; + } else + { yy = (yy - xx) >> 1; + } } return yy << t; } - /*LAMESPEC Log doesn't specify to how many ulp is has to be precise - We are equilavent to MS with about 2 ULP - */ + /* + * LAMESPEC Log doesn't specify to how many ulp is has to be precise + * We are equilavent to MS with about 2 ULP + */ /// /// Returns the logarithm of a specified number in a specified base. @@ -3358,20 +3854,26 @@ We are equilavent to MS with about 2 ULP /// A number whose logarithm is to be found. /// The base of the logarithm. /// - /// The base logarithm of value, + /// The base logarithm of value. /// /// The log of is out of range of the data type. public static double Log(BigInteger value, double baseValue) { if (value._sign == -1 || baseValue == 1.0d || baseValue == -1.0d || baseValue == double.NegativeInfinity || double.IsNaN(baseValue)) + { return double.NaN; + } - if (baseValue == 0.0d || baseValue == double.PositiveInfinity) + if (baseValue is 0.0d or double.PositiveInfinity) + { return value.IsOne ? 0 : double.NaN; + } if (value._data == null) + { return double.NegativeInfinity; + } var length = value._data.Length - 1; var bitCount = -1; @@ -3391,19 +3893,24 @@ public static double Log(BigInteger value, double baseValue) var tempBitlen = bitlen; while (tempBitlen > int.MaxValue) { - testBit = testBit << int.MaxValue; + testBit <<= int.MaxValue; tempBitlen -= int.MaxValue; } - testBit = testBit << (int)tempBitlen; + + testBit <<= (int)tempBitlen; for (var curbit = bitlen; curbit >= 0; --curbit) { if ((value & testBit)._sign != 0) + { c += d; + } + d *= 0.5; - testBit = testBit >> 1; + testBit >>= 1; } - return (Math.Log(c) + Math.Log(2) * bitlen) / Math.Log(baseValue); + + return (Math.Log(c) + (Math.Log(2) * bitlen)) / Math.Log(baseValue); } /// @@ -3440,7 +3947,7 @@ public static double Log10(BigInteger value) /// true if the current instance and the unsigned 64-bit integer have the same value; otherwise, false. /// [CLSCompliant(false)] - public bool Equals(ulong other) + public readonly bool Equals(ulong other) { return CompareTo(other) == 0; } @@ -3451,16 +3958,18 @@ public bool Equals(ulong other) /// /// A 32-bit signed integer hash code. /// - public override int GetHashCode() + public override readonly int GetHashCode() { - var hash = (uint)(_sign * 0x01010101u); + var hash = (uint) (_sign * 0x01010101u); if (_data != null) { foreach (var bit in _data) + { hash ^= bit; + } } - return (int)hash; + return (int) hash; } /// @@ -3568,15 +4077,19 @@ public static BigInteger Negate(BigInteger value) /// /// /// is not a . - public int CompareTo(object obj) + public readonly int CompareTo(object obj) { if (obj == null) + { return 1; + } - if (!(obj is BigInteger)) + if (obj is not BigInteger other) + { return -1; + } - return Compare(this, (BigInteger)obj); + return Compare(this, other); } /// @@ -3606,7 +4119,7 @@ public int CompareTo(object obj) /// /// /// - public int CompareTo(BigInteger other) + public readonly int CompareTo(BigInteger other) { return Compare(this, other); } @@ -3639,15 +4152,22 @@ public int CompareTo(BigInteger other) /// /// [CLSCompliant(false)] - public int CompareTo(ulong other) + public readonly int CompareTo(ulong other) { if (_sign < 0) + { return -1; + } + if (_sign == 0) + { return other == 0 ? 0 : -1; + } if (_data.Length > 2) + { return 1; + } var high = (uint)(other >> 32); var low = (uint)other; @@ -3655,23 +4175,36 @@ public int CompareTo(ulong other) return LongCompare(low, high); } - private int LongCompare(uint low, uint high) + private readonly int LongCompare(uint low, uint high) { uint h = 0; + if (_data.Length > 1) + { h = _data[1]; + } if (h > high) + { return 1; + } + if (h < high) + { return -1; + } var l = _data[0]; if (l > low) + { return 1; + } + if (l < low) + { return -1; + } return 0; } @@ -3703,28 +4236,39 @@ private int LongCompare(uint low, uint high) /// /// /// - public int CompareTo(long other) + public readonly int CompareTo(long other) { int ls = _sign; var rs = Math.Sign(other); if (ls != rs) + { return ls > rs ? 1 : -1; + } if (ls == 0) + { return 0; + } if (_data.Length > 2) + { return _sign; + } if (other < 0) + { other = -other; - var low = (uint)other; - var high = (uint)((ulong)other >> 32); + } + + var low = (uint) other; + var high = (uint) ((ulong) other >> 32); var r = LongCompare(low, high); if (ls == -1) + { r = -r; + } return r; } @@ -3761,11 +4305,16 @@ public static int Compare(BigInteger left, BigInteger right) int rs = right._sign; if (ls != rs) + { return ls > rs ? 1 : -1; + } var r = CoreCompare(left._data, right._data); if (ls < 0) + { r = -r; + } + return r; } @@ -3774,22 +4323,38 @@ private static int TopByte(uint x) if ((x & 0xFFFF0000u) != 0) { if ((x & 0xFF000000u) != 0) + { return 4; + } + return 3; } + if ((x & 0xFF00u) != 0) + { return 2; + } + return 1; } private static int FirstNonFfByte(uint word) { if ((word & 0xFF000000u) != 0xFF000000u) + { return 4; + } + if ((word & 0xFF0000u) != 0xFF0000u) + { return 3; + } + if ((word & 0xFF00u) != 0xFF00u) + { return 2; + } + return 1; } @@ -3799,19 +4364,21 @@ private static int FirstNonFfByte(uint word) /// /// The value of the current object converted to an array of bytes. /// - public byte[] ToByteArray() + public readonly byte[] ToByteArray() { if (_sign == 0) + { return new byte[1]; + } - //number of bytes not counting upper word + // number of bytes not counting upper word var bytes = (_data.Length - 1) * 4; var needExtraZero = false; var topWord = _data[_data.Length - 1]; int extra; - //if the topmost bit is set we need an extra + // if the topmost bit is set we need an extra if (_sign == 1) { extra = TopByte(topWord); @@ -3840,6 +4407,7 @@ public byte[] ToByteArray() res[j++] = (byte)(word >> 16); res[j++] = (byte)(word >> 24); } + while (extra-- > 0) { res[j++] = (byte)topWord; @@ -3866,7 +4434,7 @@ public byte[] ToByteArray() res[j++] = (byte)(word >> 24); } - add = (ulong)~topWord + (carry); + add = (ulong)~topWord + carry; word = (uint)add; carry = (uint)(add >> 32); if (carry == 0) @@ -3876,15 +4444,20 @@ public byte[] ToByteArray() var to = ex + (needExtra ? 1 : 0); if (to != extra) + { Array.Resize(ref res, bytes + to); + } while (ex-- > 0) { res[j++] = (byte)word; word >>= 8; } + if (needExtra) + { res[j++] = 0xFF; + } } else { @@ -3926,7 +4499,7 @@ private static uint[] CoreAdd(uint[] a, uint[] b) for (; i < bl; i++) { - sum = sum + a[i]; + sum += a[i]; res[i] = (uint)sum; sum >>= 32; } @@ -3965,10 +4538,12 @@ private static uint[] CoreSub(uint[] a, uint[] b) borrow = (borrow >> 32) & 0x1; } - //remove extra zeroes + // remove extra zeroes for (i = bl - 1; i >= 0 && res[i] == 0; --i) ; if (i < bl - 1) + { Array.Resize(ref res, i + 1); + } return res; } @@ -3982,7 +4557,7 @@ private static uint[] CoreAdd(uint[] a, uint b) int i; for (i = 0; i < len; i++) { - sum = sum + a[i]; + sum += a[i]; res[i] = (uint)sum; sum >>= 32; } @@ -4010,10 +4585,12 @@ private static uint[] CoreSub(uint[] a, uint b) borrow = (borrow >> 32) & 0x1; } - //remove extra zeroes + // Remove extra zeroes for (i = len - 1; i >= 0 && res[i] == 0; --i) ; if (i < len - 1) + { Array.Resize(ref res, i + 1); + } return res; } @@ -4024,19 +4601,30 @@ private static int CoreCompare(uint[] a, uint[] b) var bl = b != null ? b.Length : 0; if (al > bl) + { return 1; + } + if (bl > al) + { return -1; + } for (var i = al - 1; i >= 0; --i) { var ai = a[i]; var bi = b[i]; if (ai > bi) + { return 1; + } + if (ai < bi) + { return -1; + } } + return 0; } @@ -4044,11 +4632,35 @@ private static int GetNormalizeShift(uint value) { var shift = 0; - if ((value & 0xFFFF0000) == 0) { value <<= 16; shift += 16; } - if ((value & 0xFF000000) == 0) { value <<= 8; shift += 8; } - if ((value & 0xF0000000) == 0) { value <<= 4; shift += 4; } - if ((value & 0xC0000000) == 0) { value <<= 2; shift += 2; } - if ((value & 0x80000000) == 0) { value <<= 1; shift += 1; } + if ((value & 0xFFFF0000) == 0) + { + value <<= 16; + shift += 16; + } + + if ((value & 0xFF000000) == 0) + { + value <<= 8; + shift += 8; + } + + if ((value & 0xF0000000) == 0) + { + value <<= 4; + shift += 4; + } + + if ((value & 0xC0000000) == 0) + { + value <<= 2; + shift += 2; + } + + if ((value & 0x80000000) == 0) + { + value <<= 1; + shift += 1; + } return shift; } @@ -4099,7 +4711,7 @@ private static void Unnormalize(uint[] un, out uint[] r, int shift) { var uni = un[i]; r[i] = (uni >> shift) | carry; - carry = (uni << lshift); + carry = uni << lshift; } } else @@ -4118,8 +4730,7 @@ private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] if (n <= 1) { - // Divide by single digit - // + // Divide by single digit ulong rem = 0; var v0 = v[0]; q = new uint[m]; @@ -4134,6 +4745,7 @@ private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] rem -= div * v0; q[j] = (uint)div; } + r[0] = (uint)rem; } else if (m >= n) @@ -4149,8 +4761,7 @@ private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] q = new uint[m - n + 1]; r = null; - // Main division loop - // + // Main division loop for (var j = m - n; j >= 0; j--) { int i; @@ -4162,20 +4773,21 @@ private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] for (;;) { // Estimate too big ? - // if ((qq >= Base) || (qq * vn[n - 2] > (rr * Base + un[j + n - 2]))) { qq--; rr += (ulong)vn[n - 1]; if (rr < Base) + { continue; + } } + break; } - // Multiply and subtract - // + // Multiply and subtract long b = 0; long t = 0; for (i = 0; i < n; i++) @@ -4187,15 +4799,14 @@ private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] t >>= 32; b = (long)p - t; } + t = (long)un[j + n] - b; un[j + n] = (uint)t; - // Store the calculated value - // + // Store the calculated value q[j] = (uint)qq; - // Add back vn[0..n] to un[j..j+n] - // + // Add back vn[0..n] to un[j..j+n] if (t < 0) { q[j]--; @@ -4206,6 +4817,7 @@ private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] un[j + i] = (uint)c; c >>= 32; } + c += (ulong)un[j + n]; un[j + n] = (uint)c; } diff --git a/src/Renci.SshNet/Common/ChannelDataEventArgs.cs b/src/Renci.SshNet/Common/ChannelDataEventArgs.cs index 6b47eb6ed..4891fe240 100644 --- a/src/Renci.SshNet/Common/ChannelDataEventArgs.cs +++ b/src/Renci.SshNet/Common/ChannelDataEventArgs.cs @@ -1,15 +1,10 @@ 锘縩amespace Renci.SshNet.Common { /// - /// Provides data for event. + /// Provides data for event. /// internal class ChannelDataEventArgs : ChannelEventArgs { - /// - /// Gets channel data. - /// - public byte[] Data { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -20,5 +15,10 @@ public ChannelDataEventArgs(uint channelNumber, byte[] data) { Data = data; } + + /// + /// Gets channel data. + /// + public byte[] Data { get; } } } diff --git a/src/Renci.SshNet/Common/ChannelEventArgs.cs b/src/Renci.SshNet/Common/ChannelEventArgs.cs index a8e4549ce..ef514fd29 100644 --- a/src/Renci.SshNet/Common/ChannelEventArgs.cs +++ b/src/Renci.SshNet/Common/ChannelEventArgs.cs @@ -7,11 +7,6 @@ namespace Renci.SshNet.Common /// internal class ChannelEventArgs : EventArgs { - /// - /// Gets the channel number. - /// - public uint ChannelNumber { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -20,5 +15,13 @@ public ChannelEventArgs(uint channelNumber) { ChannelNumber = channelNumber; } + + /// + /// Gets the channel number. + /// + /// + /// The channel number. + /// + public uint ChannelNumber { get; } } } diff --git a/src/Renci.SshNet/Common/ChannelExtendedDataEventArgs.cs b/src/Renci.SshNet/Common/ChannelExtendedDataEventArgs.cs index 9098d6b1b..b5eadffe1 100644 --- a/src/Renci.SshNet/Common/ChannelExtendedDataEventArgs.cs +++ b/src/Renci.SshNet/Common/ChannelExtendedDataEventArgs.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet.Common { /// - /// Provides data for events. + /// Provides data for events. /// internal class ChannelExtendedDataEventArgs : ChannelDataEventArgs { @@ -11,7 +11,8 @@ internal class ChannelExtendedDataEventArgs : ChannelDataEventArgs /// Channel number. /// Channel data. /// Channel data type code. - public ChannelExtendedDataEventArgs(uint channelNumber, byte[] data, uint dataTypeCode) : base(channelNumber, data) + public ChannelExtendedDataEventArgs(uint channelNumber, byte[] data, uint dataTypeCode) + : base(channelNumber, data) { DataTypeCode = dataTypeCode; } @@ -19,6 +20,9 @@ public ChannelExtendedDataEventArgs(uint channelNumber, byte[] data, uint dataTy /// /// Gets the data type code. /// - public uint DataTypeCode { get; private set; } + /// + /// The data type code. + /// + public uint DataTypeCode { get; } } } diff --git a/src/Renci.SshNet/Common/ChannelOpenConfirmedEventArgs.cs b/src/Renci.SshNet/Common/ChannelOpenConfirmedEventArgs.cs index bd10d8258..9af1e782d 100644 --- a/src/Renci.SshNet/Common/ChannelOpenConfirmedEventArgs.cs +++ b/src/Renci.SshNet/Common/ChannelOpenConfirmedEventArgs.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet.Common { /// - /// Provides data for event. + /// Provides data for event. /// internal class ChannelOpenConfirmedEventArgs : ChannelEventArgs { @@ -24,7 +24,7 @@ public ChannelOpenConfirmedEventArgs(uint remoteChannelNumber, uint initialWindo /// /// The initial size of the window. /// - public uint InitialWindowSize { get; private set; } + public uint InitialWindowSize { get; } /// /// Gets the maximum size of the packet. @@ -32,6 +32,6 @@ public ChannelOpenConfirmedEventArgs(uint remoteChannelNumber, uint initialWindo /// /// The maximum size of the packet. /// - public uint MaximumPacketSize { get; private set; } + public uint MaximumPacketSize { get; } } } diff --git a/src/Renci.SshNet/Common/ChannelOpenFailedEventArgs.cs b/src/Renci.SshNet/Common/ChannelOpenFailedEventArgs.cs index f130a59eb..43b5790c6 100644 --- a/src/Renci.SshNet/Common/ChannelOpenFailedEventArgs.cs +++ b/src/Renci.SshNet/Common/ChannelOpenFailedEventArgs.cs @@ -1,25 +1,10 @@ 锘縩amespace Renci.SshNet.Common { /// - /// Provides data for event. + /// Provides data for event. /// internal class ChannelOpenFailedEventArgs : ChannelEventArgs { - /// - /// Gets failure reason code. - /// - public uint ReasonCode { get; private set; } - - /// - /// Gets failure description. - /// - public string Description { get; private set; } - - /// - /// Gets failure language. - /// - public string Language { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -34,5 +19,20 @@ public ChannelOpenFailedEventArgs(uint channelNumber, uint reasonCode, string de Description = description; Language = language; } + + /// + /// Gets failure reason code. + /// + public uint ReasonCode { get; } + + /// + /// Gets failure description. + /// + public string Description { get; } + + /// + /// Gets failure language. + /// + public string Language { get; } } } diff --git a/src/Renci.SshNet/Common/ChannelRequestEventArgs.cs b/src/Renci.SshNet/Common/ChannelRequestEventArgs.cs index 0de905a83..b03102aef 100644 --- a/src/Renci.SshNet/Common/ChannelRequestEventArgs.cs +++ b/src/Renci.SshNet/Common/ChannelRequestEventArgs.cs @@ -1,18 +1,14 @@ 锘縰sing System; + using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Common { /// - /// Provides data for event. + /// Provides data for event. /// internal class ChannelRequestEventArgs : EventArgs { - /// - /// Gets request information. - /// - public RequestInfo Info { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -21,5 +17,13 @@ public ChannelRequestEventArgs(RequestInfo info) { Info = info; } + + /// + /// Gets the request information. + /// + /// + /// The request information. + /// + public RequestInfo Info { get; } } } diff --git a/src/Renci.SshNet/Common/DerData.cs b/src/Renci.SshNet/Common/DerData.cs index 35178798a..ee6c07e36 100644 --- a/src/Renci.SshNet/Common/DerData.cs +++ b/src/Renci.SshNet/Common/DerData.cs @@ -16,39 +16,17 @@ public class DerData private const byte Octetstring = 0x04; private const byte Null = 0x05; private const byte Objectidentifier = 0x06; - //private const byte EXTERNAL = 0x08; - //private const byte ENUMERATED = 0x0a; private const byte Sequence = 0x10; - //private const byte SEQUENCEOF = 0x10; // for completeness - //private const byte SET = 0x11; - //private const byte SETOF = 0x11; // for completeness - - //private const byte NUMERICSTRING = 0x12; - //private const byte PRINTABLESTRING = 0x13; - //private const byte T61STRING = 0x14; - //private const byte VIDEOTEXSTRING = 0x15; - //private const byte IA5STRING = 0x16; - //private const byte UTCTIME = 0x17; - //private const byte GENERALIZEDTIME = 0x18; - //private const byte GRAPHICSTRING = 0x19; - //private const byte VISIBLESTRING = 0x1a; - //private const byte GENERALSTRING = 0x1b; - //private const byte UNIVERSALSTRING = 0x1c; - //private const byte BMPSTRING = 0x1e; - //private const byte UTF8STRING = 0x0c; - //private const byte APPLICATION = 0x40; - //private const byte TAGGED = 0x80; private readonly List _data; - - private int _readerIndex; private readonly int _lastIndex; + private int _readerIndex; /// /// Gets a value indicating whether end of data is reached. /// /// - /// true if end of data is reached; otherwise, false. + /// true if end of data is reached; otherwise, false. /// public bool IsEndOfData { @@ -80,7 +58,7 @@ public DerData(byte[] data, bool construct = false) } else { - ReadByte(); // skip dataType + _ = ReadByte(); // skip dataType var length = ReadLength(); _lastIndex = _readerIndex + length; } @@ -109,7 +87,9 @@ public BigInteger ReadBigInteger() { var type = ReadByte(); if (type != Integer) + { throw new InvalidOperationException(string.Format("Invalid data type, INTEGER(02) is expected, but was {0}", type.ToString("X2"))); + } var length = ReadLength(); @@ -126,14 +106,18 @@ public int ReadInteger() { var type = ReadByte(); if (type != Integer) + { throw new InvalidOperationException(string.Format("Invalid data type, INTEGER(02) is expected, but was {0}", type.ToString("X2"))); + } var length = ReadLength(); var data = ReadBytes(length); if (length > 4) + { throw new InvalidOperationException("Integer type cannot occupy more then 4 bytes"); + } var result = 0; var shift = (length - 1) * 8; @@ -143,8 +127,6 @@ public int ReadInteger() shift -= 8; } - //return (int)(data[0] << 56 | data[1] << 48 | data[2] << 40 | data[3] << 32 | data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7]); - return result; } @@ -156,7 +138,9 @@ public byte[] ReadOctetString() { var type = ReadByte(); if (type != Octetstring) + { throw new InvalidOperationException(string.Format("Invalid data type, OCTETSTRING(04) is expected, but was {0}", type.ToString("X2"))); + } var length = ReadLength(); var data = ReadBytes(length); @@ -171,7 +155,9 @@ public byte[] ReadBitString() { var type = ReadByte(); if (type != BITSTRING) + { throw new InvalidOperationException(string.Format("Invalid data type, BITSTRING(03) is expected, but was {0}", type.ToString("X2"))); + } var length = ReadLength(); var data = ReadBytes(length); @@ -186,7 +172,9 @@ public byte[] ReadObject() { var type = ReadByte(); if (type != Objectidentifier) + { throw new InvalidOperationException(string.Format("Invalid data type, OBJECT(06) is expected, but was {0}", type.ToString("X2"))); + } var length = ReadLength(); var data = ReadBytes(length); @@ -261,7 +249,7 @@ public void WriteBitstring(byte[] data) public void Write(ObjectIdentifier identifier) { var temp = new ulong[identifier.Identifiers.Length - 1]; - temp[0] = identifier.Identifiers[0] * 40 + identifier.Identifiers[1]; + temp[0] = (identifier.Identifiers[0] * 40) + identifier.Identifiers[1]; Buffer.BlockCopy(identifier.Identifiers, 2 * sizeof(ulong), temp, 1 * sizeof(ulong), (identifier.Identifiers.Length - 2) * sizeof(ulong)); var bytes = new List(); foreach (var subidentifier in temp) @@ -275,7 +263,10 @@ public void Write(ObjectIdentifier identifier) { buffer[bufferIndex] = current; if (bufferIndex < buffer.Length - 1) + { buffer[bufferIndex] |= 0x80; + } + item >>= 7; current = (byte)(item & 0x7F); bufferIndex--; @@ -325,7 +316,7 @@ public void Write(DerData data) _data.AddRange(bytes); } - private static IEnumerable GetLength(int length) + private static byte[] GetLength(int length) { if (length > 127) { @@ -333,7 +324,9 @@ private static IEnumerable GetLength(int length) var val = length; while ((val >>= 8) != 0) + { size++; + } var data = new byte[size]; data[0] = (byte)(size | 0x80); @@ -345,12 +338,16 @@ private static IEnumerable GetLength(int length) return data; } - return new[] { (byte)length }; + + return new[] { (byte) length }; } + /// - /// Gets Data Length + /// Gets Data Length. /// - /// length + /// + /// The length. + /// public int ReadLength() { int length = ReadByte(); @@ -366,7 +363,9 @@ public int ReadLength() // Note: The invalid long form "0xff" (see X.690 8.1.3.5c) will be caught here if (size > 4) + { throw new InvalidOperationException(string.Format("DER length is '{0}' and cannot be more than 4 bytes.", size)); + } length = 0; for (var i = 0; i < size; i++) @@ -377,10 +376,9 @@ public int ReadLength() } if (length < 0) + { throw new InvalidOperationException("Corrupted data - negative length found"); - - //if (length >= limit) // after all we must have read at least 1 byte - // throw new IOException("Corrupted stream - out of bounds length found"); + } } return length; @@ -389,6 +387,7 @@ public int ReadLength() /// /// Write Byte data into internal buffer. /// + /// The data to write. public void WriteBytes(IEnumerable data) { _data.AddRange(data); @@ -397,11 +396,15 @@ public void WriteBytes(IEnumerable data) /// /// Reads Byte data into internal buffer. /// - /// data read + /// + /// The data read. + /// public byte ReadByte() { if (_readerIndex > _data.Count) + { throw new InvalidOperationException("Read out of boundaries."); + } return _data[_readerIndex++]; } @@ -409,12 +412,16 @@ public byte ReadByte() /// /// Reads lengths Bytes data into internal buffer. /// - /// data read - /// amount of data to read. + /// + /// The data read. + /// + /// amount of data to read. public byte[] ReadBytes(int length) { if (_readerIndex + length > _data.Count) + { throw new InvalidOperationException("Read out of boundaries."); + } var result = new byte[length]; _data.CopyTo(_readerIndex, result, 0, length); @@ -422,4 +429,4 @@ public byte[] ReadBytes(int length) return result; } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Common/ExceptionEventArgs.cs b/src/Renci.SshNet/Common/ExceptionEventArgs.cs index 0211be943..7e99def5a 100644 --- a/src/Renci.SshNet/Common/ExceptionEventArgs.cs +++ b/src/Renci.SshNet/Common/ExceptionEventArgs.cs @@ -7,11 +7,6 @@ namespace Renci.SshNet.Common /// public class ExceptionEventArgs : EventArgs { - /// - /// Gets the System.Exception that represents the error that occurred. - /// - public Exception Exception { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -20,5 +15,13 @@ public ExceptionEventArgs(Exception exception) { Exception = exception; } + + /// + /// Gets the that represents the error that occurred. + /// + /// + /// The that represents the error that occurred. + /// + public Exception Exception { get; } } } diff --git a/src/Renci.SshNet/Common/Extensions.cs b/src/Renci.SshNet/Common/Extensions.cs index 3a5311f07..1e6bb6def 100644 --- a/src/Renci.SshNet/Common/Extensions.cs +++ b/src/Renci.SshNet/Common/Extensions.cs @@ -11,7 +11,7 @@ namespace Renci.SshNet.Common { /// - /// Collection of different extension method + /// Collection of different extension methods. /// internal static partial class Extensions { @@ -24,12 +24,17 @@ internal static partial class Extensions /// public static bool IsNullOrWhiteSpace(this string value) { - if (string.IsNullOrEmpty(value)) return true; + if (string.IsNullOrEmpty(value)) + { + return true; + } for (var i = 0; i < value.Length; i++) { if (!char.IsWhiteSpace(value[i])) + { return false; + } } return true; @@ -97,7 +102,7 @@ internal static T[] Reverse(this T[] array) } /// - /// Prints out + /// Prints out the specified bytes. /// /// The bytes. internal static void DebugPrint(this IEnumerable bytes) @@ -106,8 +111,9 @@ internal static void DebugPrint(this IEnumerable bytes) foreach (var b in bytes) { - sb.AppendFormat(CultureInfo.CurrentCulture, "0x{0:x2}, ", b); + _ = sb.AppendFormat(CultureInfo.CurrentCulture, "0x{0:x2}, ", b); } + Debug.WriteLine(sb.ToString()); } @@ -117,32 +123,37 @@ internal static void DebugPrint(this IEnumerable bytes) /// The type to create. /// Type of the instance to create. /// A reference to the newly created object. - internal static T CreateInstance(this Type type) where T : class + internal static T CreateInstance(this Type type) + where T : class { if (type == null) + { return null; + } + return Activator.CreateInstance(type) as T; } internal static void ValidatePort(this uint value, string argument) { if (value > IPEndPoint.MaxPort) + { throw new ArgumentOutOfRangeException(argument, - string.Format(CultureInfo.InvariantCulture, "Specified value cannot be greater than {0}.", - IPEndPoint.MaxPort)); + string.Format(CultureInfo.InvariantCulture, "Specified value cannot be greater than {0}.", IPEndPoint.MaxPort)); + } } internal static void ValidatePort(this int value, string argument) { if (value < IPEndPoint.MinPort) - throw new ArgumentOutOfRangeException(argument, - string.Format(CultureInfo.InvariantCulture, "Specified value cannot be less than {0}.", - IPEndPoint.MinPort)); + { + throw new ArgumentOutOfRangeException(argument, string.Format(CultureInfo.InvariantCulture, "Specified value cannot be less than {0}.", IPEndPoint.MinPort)); + } if (value > IPEndPoint.MaxPort) - throw new ArgumentOutOfRangeException(argument, - string.Format(CultureInfo.InvariantCulture, "Specified value cannot be greater than {0}.", - IPEndPoint.MaxPort)); + { + throw new ArgumentOutOfRangeException(argument, string.Format(CultureInfo.InvariantCulture, "Specified value cannot be greater than {0}.", IPEndPoint.MaxPort)); + } } /// @@ -163,13 +174,19 @@ internal static void ValidatePort(this int value, string argument) public static byte[] Take(this byte[] value, int offset, int count) { if (value == null) - throw new ArgumentNullException("value"); + { + throw new ArgumentNullException(nameof(value)); + } if (count == 0) + { return Array.Empty; + } if (offset == 0 && value.Length == count) + { return value; + } var taken = new byte[count]; Buffer.BlockCopy(value, offset, taken, 0, count); @@ -192,13 +209,19 @@ public static byte[] Take(this byte[] value, int offset, int count) public static byte[] Take(this byte[] value, int count) { if (value == null) - throw new ArgumentNullException("value"); + { + throw new ArgumentNullException(nameof(value)); + } if (count == 0) + { return Array.Empty; + } if (value.Length == count) + { return value; + } var taken = new byte[count]; Buffer.BlockCopy(value, 0, taken, 0, count); @@ -208,20 +231,31 @@ public static byte[] Take(this byte[] value, int count) public static bool IsEqualTo(this byte[] left, byte[] right) { if (left == null) - throw new ArgumentNullException("left"); + { + throw new ArgumentNullException(nameof(left)); + } + if (right == null) - throw new ArgumentNullException("right"); + { + throw new ArgumentNullException(nameof(right)); + } if (left == right) + { return true; + } if (left.Length != right.Length) + { return false; + } for (var i = 0; i < left.Length; i++) { if (left[i] != right[i]) + { return false; + } } return true; @@ -237,16 +271,22 @@ public static bool IsEqualTo(this byte[] left, byte[] right) public static byte[] TrimLeadingZeros(this byte[] value) { if (value == null) - throw new ArgumentNullException("value"); + { + throw new ArgumentNullException(nameof(value)); + } for (var i = 0; i < value.Length; i++) { if (value[i] == 0) + { continue; + } // if the first byte is non-zero, then we return the byte array as is if (i == 0) + { return value; + } var remainingBytes = value.Length - i; @@ -266,7 +306,10 @@ public static byte[] TrimLeadingZeros(this byte[] value) public static byte[] Pad(this byte[] data, int length) { if (length <= data.Length) + { return data; + } + var newData = new byte[length]; Buffer.BlockCopy(data, 0, newData, newData.Length - data.Length, data.Length); return newData; @@ -275,10 +318,14 @@ public static byte[] Pad(this byte[] data, int length) public static byte[] Concat(this byte[] first, byte[] second) { if (first == null || first.Length == 0) + { return second; + } if (second == null || second.Length == 0) + { return first; + } var concat = new byte[first.Length + second.Length]; Buffer.BlockCopy(first, 0, concat, 0, first.Length); @@ -299,7 +346,10 @@ internal static bool CanWrite(this Socket socket) internal static bool IsConnected(this Socket socket) { if (socket == null) + { return false; + } + return socket.Connected; } } diff --git a/src/Renci.SshNet/Common/HostKeyEventArgs.cs b/src/Renci.SshNet/Common/HostKeyEventArgs.cs index 7f0d6befc..017b1e513 100644 --- a/src/Renci.SshNet/Common/HostKeyEventArgs.cs +++ b/src/Renci.SshNet/Common/HostKeyEventArgs.cs @@ -46,12 +46,9 @@ public class HostKeyEventArgs : EventArgs /// The host. public HostKeyEventArgs(KeyHostAlgorithm host) { - CanTrust = true; // Set default value - + CanTrust = true; HostKey = host.Data; - HostKeyName = host.Name; - KeyLength = host.Key.KeyLength; using (var md5 = CryptoAbstraction.CreateMD5()) diff --git a/src/Renci.SshNet/Common/NetConfServerException.cs b/src/Renci.SshNet/Common/NetConfServerException.cs index 86fbeabef..39f3f8eb7 100644 --- a/src/Renci.SshNet/Common/NetConfServerException.cs +++ b/src/Renci.SshNet/Common/NetConfServerException.cs @@ -34,8 +34,8 @@ public NetConfServerException(string message) /// /// The message. /// The inner exception. - public NetConfServerException(string message, Exception innerException) : - base(message, innerException) + public NetConfServerException(string message, Exception innerException) + : base(message, innerException) { } diff --git a/src/Renci.SshNet/Common/ObjectIdentifier.cs b/src/Renci.SshNet/Common/ObjectIdentifier.cs index 3ff128bc6..ab491cce6 100644 --- a/src/Renci.SshNet/Common/ObjectIdentifier.cs +++ b/src/Renci.SshNet/Common/ObjectIdentifier.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Common { /// - /// Describes object identifier for DER encoding + /// Describes object identifier for DER encoding. /// public struct ObjectIdentifier { @@ -13,14 +13,22 @@ public struct ObjectIdentifier public ulong[] Identifiers { get; private set; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the struct. /// /// The identifiers. + /// is . + /// has less than two elements. public ObjectIdentifier(params ulong[] identifiers) - : this() { + if (identifiers == null) + { + throw new ArgumentNullException(nameof(identifiers)); + } + if (identifiers.Length < 2) - throw new ArgumentException("identifiers"); + { + throw new ArgumentException("Must contain at least two elements.", nameof(identifiers)); + } Identifiers = identifiers; } diff --git a/src/Renci.SshNet/Common/PacketDump.cs b/src/Renci.SshNet/Common/PacketDump.cs index cd68549d6..c9357a3af 100644 --- a/src/Renci.SshNet/Common/PacketDump.cs +++ b/src/Renci.SshNet/Common/PacketDump.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Common { - internal class PacketDump + internal static class PacketDump { public static string Create(List data, int indentLevel) { @@ -15,9 +15,14 @@ public static string Create(List data, int indentLevel) public static string Create(byte[] data, int indentLevel) { if (data == null) - throw new ArgumentNullException("data"); + { + throw new ArgumentNullException(nameof(data)); + } + if (indentLevel < 0) - throw new ArgumentOutOfRangeException("indentLevel", "Cannot be less than zero."); + { + throw new ArgumentOutOfRangeException(nameof(indentLevel), "Cannot be less than zero."); + } const int lineWidth = 16; @@ -31,12 +36,12 @@ public static string Create(byte[] data, int indentLevel) if (result.Length > 0) { - result.Append(Environment.NewLine); + _ = result.Append(Environment.NewLine); } - result.Append(indentChars); - result.Append(pos.ToString("X8")); - result.Append(" "); + _ = result.Append(indentChars); + _ = result.Append(pos.ToString("X8")); + _ = result.Append(" "); while (true) { @@ -48,10 +53,11 @@ public static string Create(byte[] data, int indentLevel) } } - result.Append(AsHex(line, linePos)); - result.Append(" "); - result.Append(AsAscii(line, linePos)); + _ = result.Append(AsHex(line, linePos)); + _ = result.Append(" "); + _ = result.Append(AsAscii(line, linePos)); } + return result.ToString(); } @@ -63,15 +69,15 @@ private static string AsHex(byte[] data, int length) { if (i > 0) { - hex.Append(' '); + _ = hex.Append(' '); } - hex.Append(data[i].ToString("X2", CultureInfo.InvariantCulture)); + _ = hex.Append(data[i].ToString("X2", CultureInfo.InvariantCulture)); } if (length < data.Length) { - hex.Append(new string(' ', (data.Length - length) * 3)); + _ = hex.Append(new string(' ', (data.Length - length) * 3)); } return hex.ToString(); @@ -88,17 +94,17 @@ private static string AsAscii(byte[] data, int length) { var b = data[i]; - if (b < 32 || b >= 127) + if (b is < 32 or >= 127) { - ascii.Append(dot); + _ = ascii.Append(dot); } else { - ascii.Append(encoding.GetString(data, i, 1)); + _ = ascii.Append(encoding.GetString(data, i, 1)); } } return ascii.ToString(); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Common/PipeStream.cs b/src/Renci.SshNet/Common/PipeStream.cs index fac54fb62..71a82e1d8 100644 --- a/src/Renci.SshNet/Common/PipeStream.cs +++ b/src/Renci.SshNet/Common/PipeStream.cs @@ -1,40 +1,38 @@ -锘縩amespace Renci.SshNet.Common -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Threading; - using System.Globalization; +锘縰sing System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Threading; +namespace Renci.SshNet.Common +{ /// - /// PipeStream is a thread-safe read/write data stream for use between two threads in a + /// PipeStream is a thread-safe read/write data stream for use between two threads in a /// single-producer/single-consumer type problem. /// /// 2006/10/13 1.0 /// Update on 2008/10/9 1.1 - uses Monitor instead of Manual Reset events for more elegant synchronicity. /// - /// Copyright (c) 2006 James Kolpack (james dot kolpack at google mail) - /// - /// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and - /// associated documentation files (the "Software"), to deal in the Software without restriction, - /// including without limitation the rights to use, copy, modify, merge, publish, distribute, - /// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - /// furnished to do so, subject to the following conditions: - /// - /// The above copyright notice and this permission notice shall be included in all copies or - /// substantial portions of the Software. - /// - /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - /// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - /// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - /// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT - /// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - /// OTHER DEALINGS IN THE SOFTWARE. + /// Copyright (c) 2006 James Kolpack (james dot kolpack at google mail) + /// + /// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + /// associated documentation files (the "Software"), to deal in the Software without restriction, + /// including without limitation the rights to use, copy, modify, merge, publish, distribute, + /// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + /// furnished to do so, subject to the following conditions: + /// + /// The above copyright notice and this permission notice shall be included in all copies or + /// substantial portions of the Software. + /// + /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + /// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR + /// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + /// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT + /// OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + /// OTHER DEALINGS IN THE SOFTWARE. /// public class PipeStream : Stream { - #region Private members - /// /// Queue of bytes provides the datastructure for transmitting from an /// input stream to an output stream. @@ -64,10 +62,6 @@ public class PipeStream : Stream /// private bool _isDisposed; - #endregion - - #region Public properties - /// /// Gets or sets the maximum number of bytes to store in the buffer. /// @@ -87,7 +81,7 @@ public long MaxBufferLength /// Setting to true will remove the possibility of ending a stream reader prematurely. /// /// - /// true if block last read method before the buffer is empty; otherwise, false. + /// true if block last read method before the buffer is empty; otherwise, false. /// /// Methods were called after the stream was closed. public bool BlockLastReadBuffer @@ -95,28 +89,32 @@ public bool BlockLastReadBuffer get { if (_isDisposed) + { throw CreateObjectDisposedException(); + } return _canBlockLastRead; } set { if (_isDisposed) + { throw CreateObjectDisposedException(); + } _canBlockLastRead = value; // when turning off the block last read, signal Read() that it may now read the rest of the buffer. if (!_canBlockLastRead) + { lock (_buffer) + { Monitor.Pulse(_buffer); + } + } } } - #endregion - - #region Stream overide methods - /// /// When overridden in a derived class, clears all buffers for this stream and causes any buffered data to be written to the underlying device. /// @@ -129,7 +127,9 @@ public bool BlockLastReadBuffer public override void Flush() { if (_isDisposed) + { throw CreateObjectDisposedException(); + } _isFlushed = true; lock (_buffer) @@ -163,37 +163,57 @@ public override void SetLength(long value) throw new NotSupportedException(); } - /// - ///When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. - /// - /// - ///The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero if the stream is closed or end of the stream has been reached. - /// - ///The zero-based byte offset in buffer at which to begin storing the data read from the current stream. - ///The maximum number of bytes to be read from the current stream. - ///An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source. - ///The sum of offset and count is larger than the buffer length. - ///Methods were called after the stream was closed. - ///The stream does not support reading. - /// is null. - ///An I/O error occurs. - ///offset or count is negative. + /// + /// When overridden in a derived class, reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + /// + /// + /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero if the stream is closed or end of the stream has been reached. + /// + /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between offset and (offset + count - 1) replaced by the bytes read from the current source. + /// The zero-based byte offset in buffer at which to begin storing the data read from the current stream. + /// The maximum number of bytes to be read from the current stream. + /// The sum of offset and count is larger than the buffer length. + /// Methods were called after the stream was closed. + /// The stream does not support reading. + /// is null. + /// An I/O error occurs. + /// offset or count is negative. public override int Read(byte[] buffer, int offset, int count) { if (offset != 0) + { throw new NotSupportedException("Offsets with value of non-zero are not supported"); + } + if (buffer == null) - throw new ArgumentNullException("buffer"); + { + throw new ArgumentNullException(nameof(buffer)); + } + if (offset + count > buffer.Length) + { throw new ArgumentException("The sum of offset and count is greater than the buffer length."); + } + if (offset < 0 || count < 0) - throw new ArgumentOutOfRangeException("offset", "offset or count is negative."); + { + throw new ArgumentOutOfRangeException(nameof(offset), "offset or count is negative."); + } + if (BlockLastReadBuffer && count >= _maxBufferLength) + { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "count({0}) > mMaxBufferLength({1})", count, _maxBufferLength)); + } + if (_isDisposed) + { throw CreateObjectDisposedException(); + } + if (count == 0) + { return 0; + } var readLength = 0; @@ -201,7 +221,7 @@ public override int Read(byte[] buffer, int offset, int count) { while (!_isDisposed && !ReadAvailable(count)) { - Monitor.Wait(_buffer); + _ = Monitor.Wait(_buffer); } // return zero when the read is interrupted by a close/dispose of the stream @@ -223,46 +243,64 @@ public override int Read(byte[] buffer, int offset, int count) } /// - /// Returns true if there are + /// Returns a value indicating whether data is available. /// /// The count. - /// True if data available; otherwisefalse. + /// + /// if data is available; otherwise, . + /// private bool ReadAvailable(int count) { var length = Length; return (_isFlushed || length >= count) && (length >= (count + 1) || !BlockLastReadBuffer); } - /// - ///When overridden in a derived class, writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. - /// - ///The zero-based byte offset in buffer at which to begin copying bytes to the current stream. - ///The number of bytes to be written to the current stream. - ///An array of bytes. This method copies count bytes from buffer to the current stream. - ///An I/O error occurs. - ///The stream does not support writing. - ///Methods were called after the stream was closed. - /// is null. - ///The sum of offset and count is greater than the buffer length. - ///offset or count is negative. + /// + /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// + /// An array of bytes. This method copies count bytes from buffer to the current stream. + /// The zero-based byte offset in buffer at which to begin copying bytes to the current stream. + /// The number of bytes to be written to the current stream. + /// An I/O error occurs. + /// The stream does not support writing. + /// Methods were called after the stream was closed. + /// is null. + /// The sum of offset and count is greater than the buffer length. + /// offset or count is negative. public override void Write(byte[] buffer, int offset, int count) { if (buffer == null) - throw new ArgumentNullException("buffer"); + { + throw new ArgumentNullException(nameof(buffer)); + } + if (offset + count > buffer.Length) + { throw new ArgumentException("The sum of offset and count is greater than the buffer length."); + } + if (offset < 0 || count < 0) - throw new ArgumentOutOfRangeException("offset", "offset or count is negative."); + { + throw new ArgumentOutOfRangeException(nameof(offset), "offset or count is negative."); + } + if (_isDisposed) + { throw CreateObjectDisposedException(); + } + if (count == 0) + { return; + } lock (_buffer) { // wait until the buffer isn't full while (Length >= _maxBufferLength) - Monitor.Wait(_buffer); + { + _ = Monitor.Wait(_buffer); + } _isFlushed = false; // if it were flushed before, it soon will not be. @@ -297,30 +335,30 @@ protected override void Dispose(bool disposing) } } - /// - ///When overridden in a derived class, gets a value indicating whether the current stream supports reading. - /// - /// - ///true if the stream supports reading; otherwise, false. - /// + /// + /// Gets a value indicating whether the current stream supports reading. + /// + /// + /// true if the stream supports reading; otherwise, false. + /// public override bool CanRead { get { return !_isDisposed; } } /// - /// When overridden in a derived class, gets a value indicating whether the current stream supports seeking. + /// Gets a value indicating whether the current stream supports seeking. /// /// /// true if the stream supports seeking; otherwise, false. - /// + /// public override bool CanSeek { get { return false; } } /// - /// When overridden in a derived class, gets a value indicating whether the current stream supports writing. + /// Gets a value indicating whether the current stream supports writing. /// /// /// true if the stream supports writing; otherwise, false. @@ -331,7 +369,7 @@ public override bool CanWrite } /// - /// When overridden in a derived class, gets the length in bytes of the stream. + /// Gets the length in bytes of the stream. /// /// /// A long value representing the length of the stream in bytes. @@ -343,14 +381,16 @@ public override long Length get { if (_isDisposed) + { throw CreateObjectDisposedException(); + } return _buffer.Count; } } /// - /// When overridden in a derived class, gets or sets the position within the current stream. + /// Gets or sets the position within the current stream. /// /// /// The current position within the stream. @@ -362,8 +402,6 @@ public override long Position set { throw new NotSupportedException(); } } - #endregion - private ObjectDisposedException CreateObjectDisposedException() { return new ObjectDisposedException(GetType().FullName); diff --git a/src/Renci.SshNet/Common/PortForwardEventArgs.cs b/src/Renci.SshNet/Common/PortForwardEventArgs.cs index 96a7f8255..4d1f1656d 100644 --- a/src/Renci.SshNet/Common/PortForwardEventArgs.cs +++ b/src/Renci.SshNet/Common/PortForwardEventArgs.cs @@ -1,37 +1,41 @@ 锘縰sing System; +using System.Net; namespace Renci.SshNet.Common { /// - /// Provides data for event. + /// Provides data for event. /// public class PortForwardEventArgs : EventArgs { - /// - /// Gets request originator host. - /// - public string OriginatorHost { get; private set; } - - /// - /// Gets request originator port. - /// - public uint OriginatorPort { get; private set; } - /// /// Initializes a new instance of the class. /// /// The host. /// The port. /// is null. - /// is not within and . + /// is not within and . internal PortForwardEventArgs(string host, uint port) { if (host == null) - throw new ArgumentNullException("host"); + { + throw new ArgumentNullException(nameof(host)); + } + port.ValidatePort("port"); OriginatorHost = host; OriginatorPort = port; } + + /// + /// Gets request originator host. + /// + public string OriginatorHost { get; } + + /// + /// Gets request originator port. + /// + public uint OriginatorPort { get; } } } diff --git a/src/Renci.SshNet/Common/PosixPath.cs b/src/Renci.SshNet/Common/PosixPath.cs index 465916b3a..2d028bd67 100644 --- a/src/Renci.SshNet/Common/PosixPath.cs +++ b/src/Renci.SshNet/Common/PosixPath.cs @@ -2,16 +2,45 @@ namespace Renci.SshNet.Common { + /// + /// Represents a POSIX path. + /// internal class PosixPath { + private PosixPath() + { + } + + /// + /// Gets the directory of the path. + /// + /// + /// The directory of the path. + /// public string Directory { get; private set; } + + /// + /// Gets the file part of the path. + /// + /// + /// The file part of the path, or if the path represents a directory. + /// public string File { get; private set; } + /// + /// Create a from the specified path. + /// + /// The path. + /// + /// A created from the specified path. + /// + /// is . + /// is empty (""). public static PosixPath CreateAbsoluteOrRelativeFilePath(string path) { if (path == null) { - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(path)); } var posixPath = new PosixPath(); @@ -21,7 +50,7 @@ public static PosixPath CreateAbsoluteOrRelativeFilePath(string path) { if (path.Length == 0) { - throw new ArgumentException("The path is a zero-length string.", "path"); + throw new ArgumentException("The path is a zero-length string.", nameof(path)); } posixPath.Directory = "."; @@ -54,7 +83,7 @@ public static PosixPath CreateAbsoluteOrRelativeFilePath(string path) /// /// The file name part of . /// - /// is null. + /// is null. /// /// /// If contains no forward slash, then @@ -67,13 +96,21 @@ public static PosixPath CreateAbsoluteOrRelativeFilePath(string path) public static string GetFileName(string path) { if (path == null) - throw new ArgumentNullException("path"); + { + throw new ArgumentNullException(nameof(path)); + } var pathEnd = path.LastIndexOf('/'); if (pathEnd == -1) + { return path; + } + if (pathEnd == path.Length - 1) + { return string.Empty; + } + return path.Substring(pathEnd + 1); } @@ -89,15 +126,26 @@ public static string GetFileName(string path) public static string GetDirectoryName(string path) { if (path == null) - throw new ArgumentNullException("path"); + { + throw new ArgumentNullException(nameof(path)); + } var pathEnd = path.LastIndexOf('/'); if (pathEnd == -1) + { return "."; + } + if (pathEnd == 0) + { return "/"; + } + if (pathEnd == path.Length - 1) + { return path.Substring(0, pathEnd); + } + return path.Substring(0, pathEnd); } } diff --git a/src/Renci.SshNet/Common/ProxyException.cs b/src/Renci.SshNet/Common/ProxyException.cs index efb387b45..371f4f7a6 100644 --- a/src/Renci.SshNet/Common/ProxyException.cs +++ b/src/Renci.SshNet/Common/ProxyException.cs @@ -14,14 +14,14 @@ namespace Renci.SshNet.Common public class ProxyException : SshException { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// public ProxyException() { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The message. public ProxyException(string message) @@ -30,12 +30,12 @@ public ProxyException(string message) } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The message. /// The inner exception. - public ProxyException(string message, Exception innerException) : - base(message, innerException) + public ProxyException(string message, Exception innerException) + : base(message, innerException) { } diff --git a/src/Renci.SshNet/Common/ScpDownloadEventArgs.cs b/src/Renci.SshNet/Common/ScpDownloadEventArgs.cs index 95ddcd638..59c6312af 100644 --- a/src/Renci.SshNet/Common/ScpDownloadEventArgs.cs +++ b/src/Renci.SshNet/Common/ScpDownloadEventArgs.cs @@ -7,21 +7,6 @@ namespace Renci.SshNet.Common /// public class ScpDownloadEventArgs : EventArgs { - /// - /// Gets the downloaded filename. - /// - public string Filename { get; private set; } - - /// - /// Gets the downloaded file size. - /// - public long Size { get; private set; } - - /// - /// Gets number of downloaded bytes so far. - /// - public long Downloaded { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -34,5 +19,20 @@ public ScpDownloadEventArgs(string filename, long size, long downloaded) Size = size; Downloaded = downloaded; } + + /// + /// Gets the downloaded filename. + /// + public string Filename { get; } + + /// + /// Gets the downloaded file size. + /// + public long Size { get; } + + /// + /// Gets number of downloaded bytes so far. + /// + public long Downloaded { get; } } } diff --git a/src/Renci.SshNet/Common/ScpException.cs b/src/Renci.SshNet/Common/ScpException.cs index e98bc688d..42d7e8d62 100644 --- a/src/Renci.SshNet/Common/ScpException.cs +++ b/src/Renci.SshNet/Common/ScpException.cs @@ -34,8 +34,8 @@ public ScpException(string message) /// /// The message. /// The inner exception. - public ScpException(string message, Exception innerException) : - base(message, innerException) + public ScpException(string message, Exception innerException) + : base(message, innerException) { } diff --git a/src/Renci.SshNet/Common/ScpUploadEventArgs.cs b/src/Renci.SshNet/Common/ScpUploadEventArgs.cs index 555bdc07c..ca8514e9b 100644 --- a/src/Renci.SshNet/Common/ScpUploadEventArgs.cs +++ b/src/Renci.SshNet/Common/ScpUploadEventArgs.cs @@ -7,21 +7,6 @@ namespace Renci.SshNet.Common /// public class ScpUploadEventArgs : EventArgs { - /// - /// Gets the uploaded filename. - /// - public string Filename { get; private set; } - - /// - /// Gets the uploaded file size. - /// - public long Size { get; private set; } - - /// - /// Gets number of uploaded bytes so far. - /// - public long Uploaded { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -34,5 +19,20 @@ public ScpUploadEventArgs(string filename, long size, long uploaded) Size = size; Uploaded = uploaded; } + + /// + /// Gets the uploaded filename. + /// + public string Filename { get; } + + /// + /// Gets the uploaded file size. + /// + public long Size { get; } + + /// + /// Gets number of uploaded bytes so far. + /// + public long Uploaded { get; } } } diff --git a/src/Renci.SshNet/Common/SemaphoreLight.cs b/src/Renci.SshNet/Common/SemaphoreLight.cs index 55e4a840a..f3210c788 100644 --- a/src/Renci.SshNet/Common/SemaphoreLight.cs +++ b/src/Renci.SshNet/Common/SemaphoreLight.cs @@ -14,15 +14,17 @@ public class SemaphoreLight : IDisposable private int _currentCount; /// - /// Initializes a new instance of the class, specifying - /// the initial number of requests that can be granted concurrently. + /// Initializes a new instance of the class, specifying the initial number of requests that can + /// be granted concurrently. /// /// The initial number of requests for the semaphore that can be granted concurrently. /// is a negative number. public SemaphoreLight(int initialCount) { - if (initialCount < 0 ) - throw new ArgumentOutOfRangeException("initialCount", "The value cannot be negative."); + if (initialCount < 0) + { + throw new ArgumentOutOfRangeException(nameof(initialCount), "The value cannot be negative."); + } _currentCount = initialCount; } @@ -30,10 +32,13 @@ public SemaphoreLight(int initialCount) /// /// Gets the current count of the . /// - public int CurrentCount { get { return _currentCount; } } + public int CurrentCount + { + get { return _currentCount; } + } /// - /// Returns a that can be used to wait on the semaphore. + /// Gets a that can be used to wait on the semaphore. /// /// /// A that can be used to wait on the semaphore. @@ -51,10 +56,7 @@ public WaitHandle AvailableWaitHandle { lock (_lock) { - if (_waitHandle == null) - { - _waitHandle = new ManualResetEvent(_currentCount > 0); - } + _waitHandle ??= new ManualResetEvent(_currentCount > 0); } } @@ -89,7 +91,7 @@ public int Release(int releaseCount) // signal waithandle when the original semaphore count was zero if (_waitHandle != null && oldCount == 0) { - _waitHandle.Set(); + _ = _waitHandle.Set(); } Monitor.PulseAll(_lock); @@ -107,7 +109,7 @@ public void Wait() { while (_currentCount < 1) { - Monitor.Wait(_lock); + _ = Monitor.Wait(_lock); } _currentCount--; @@ -115,7 +117,7 @@ public void Wait() // unsignal waithandle when the semaphore count reaches zero if (_waitHandle != null && _currentCount == 0) { - _waitHandle.Reset(); + _ = _waitHandle.Reset(); } Monitor.PulseAll(_lock); @@ -133,7 +135,9 @@ public void Wait() public bool Wait(int millisecondsTimeout) { if (millisecondsTimeout < -1) - throw new ArgumentOutOfRangeException("millisecondsTimeout", "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); + { + throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); + } return WaitWithTimeout(millisecondsTimeout); } @@ -149,8 +153,10 @@ public bool Wait(int millisecondsTimeout) public bool Wait(TimeSpan timeout) { var timeoutInMilliseconds = timeout.TotalMilliseconds; - if (timeoutInMilliseconds < -1d || timeoutInMilliseconds > int.MaxValue) - throw new ArgumentOutOfRangeException("timeout", "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); + if (timeoutInMilliseconds is < -1d or > int.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(timeout), "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); + } return WaitWithTimeout((int) timeoutInMilliseconds); } @@ -162,14 +168,18 @@ private bool WaitWithTimeout(int timeoutInMilliseconds) if (timeoutInMilliseconds == Session.Infinite) { while (_currentCount < 1) - Monitor.Wait(_lock); + { + _ = Monitor.Wait(_lock); + } } else { if (_currentCount < 1) { if (timeoutInMilliseconds > 0) + { return false; + } var remainingTimeInMilliseconds = timeoutInMilliseconds; var startTicks = Environment.TickCount; @@ -184,7 +194,9 @@ private bool WaitWithTimeout(int timeoutInMilliseconds) var elapsed = Environment.TickCount - startTicks; remainingTimeInMilliseconds -= elapsed; if (remainingTimeInMilliseconds < 0) + { return false; + } } } } @@ -194,7 +206,7 @@ private bool WaitWithTimeout(int timeoutInMilliseconds) // unsignal waithandle when the semaphore count is zero if (_waitHandle != null && _currentCount == 0) { - _waitHandle.Reset(); + _ = _waitHandle.Reset(); } Monitor.PulseAll(_lock); @@ -204,11 +216,11 @@ private bool WaitWithTimeout(int timeoutInMilliseconds) } /// - /// Finalizes the current . + /// Finalizes an instance of the class. /// ~SemaphoreLight() { - Dispose(false); + Dispose(disposing: false); } /// @@ -216,12 +228,12 @@ private bool WaitWithTimeout(int timeoutInMilliseconds) /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected void Dispose(bool disposing) diff --git a/src/Renci.SshNet/Common/SftpPathNotFoundException.cs b/src/Renci.SshNet/Common/SftpPathNotFoundException.cs index 681a4fe5f..f56f2ea31 100644 --- a/src/Renci.SshNet/Common/SftpPathNotFoundException.cs +++ b/src/Renci.SshNet/Common/SftpPathNotFoundException.cs @@ -34,8 +34,8 @@ public SftpPathNotFoundException(string message) /// /// The message. /// The inner exception. - public SftpPathNotFoundException(string message, Exception innerException) : - base(message, innerException) + public SftpPathNotFoundException(string message, Exception innerException) + : base(message, innerException) { } diff --git a/src/Renci.SshNet/Common/SftpPermissionDeniedException.cs b/src/Renci.SshNet/Common/SftpPermissionDeniedException.cs index 559c98cf3..a734bdb19 100644 --- a/src/Renci.SshNet/Common/SftpPermissionDeniedException.cs +++ b/src/Renci.SshNet/Common/SftpPermissionDeniedException.cs @@ -34,8 +34,8 @@ public SftpPermissionDeniedException(string message) /// /// The message. /// The inner exception. - public SftpPermissionDeniedException(string message, Exception innerException) : - base(message, innerException) + public SftpPermissionDeniedException(string message, Exception innerException) + : base(message, innerException) { } diff --git a/src/Renci.SshNet/Common/ShellDataEventArgs.cs b/src/Renci.SshNet/Common/ShellDataEventArgs.cs index 34fea8b46..e99913d22 100644 --- a/src/Renci.SshNet/Common/ShellDataEventArgs.cs +++ b/src/Renci.SshNet/Common/ShellDataEventArgs.cs @@ -3,20 +3,10 @@ namespace Renci.SshNet.Common { /// - /// Provides data for Shell DataReceived event + /// Provides data for Shell DataReceived event. /// public class ShellDataEventArgs : EventArgs { - /// - /// Gets the data. - /// - public byte[] Data { get; private set; } - - /// - /// Gets the line data. - /// - public string Line { get; private set; } - /// /// Initializes a new instance of the class. /// @@ -34,5 +24,15 @@ public ShellDataEventArgs(string line) { Line = line; } + + /// + /// Gets the data. + /// + public byte[] Data { get; } + + /// + /// Gets the line data. + /// + public string Line { get; } } } diff --git a/src/Renci.SshNet/Common/SshAuthenticationException.cs b/src/Renci.SshNet/Common/SshAuthenticationException.cs index 4c6f72546..260fe552d 100644 --- a/src/Renci.SshNet/Common/SshAuthenticationException.cs +++ b/src/Renci.SshNet/Common/SshAuthenticationException.cs @@ -18,7 +18,6 @@ public class SshAuthenticationException : SshException /// public SshAuthenticationException() { - } /// @@ -28,7 +27,6 @@ public SshAuthenticationException() public SshAuthenticationException(string message) : base(message) { - } /// @@ -36,8 +34,8 @@ public SshAuthenticationException(string message) /// /// The message. /// The inner exception. - public SshAuthenticationException(string message, Exception innerException) : - base(message, innerException) + public SshAuthenticationException(string message, Exception innerException) + : base(message, innerException) { } diff --git a/src/Renci.SshNet/Common/SshData.cs b/src/Renci.SshNet/Common/SshData.cs index 844bace7a..0a10eee64 100644 --- a/src/Renci.SshNet/Common/SshData.cs +++ b/src/Renci.SshNet/Common/SshData.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Common { /// - /// Base ssh data serialization type + /// Base ssh data serialization type. /// public abstract class SshData { @@ -57,7 +57,7 @@ protected virtual int BufferCapacity /// Gets data bytes array. /// /// - /// A array representation of data structure. + /// A array representation of data structure. /// public byte[] GetBytes() { @@ -86,7 +86,9 @@ protected virtual void WriteBytes(SshDataStream stream) public void Load(byte[] data) { if (data == null) - throw new ArgumentNullException("data"); + { + throw new ArgumentNullException(nameof(data)); + } LoadInternal(data, 0, data.Length); } @@ -101,7 +103,9 @@ public void Load(byte[] data) public void Load(byte[] data, int offset, int count) { if (data == null) - throw new ArgumentNullException("data"); + { + throw new ArgumentNullException(nameof(data)); + } LoadInternal(data, offset, count); } @@ -130,7 +134,7 @@ protected byte[] ReadBytes() { var bytesLength = (int) (_stream.Length - _stream.Position); var data = new byte[bytesLength]; - _stream.Read(data, 0, bytesLength); + _ = _stream.Read(data, 0, bytesLength); return data; } @@ -142,15 +146,19 @@ protected byte[] ReadBytes() /// is greater than the internal buffer size. protected byte[] ReadBytes(int length) { - // Note that this also prevents allocating non-relevant lengths, such as if length is greater than _data.Count but less than int.MaxValue. - // For the nerds, the condition translates to: if (length > data.Count && length < int.MaxValue) - // Which probably would cause all sorts of exception, most notably OutOfMemoryException. + /* + * Note that this also prevents allocating non-relevant lengths, such as if length is greater than _data.Count but less than int.MaxValue. + * For the nerds, the condition translates to: if (length > data.Count && length < int.MaxValue) + * Which probably would cause all sorts of exception, most notably OutOfMemoryException. + */ var data = new byte[length]; var bytesRead = _stream.Read(data, 0, length); if (bytesRead < length) - throw new ArgumentOutOfRangeException("length"); + { + throw new ArgumentOutOfRangeException(nameof(length)); + } return data; } @@ -163,51 +171,63 @@ protected byte ReadByte() { var byteRead = _stream.ReadByte(); if (byteRead == -1) + { throw new InvalidOperationException("Attempt to read past the end of the SSH data stream."); + } + return (byte) byteRead; } /// - /// Reads next boolean data type from internal buffer. + /// Reads the next from the internal buffer. /// - /// Boolean read. + /// + /// The that was read. + /// protected bool ReadBoolean() { return ReadByte() != 0; } /// - /// Reads next uint16 data type from internal buffer. + /// Reads the next from the internal buffer. /// - /// uint16 read + /// + /// The that was read. + /// protected ushort ReadUInt16() { return Pack.BigEndianToUInt16(ReadBytes(2)); } /// - /// Reads next uint32 data type from internal buffer. + /// Reads the next from the internal buffer. /// - /// uint32 read + /// + /// The that was read. + /// protected uint ReadUInt32() { return Pack.BigEndianToUInt32(ReadBytes(4)); } /// - /// Reads next uint64 data type from internal buffer. + /// Reads the next from the internal buffer. /// - /// uint64 read + /// + /// The that was read. + /// protected ulong ReadUInt64() { return Pack.BigEndianToUInt64(ReadBytes(8)); } /// - /// Reads next string data type from internal buffer using the specific encoding. + /// Reads the next from the internal buffer using the specified encoding. /// + /// The character encoding to use. /// - /// The read. + /// The that was read. /// protected string ReadString(Encoding encoding) { @@ -244,12 +264,14 @@ protected string[] ReadNamesList() protected IDictionary ReadExtensionPair() { var result = new Dictionary(); + while (!IsEndOfData) { var extensionName = ReadString(Ascii); var extensionData = ReadString(Ascii); result.Add(extensionName, extensionData); } + return result; } diff --git a/src/Renci.SshNet/Common/SshDataStream.cs b/src/Renci.SshNet/Common/SshDataStream.cs index 0e024491c..54a5505f5 100644 --- a/src/Renci.SshNet/Common/SshDataStream.cs +++ b/src/Renci.SshNet/Common/SshDataStream.cs @@ -21,7 +21,7 @@ public SshDataStream(int capacity) } /// - /// Initializes a new non-resizable instance of the class based on the specified byte array. + /// Initializes a new instance of the class for the specified byte array. /// /// The array of unsigned bytes from which to create the current stream. /// is null. @@ -31,7 +31,7 @@ public SshDataStream(byte[] buffer) } /// - /// Initializes a new non-resizable instance of the class based on the specified byte array. + /// Initializes a new instance of the class for the specified byte array. /// /// The array of unsigned bytes from which to create the current stream. /// The zero-based offset in at which to begin reading SSH data. @@ -94,7 +94,9 @@ public void Write(BigInteger data) public void Write(byte[] data) { if (data == null) - throw new ArgumentNullException("data"); + { + throw new ArgumentNullException(nameof(data)); + } Write(data, 0, data.Length); } @@ -125,7 +127,9 @@ public byte[] ReadBinary() public void WriteBinary(byte[] buffer) { if (buffer == null) - throw new ArgumentNullException("buffer"); + { + throw new ArgumentNullException(nameof(buffer)); + } WriteBinary(buffer, 0, buffer.Length); } @@ -155,7 +159,9 @@ public void WriteBinary(byte[] buffer, int offset, int count) public void Write(string s, Encoding encoding) { if (encoding == null) - throw new ArgumentNullException("encoding"); + { + throw new ArgumentNullException(nameof(encoding)); + } var bytes = encoding.GetBytes(s); WriteBinary(bytes, 0, bytes.Length); @@ -201,6 +207,7 @@ public ulong ReadUInt64() /// /// Reads the next data type from the SSH data stream. /// + /// The character encoding to use. /// /// The read from the SSH data stream. /// @@ -217,27 +224,6 @@ public string ReadString(Encoding encoding) return encoding.GetString(bytes, 0, bytes.Length); } - /// - /// Reads next specified number of bytes data type from internal buffer. - /// - /// Number of bytes to read. - /// - /// An array of bytes that was read from the internal buffer. - /// - /// is greater than the internal buffer size. - private byte[] ReadBytes(int length) - { - var data = new byte[length]; - var bytesRead = Read(data, 0, length); - - if (bytesRead < length) - throw new ArgumentOutOfRangeException("length", - string.Format(CultureInfo.InvariantCulture, - "The requested length ({0}) is greater than the actual number of bytes read ({1}).", length, bytesRead)); - - return data; - } - /// /// Writes the stream contents to a byte array, regardless of the . /// @@ -254,7 +240,29 @@ public override byte[] ToArray() { return GetBuffer(); } + return base.ToArray(); } + + /// + /// Reads next specified number of bytes data type from internal buffer. + /// + /// Number of bytes to read. + /// + /// An array of bytes that was read from the internal buffer. + /// + /// is greater than the internal buffer size. + private byte[] ReadBytes(int length) + { + var data = new byte[length]; + var bytesRead = Read(data, 0, length); + + if (bytesRead < length) + { + throw new ArgumentOutOfRangeException(nameof(length), string.Format(CultureInfo.InvariantCulture, "The requested length ({0}) is greater than the actual number of bytes read ({1}).", length, bytesRead)); + } + + return data; + } } } diff --git a/src/Renci.SshNet/Common/SshOperationTimeoutException.cs b/src/Renci.SshNet/Common/SshOperationTimeoutException.cs index 7dff901f6..9fcce26ae 100644 --- a/src/Renci.SshNet/Common/SshOperationTimeoutException.cs +++ b/src/Renci.SshNet/Common/SshOperationTimeoutException.cs @@ -34,8 +34,8 @@ public SshOperationTimeoutException(string message) /// /// The message. /// The inner exception. - public SshOperationTimeoutException(string message, Exception innerException) : - base(message, innerException) + public SshOperationTimeoutException(string message, Exception innerException) + : base(message, innerException) { } diff --git a/src/Renci.SshNet/Common/SshPassPhraseNullOrEmptyException.cs b/src/Renci.SshNet/Common/SshPassPhraseNullOrEmptyException.cs index 1aa0f0d9d..102b585d7 100644 --- a/src/Renci.SshNet/Common/SshPassPhraseNullOrEmptyException.cs +++ b/src/Renci.SshNet/Common/SshPassPhraseNullOrEmptyException.cs @@ -6,7 +6,7 @@ namespace Renci.SshNet.Common { /// - /// The exception that is thrown when pass phrase for key file is empty or null + /// The exception that is thrown when pass phrase for key file is empty or . /// #if FEATURE_BINARY_SERIALIZATION [Serializable] @@ -18,7 +18,6 @@ public class SshPassPhraseNullOrEmptyException : SshException /// public SshPassPhraseNullOrEmptyException() { - } /// @@ -28,7 +27,6 @@ public SshPassPhraseNullOrEmptyException() public SshPassPhraseNullOrEmptyException(string message) : base(message) { - } /// @@ -36,8 +34,8 @@ public SshPassPhraseNullOrEmptyException(string message) /// /// The message. /// The inner exception. - public SshPassPhraseNullOrEmptyException(string message, Exception innerException) : - base(message, innerException) + public SshPassPhraseNullOrEmptyException(string message, Exception innerException) + : base(message, innerException) { } diff --git a/src/Renci.SshNet/Common/TerminalModes.cs b/src/Renci.SshNet/Common/TerminalModes.cs index 98c7b8fe5..8737872b8 100644 --- a/src/Renci.SshNet/Common/TerminalModes.cs +++ b/src/Renci.SshNet/Common/TerminalModes.cs @@ -7,21 +7,21 @@ public enum TerminalModes : byte { /// /// Indicates end of options. - /// + /// TTY_OP_END = 0, - + /// /// Interrupt character; 255 if none. Similarly for the other characters. Not all of these characters are supported on all systems. - /// + /// VINTR = 1, /// /// The quit character (sends SIGQUIT signal on POSIX systems). - /// + /// VQUIT = 2, - + /// - /// Erase the character to left of the cursor. + /// Erase the character to left of the cursor. /// VERASE = 3, @@ -34,32 +34,32 @@ public enum TerminalModes : byte /// End-of-file character (sends EOF from the terminal). /// VEOF = 5, - + /// /// End-of-line character in addition to carriage return and/or linefeed. /// VEOL = 6, - + /// /// Additional end-of-line character. /// VEOL2 = 7, - + /// /// Continues paused output (normally control-Q). /// VSTART = 8, - + /// /// Pauses output (normally control-S). /// VSTOP = 9, - + /// /// Suspends the current program. /// VSUSP = 10, - + /// /// Another suspend character. /// @@ -76,7 +76,7 @@ public enum TerminalModes : byte VWERASE = 13, /// - /// Enter the next character typed literally, even if it is a special character + /// Enter the next character typed literally, even if it is a special character. /// VLNEXT = 14, diff --git a/src/Renci.SshNet/Compression/Compressor.cs b/src/Renci.SshNet/Compression/Compressor.cs index 5d06c781f..df887aa1c 100644 --- a/src/Renci.SshNet/Compression/Compressor.cs +++ b/src/Renci.SshNet/Compression/Compressor.cs @@ -1,6 +1,7 @@ -锘縰sing Renci.SshNet.Security; +锘縰sing System; using System.IO; -using System; + +using Renci.SshNet.Security; namespace Renci.SshNet.Compression { @@ -11,9 +12,9 @@ public abstract class Compressor : Algorithm, IDisposable { private readonly ZlibStream _compressor; private readonly ZlibStream _decompressor; - private MemoryStream _compressorStream; private MemoryStream _decompressorStream; + private bool _isDisposed; /// /// Gets or sets a value indicating whether compression is active. @@ -73,7 +74,9 @@ public virtual byte[] Compress(byte[] data, int offset, int length) if (!IsActive) { if (offset == 0 && length == data.Length) + { return data; + } var buffer = new byte[length]; Buffer.BlockCopy(data, offset, buffer, 0, length); @@ -113,7 +116,9 @@ public virtual byte[] Decompress(byte[] data, int offset, int length) if (!IsActive) { if (offset == 0 && length == data.Length) + { return data; + } var buffer = new byte[length]; Buffer.BlockCopy(data, offset, buffer, 0, length); @@ -127,16 +132,12 @@ public virtual byte[] Decompress(byte[] data, int offset, int length) return _decompressorStream.ToArray(); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } @@ -147,7 +148,9 @@ public void Dispose() protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -175,9 +178,7 @@ protected virtual void Dispose(bool disposing) /// ~Compressor() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } } diff --git a/src/Renci.SshNet/Connection/ConnectorBase.cs b/src/Renci.SshNet/Connection/ConnectorBase.cs index 6bcd556fd..1725657f5 100644 --- a/src/Renci.SshNet/Connection/ConnectorBase.cs +++ b/src/Renci.SshNet/Connection/ConnectorBase.cs @@ -1,12 +1,13 @@ -锘縰sing Renci.SshNet.Abstractions; -using Renci.SshNet.Common; -using Renci.SshNet.Messages.Transport; -using System; +锘縰sing System; using System.Net; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; +using Renci.SshNet.Abstractions; +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Transport; + namespace Renci.SshNet.Connection { internal abstract class ConnectorBase : IConnector @@ -14,7 +15,9 @@ internal abstract class ConnectorBase : IConnector protected ConnectorBase(ISocketFactory socketFactory) { if (socketFactory == null) - throw new ArgumentNullException("socketFactory"); + { + throw new ArgumentNullException(nameof(socketFactory)); + } SocketFactory = socketFactory; } @@ -95,14 +98,14 @@ protected async Task SocketConnectAsync(string host, int port, Cancellat protected static byte SocketReadByte(Socket socket) { var buffer = new byte[1]; - SocketRead(socket, buffer, 0, 1, Session.InfiniteTimeSpan); + _ = SocketRead(socket, buffer, 0, 1, Session.InfiniteTimeSpan); return buffer[0]; } protected static byte SocketReadByte(Socket socket, TimeSpan readTimeout) { var buffer = new byte[1]; - SocketRead(socket, buffer, 0, 1, readTimeout); + _ = SocketRead(socket, buffer, 0, 1, readTimeout); return buffer[0]; } @@ -145,6 +148,7 @@ protected static int SocketRead(Socket socket, byte[] buffer, int offset, int le throw new SshConnectionException("An established connection was aborted by the server.", DisconnectReason.ConnectionLost); } + return bytesRead; } } diff --git a/src/Renci.SshNet/Connection/DirectConnector.cs b/src/Renci.SshNet/Connection/DirectConnector.cs index 0f428fc31..f0b1d6d62 100644 --- a/src/Renci.SshNet/Connection/DirectConnector.cs +++ b/src/Renci.SshNet/Connection/DirectConnector.cs @@ -5,7 +5,8 @@ namespace Renci.SshNet.Connection { internal sealed class DirectConnector : ConnectorBase { - public DirectConnector(ISocketFactory socketFactory) : base(socketFactory) + public DirectConnector(ISocketFactory socketFactory) + : base(socketFactory) { } diff --git a/src/Renci.SshNet/Connection/HttpConnector.cs b/src/Renci.SshNet/Connection/HttpConnector.cs index 62c4ae279..01fa6fa10 100644 --- a/src/Renci.SshNet/Connection/HttpConnector.cs +++ b/src/Renci.SshNet/Connection/HttpConnector.cs @@ -1,11 +1,12 @@ -锘縰sing Renci.SshNet.Abstractions; -using Renci.SshNet.Common; -using System; +锘縰sing System; using System.Collections.Generic; +using System.Globalization; using System.Net; using System.Net.Sockets; using System.Text.RegularExpressions; -using System.Threading; + +using Renci.SshNet.Abstractions; +using Renci.SshNet.Common; namespace Renci.SshNet.Connection { @@ -30,7 +31,8 @@ namespace Renci.SshNet.Connection /// internal sealed class HttpConnector : ProxyConnector { - public HttpConnector(ISocketFactory socketFactory) : base(socketFactory) + public HttpConnector(ISocketFactory socketFactory) + : base(socketFactory) { } @@ -39,13 +41,17 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke var httpResponseRe = new Regex(@"HTTP/(?\d[.]\d) (?\d{3}) (?.+)$"); var httpHeaderRe = new Regex(@"(?[^\[\]()<>@,;:\""/?={} \t]+):(?.+)?"); - SocketAbstraction.Send(socket, SshData.Ascii.GetBytes(string.Format("CONNECT {0}:{1} HTTP/1.0\r\n", connectionInfo.Host, connectionInfo.Port))); + SocketAbstraction.Send(socket, SshData.Ascii.GetBytes(string.Format(CultureInfo.InvariantCulture, + "CONNECT {0}:{1} HTTP/1.0\r\n", + connectionInfo.Host, + connectionInfo.Port))); - // Sent proxy authorization if specified + // Send proxy authorization if specified if (!string.IsNullOrEmpty(connectionInfo.ProxyUsername)) { - var authorization = string.Format("Proxy-Authorization: Basic {0}\r\n", - Convert.ToBase64String(SshData.Ascii.GetBytes(string.Format("{0}:{1}", connectionInfo.ProxyUsername, connectionInfo.ProxyPassword)))); + var authorization = string.Format(CultureInfo.InvariantCulture, + "Proxy-Authorization: Basic {0}\r\n", + Convert.ToBase64String(SshData.Ascii.GetBytes($"{connectionInfo.ProxyUsername}:{connectionInfo.ProxyPassword}"))); SocketAbstraction.Send(socket, SshData.Ascii.GetBytes(authorization)); } @@ -69,12 +75,10 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke if (statusMatch.Success) { var httpStatusCode = statusMatch.Result("${statusCode}"); - statusCode = (HttpStatusCode)int.Parse(httpStatusCode); + statusCode = (HttpStatusCode) int.Parse(httpStatusCode, CultureInfo.InvariantCulture); if (statusCode != HttpStatusCode.OK) { - throw new ProxyException(string.Format("HTTP: Status code {0}, \"{1}\"", - httpStatusCode, - statusMatch.Result("${reasonPhrase}"))); + throw new ProxyException($"HTTP: Status code {httpStatusCode}, \"{statusMatch.Result("${reasonPhrase}")}\""); } } @@ -88,20 +92,22 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke var fieldName = headerMatch.Result("${fieldName}"); if (fieldName.Equals("Content-Length", StringComparison.OrdinalIgnoreCase)) { - contentLength = int.Parse(headerMatch.Result("${fieldValue}")); + contentLength = int.Parse(headerMatch.Result("${fieldValue}"), CultureInfo.InvariantCulture); } + continue; } // check if we've reached the CRLF which separates request line and headers from the message body if (response.Length == 0) { - // read response body if specified + // read response body if specified if (contentLength > 0) { var contentBody = new byte[contentLength]; - SocketRead(socket, contentBody, 0, contentLength, connectionInfo.Timeout); + _ = SocketRead(socket, contentBody, 0, contentLength, connectionInfo.Timeout); } + break; } } diff --git a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs index 716b8a42c..044f58715 100644 --- a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs +++ b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs @@ -1,7 +1,4 @@ -锘縰sing Renci.SshNet.Abstractions; -using Renci.SshNet.Common; -using Renci.SshNet.Messages.Transport; -using System; +锘縰sing System; using System.Collections.Generic; using System.Globalization; using System.Net.Sockets; @@ -10,13 +7,17 @@ using System.Threading; using System.Threading.Tasks; +using Renci.SshNet.Abstractions; +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Transport; + namespace Renci.SshNet.Connection { /// /// Handles the SSH protocol version exchange. /// /// - /// https://tools.ietf.org/html/rfc4253#section-4.2 + /// https://tools.ietf.org/html/rfc4253#section-4.2. /// internal class ProtocolVersionExchange : IProtocolVersionExchange { @@ -50,20 +51,10 @@ public SshIdentification Start(string clientVersion, Socket socket, TimeSpan tim { if (bytesReceived.Count == 0) { - throw new SshConnectionException(string.Format("The server response does not contain an SSH identification string.{0}" + - "The connection to the remote server was closed before any data was received.{0}{0}" + - "More information on the Protocol Version Exchange is available here:{0}" + - "https://tools.ietf.org/html/rfc4253#section-4.2", - Environment.NewLine), - DisconnectReason.ConnectionLost); + throw CreateConnectionLostException(); } - throw new SshConnectionException(string.Format("The server response does not contain an SSH identification string:{0}{0}{1}{0}{0}" + - "More information on the Protocol Version Exchange is available here:{0}" + - "https://tools.ietf.org/html/rfc4253#section-4.2", - Environment.NewLine, - PacketDump.Create(bytesReceived, 2)), - DisconnectReason.ProtocolError); + throw CreateServerResponseDoesNotContainIdentification(bytesReceived); } var identificationMatch = ServerVersionRe.Match(line); @@ -88,25 +79,15 @@ public async Task StartAsync(string clientVersion, Socket soc // ignore text lines which are sent before if any while (true) { - var line = await SocketReadLineAsync(socket, cancellationToken, bytesReceived).ConfigureAwait(false); + var line = await SocketReadLineAsync(socket, bytesReceived, cancellationToken).ConfigureAwait(false); if (line == null) { if (bytesReceived.Count == 0) { - throw new SshConnectionException(string.Format("The server response does not contain an SSH identification string.{0}" + - "The connection to the remote server was closed before any data was received.{0}{0}" + - "More information on the Protocol Version Exchange is available here:{0}" + - "https://tools.ietf.org/html/rfc4253#section-4.2", - Environment.NewLine), - DisconnectReason.ConnectionLost); + throw CreateConnectionLostException(); } - throw new SshConnectionException(string.Format("The server response does not contain an SSH identification string:{0}{0}{1}{0}{0}" + - "More information on the Protocol Version Exchange is available here:{0}" + - "https://tools.ietf.org/html/rfc4253#section-4.2", - Environment.NewLine, - PacketDump.Create(bytesReceived, 2)), - DisconnectReason.ProtocolError); + throw CreateServerResponseDoesNotContainIdentification(bytesReceived); } var identificationMatch = ServerVersionRe.Match(line); @@ -164,14 +145,7 @@ private static string SocketReadLine(Socket socket, TimeSpan timeout, List // The null character MUST NOT be sent if (byteRead == Null) { - throw new SshConnectionException(string.Format(CultureInfo.InvariantCulture, - "The server response contains a null character at position 0x{0:X8}:{1}{1}{2}{1}{1}" + - "A server must not send a null character before the Protocol Version Exchange is complete.{1}{1}" + - "More information is available here:{1}" + - "https://tools.ietf.org/html/rfc4253#section-4.2", - buffer.Count, - Environment.NewLine, - PacketDump.Create(buffer.ToArray(), 2))); + throw CreateServerResponseContainsNullCharacterException(buffer); } if (byteRead == Session.LineFeed) @@ -181,21 +155,19 @@ private static string SocketReadLine(Socket socket, TimeSpan timeout, List // Return current line without CRLF return Encoding.UTF8.GetString(buffer.ToArray(), startPosition, buffer.Count - (startPosition + 2)); } - else - { - // Even though RFC4253 clearly indicates that the identification string should be terminated - // by a CR LF we also support banners and identification strings that are terminated by a LF - // Return current line without LF - return Encoding.UTF8.GetString(buffer.ToArray(), startPosition, buffer.Count - (startPosition + 1)); - } + // Even though RFC4253 clearly indicates that the identification string should be terminated + // by a CR LF we also support banners and identification strings that are terminated by a LF + + // Return current line without LF + return Encoding.UTF8.GetString(buffer.ToArray(), startPosition, buffer.Count - (startPosition + 1)); } } return null; } - private static async Task SocketReadLineAsync(Socket socket, CancellationToken cancellationToken, List buffer) + private static async Task SocketReadLineAsync(Socket socket, List buffer, CancellationToken cancellationToken) { var data = new byte[1]; @@ -217,14 +189,7 @@ private static async Task SocketReadLineAsync(Socket socket, Cancellatio // The null character MUST NOT be sent if (byteRead == Null) { - throw new SshConnectionException(string.Format(CultureInfo.InvariantCulture, - "The server response contains a null character at position 0x{0:X8}:{1}{1}{2}{1}{1}" + - "A server must not send a null character before the Protocol Version Exchange is complete.{1}{1}" + - "More information is available here:{1}" + - "https://tools.ietf.org/html/rfc4253#section-4.2", - buffer.Count, - Environment.NewLine, - PacketDump.Create(buffer.ToArray(), 2))); + throw CreateServerResponseContainsNullCharacterException(buffer); } if (byteRead == Session.LineFeed) @@ -234,16 +199,58 @@ private static async Task SocketReadLineAsync(Socket socket, Cancellatio // Return current line without CRLF return Encoding.UTF8.GetString(buffer.ToArray(), startPosition, buffer.Count - (startPosition + 2)); } - else - { - // Even though RFC4253 clearly indicates that the identification string should be terminated - // by a CR LF we also support banners and identification strings that are terminated by a LF - // Return current line without LF - return Encoding.UTF8.GetString(buffer.ToArray(), startPosition, buffer.Count - (startPosition + 1)); - } + // Even though RFC4253 clearly indicates that the identification string should be terminated + // by a CR LF we also support banners and identification strings that are terminated by a LF + + // Return current line without LF + return Encoding.UTF8.GetString(buffer.ToArray(), startPosition, buffer.Count - (startPosition + 1)); } } } + + private static SshConnectionException CreateConnectionLostException() + { +#pragma warning disable SA1118 // Parameter should not span multiple lines + var message = string.Format(CultureInfo.InvariantCulture, + "The server response does not contain an SSH identification string.{0}" + + "The connection to the remote server was closed before any data was received.{0}{0}" + + "More information on the Protocol Version Exchange is available here:{0}" + + "https://tools.ietf.org/html/rfc4253#section-4.2", + Environment.NewLine); +#pragma warning restore SA1118 // Parameter should not span multiple lines + + return new SshConnectionException(message, DisconnectReason.ConnectionLost); + } + + private static SshConnectionException CreateServerResponseContainsNullCharacterException(List buffer) + { +#pragma warning disable SA1118 // Parameter should not span multiple lines + var message = string.Format(CultureInfo.InvariantCulture, + "The server response contains a null character at position 0x{0:X8}:{1}{1}{2}{1}{1}" + + "A server must not send a null character before the Protocol Version Exchange is complete.{1}{1}" + + "More information is available here:{1}" + + "https://tools.ietf.org/html/rfc4253#section-4.2", + buffer.Count, + Environment.NewLine, + PacketDump.Create(buffer.ToArray(), 2)); +#pragma warning restore SA1118 // Parameter should not span multiple lines + + throw new SshConnectionException(message); + } + + private static SshConnectionException CreateServerResponseDoesNotContainIdentification(List bytesReceived) + { +#pragma warning disable SA1118 // Parameter should not span multiple lines + var message = string.Format(CultureInfo.InvariantCulture, + "The server response does not contain an SSH identification string:{0}{0}{1}{0}{0}" + + "More information on the Protocol Version Exchange is available here:{0}" + + "https://tools.ietf.org/html/rfc4253#section-4.2", + Environment.NewLine, + PacketDump.Create(bytesReceived, 2)); +#pragma warning restore SA1118 // Parameter should not span multiple lines + + throw new SshConnectionException(message, DisconnectReason.ProtocolError); + } } } diff --git a/src/Renci.SshNet/Connection/ProxyConnector.cs b/src/Renci.SshNet/Connection/ProxyConnector.cs index 164ae4835..9bbf8b0f2 100644 --- a/src/Renci.SshNet/Connection/ProxyConnector.cs +++ b/src/Renci.SshNet/Connection/ProxyConnector.cs @@ -3,13 +3,12 @@ using System.Threading; using System.Threading.Tasks; - namespace Renci.SshNet.Connection { internal abstract class ProxyConnector : ConnectorBase { - public ProxyConnector(ISocketFactory socketFactory) : - base(socketFactory) + public ProxyConnector(ISocketFactory socketFactory) + : base(socketFactory) { } @@ -20,10 +19,11 @@ protected virtual Task HandleProxyConnectAsync(IConnectionInfo connectionInfo, S { cancellationToken.ThrowIfCancellationRequested(); - using (cancellationToken.Register(o => ((Socket)o).Dispose(), socket, false)) + using (cancellationToken.Register(o => ((Socket)o).Dispose(), socket, useSynchronizationContext: false)) { HandleProxyConnect(connectionInfo, socket); } + return Task.CompletedTask; } diff --git a/src/Renci.SshNet/Connection/Socks4Connector.cs b/src/Renci.SshNet/Connection/Socks4Connector.cs index d507872c6..046d0549b 100644 --- a/src/Renci.SshNet/Connection/Socks4Connector.cs +++ b/src/Renci.SshNet/Connection/Socks4Connector.cs @@ -1,20 +1,22 @@ -锘縰sing Renci.SshNet.Abstractions; -using Renci.SshNet.Common; -using System; +锘縰sing System; using System.Net.Sockets; using System.Text; +using Renci.SshNet.Abstractions; +using Renci.SshNet.Common; + namespace Renci.SshNet.Connection { /// /// Establishes a tunnel via a SOCKS4 proxy server. /// /// - /// https://www.openssh.com/txt/socks4.protocol + /// https://www.openssh.com/txt/socks4.protocol. /// internal sealed class Socks4Connector : ProxyConnector { - public Socks4Connector(ISocketFactory socketFactory) : base(socketFactory) + public Socks4Connector(ISocketFactory socketFactory) + : base(socketFactory) { } @@ -28,13 +30,13 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke var connectionRequest = CreateSocks4ConnectionRequest(connectionInfo.Host, (ushort)connectionInfo.Port, connectionInfo.ProxyUsername); SocketAbstraction.Send(socket, connectionRequest); - // Read reply version + // Read reply version if (SocketReadByte(socket, connectionInfo.Timeout) != 0x00) { throw new ProxyException("SOCKS4: Null is expected."); } - // Read response code + // Read response code var code = SocketReadByte(socket, connectionInfo.Timeout); switch (code) @@ -52,7 +54,7 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke } var destBuffer = new byte[6]; // destination port and IP address should be ignored - SocketRead(socket, destBuffer, 0, destBuffer.Length, connectionInfo.Timeout); + _ = SocketRead(socket, destBuffer, 0, destBuffer.Length, connectionInfo.Timeout); } private static byte[] CreateSocks4ConnectionRequest(string hostname, ushort port, string username) diff --git a/src/Renci.SshNet/Connection/Socks5Connector.cs b/src/Renci.SshNet/Connection/Socks5Connector.cs index e1b6859dc..9cfc4758f 100644 --- a/src/Renci.SshNet/Connection/Socks5Connector.cs +++ b/src/Renci.SshNet/Connection/Socks5Connector.cs @@ -1,19 +1,21 @@ -锘縰sing Renci.SshNet.Abstractions; -using Renci.SshNet.Common; -using System; +锘縰sing System; using System.Net.Sockets; +using Renci.SshNet.Abstractions; +using Renci.SshNet.Common; + namespace Renci.SshNet.Connection { /// /// Establishes a tunnel via a SOCKS5 proxy server. /// /// - /// https://en.wikipedia.org/wiki/SOCKS#SOCKS5 + /// https://en.wikipedia.org/wiki/SOCKS#SOCKS5. /// internal sealed class Socks5Connector : ProxyConnector { - public Socks5Connector(ISocketFactory socketFactory) : base(socketFactory) + public Socks5Connector(ISocketFactory socketFactory) + : base(socketFactory) { } @@ -51,15 +53,23 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke case 0x02: // Create username/password authentication request var authenticationRequest = CreateSocks5UserNameAndPasswordAuthenticationRequest(connectionInfo.ProxyUsername, connectionInfo.ProxyPassword); + // Send authentication request SocketAbstraction.Send(socket, authenticationRequest); + // Read authentication result var authenticationResult = SocketAbstraction.Read(socket, 2, connectionInfo.Timeout); if (authenticationResult[0] != 0x01) + { throw new ProxyException("SOCKS5: Server authentication version is not valid."); + } + if (authenticationResult[1] != 0x00) + { throw new ProxyException("SOCKS5: Username/Password authentication failed."); + } + break; case 0xFF: throw new ProxyException("SOCKS5: No acceptable authentication methods were offered."); @@ -68,13 +78,13 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke var connectionRequest = CreateSocks5ConnectionRequest(connectionInfo.Host, (ushort) connectionInfo.Port); SocketAbstraction.Send(socket, connectionRequest); - // Read Server SOCKS5 version + // Read Server SOCKS5 version if (SocketReadByte(socket) != 5) { throw new ProxyException("SOCKS5: Version 5 is expected."); } - // Read response code + // Read response code var status = SocketReadByte(socket); switch (status) @@ -101,7 +111,7 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke throw new ProxyException("SOCKS5: Not valid response."); } - // Read reserved byte + // Read reserved byte if (SocketReadByte(socket) != 0) { throw new ProxyException("SOCKS5: 0 byte is expected."); @@ -112,11 +122,11 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke { case 0x01: var ipv4 = new byte[4]; - SocketRead(socket, ipv4, 0, 4); + _ = SocketRead(socket, ipv4, 0, 4); break; case 0x04: var ipv6 = new byte[16]; - SocketRead(socket, ipv6, 0, 16); + _ =SocketRead(socket, ipv6, 0, 16); break; default: throw new ProxyException(string.Format("Address type '{0}' is not supported.", addressType)); @@ -124,19 +134,24 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke var port = new byte[2]; - // Read 2 bytes to be ignored - SocketRead(socket, port, 0, 2); + // Read 2 bytes to be ignored + _ = SocketRead(socket, port, 0, 2); } /// - /// https://tools.ietf.org/html/rfc1929 + /// https://tools.ietf.org/html/rfc1929. /// private static byte[] CreateSocks5UserNameAndPasswordAuthenticationRequest(string username, string password) { if (username.Length > byte.MaxValue) + { throw new ProxyException("Proxy username is too long."); + } + if (password.Length > byte.MaxValue) + { throw new ProxyException("Proxy password is too long."); + } var authenticationRequest = new byte [ @@ -161,22 +176,21 @@ private static byte[] CreateSocks5UserNameAndPasswordAuthenticationRequest(strin authenticationRequest[index++] = (byte) username.Length; // Username - SshData.Ascii.GetBytes(username, 0, username.Length, authenticationRequest, index); + _ = SshData.Ascii.GetBytes(username, 0, username.Length, authenticationRequest, index); index += username.Length; // Length of the password authenticationRequest[index++] = (byte) password.Length; // Password - SshData.Ascii.GetBytes(password, 0, password.Length, authenticationRequest, index); + _ =SshData.Ascii.GetBytes(password, 0, password.Length, authenticationRequest, index); return authenticationRequest; } private static byte[] CreateSocks5ConnectionRequest(string hostname, ushort port) { - byte addressType; - var addressBytes = GetSocks5DestinationAddress(hostname, out addressType); + var addressBytes = GetSocks5DestinationAddress(hostname, out var addressType); var connectionRequest = new byte [ diff --git a/src/Renci.SshNet/Connection/SshIdentification.cs b/src/Renci.SshNet/Connection/SshIdentification.cs index 90c00fe9f..9484ea0c8 100644 --- a/src/Renci.SshNet/Connection/SshIdentification.cs +++ b/src/Renci.SshNet/Connection/SshIdentification.cs @@ -8,33 +8,38 @@ namespace Renci.SshNet.Connection internal class SshIdentification { /// - /// Initializes a new instance with the specified protocol version + /// Initializes a new instance of the class with the specified protocol version /// and software version. /// /// The SSH protocol version. - /// The software version of the implementation + /// The software version of the implementation. /// is . /// is . public SshIdentification(string protocolVersion, string softwareVersion) - : this(protocolVersion, softwareVersion, null) + : this(protocolVersion, softwareVersion, comments: null) { } /// - /// Initializes a new instance with the specified protocol version, + /// Initializes a new instance of the class with the specified protocol version, /// software version and comments. /// /// The SSH protocol version. - /// The software version of the implementation + /// The software version of the implementation. /// The comments. /// is . /// is . public SshIdentification(string protocolVersion, string softwareVersion, string comments) { if (protocolVersion == null) - throw new ArgumentNullException("protocolVersion"); + { + throw new ArgumentNullException(nameof(protocolVersion)); + } + if (softwareVersion == null) - throw new ArgumentNullException("softwareVersion"); + { + throw new ArgumentNullException(nameof(softwareVersion)); + } ProtocolVersion = protocolVersion; SoftwareVersion = softwareVersion; @@ -42,7 +47,7 @@ public SshIdentification(string protocolVersion, string softwareVersion, string } /// - /// Gets or sets the software version of the implementation. + /// Gets the software version of the implementation. /// /// /// The software version of the implementation. @@ -51,18 +56,18 @@ public SshIdentification(string protocolVersion, string softwareVersion, string /// This is primarily used to trigger compatibility extensions and to indicate /// the capabilities of an implementation. /// - public string SoftwareVersion { get; private set; } + public string SoftwareVersion { get; } /// - /// Gets or sets the SSH protocol version. + /// Gets the SSH protocol version. /// /// /// The SSH protocol version. /// - public string ProtocolVersion { get; private set; } + public string ProtocolVersion { get; } /// - /// Gets or sets the comments. + /// Gets the comments. /// /// /// The comments, or if there are no comments. @@ -71,7 +76,7 @@ public SshIdentification(string protocolVersion, string softwareVersion, string /// should contain additional information that might be useful /// in solving user problems. /// - public string Comments { get; private set; } + public string Comments { get; } /// /// Returns the SSH identification string. @@ -82,10 +87,12 @@ public SshIdentification(string protocolVersion, string softwareVersion, string public override string ToString() { var identificationString = "SSH-" + ProtocolVersion + "-" + SoftwareVersion; + if (Comments != null) { identificationString += " " + Comments; } + return identificationString; } } diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index f0f8b57c7..b36b4eb15 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -1,14 +1,16 @@ 锘縰sing System; using System.Collections.Generic; using System.Linq; +using System.Net; using System.Text; + using Renci.SshNet.Abstractions; -using Renci.SshNet.Security; -using Renci.SshNet.Messages.Connection; using Renci.SshNet.Common; using Renci.SshNet.Messages.Authentication; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; +using Renci.SshNet.Messages.Connection; +using Renci.SshNet.Security; using Renci.SshNet.Security.Cryptography.Ciphers; +using Renci.SshNet.Security.Cryptography.Ciphers.Modes; namespace Renci.SshNet { @@ -161,7 +163,7 @@ public class ConnectionInfo : IConnectionInfoInternal /// Gets or sets the character encoding. /// /// - /// The character encoding. The default is . + /// The character encoding. The default is . /// public Encoding Encoding { get; set; } @@ -232,7 +234,7 @@ public class ConnectionInfo : IConnectionInfoInternal public string ServerVersion { get; internal set; } /// - /// Get the client version. + /// Gets the client version. /// public string ClientVersion { get; internal set; } @@ -253,7 +255,7 @@ public class ConnectionInfo : IConnectionInfoInternal /// is null. /// No specified. public ConnectionInfo(string host, string username, params AuthenticationMethod[] authenticationMethods) - : this(host, DefaultPort, username, ProxyTypes.None, null, 0, null, null, authenticationMethods) + : this(host, DefaultPort, username, ProxyTypes.None, proxyHost: null, 0, proxyUsername: null, proxyPassword: null, authenticationMethods) { } @@ -266,11 +268,11 @@ public ConnectionInfo(string host, string username, params AuthenticationMethod[ /// The authentication methods. /// is null. /// is null, a zero-length string or contains only whitespace characters. - /// is not within and . + /// is not within and . /// is null. /// No specified. public ConnectionInfo(string host, int port, string username, params AuthenticationMethod[] authenticationMethods) - : this(host, port, username, ProxyTypes.None, null, 0, null, null, authenticationMethods) + : this(host, port, username, ProxyTypes.None, proxyHost: null, 0, proxyUsername: null, proxyPassword: null, authenticationMethods) { } @@ -288,35 +290,51 @@ public ConnectionInfo(string host, int port, string username, params Authenticat /// The authentication methods. /// is null. /// is null, a zero-length string or contains only whitespace characters. - /// is not within and . + /// is not within and . /// is not and is null. - /// is not and is not within and . + /// is not and is not within and . /// is null. /// No specified. public ConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params AuthenticationMethod[] authenticationMethods) { if (host == null) - throw new ArgumentNullException("host"); + { + throw new ArgumentNullException(nameof(host)); + } + port.ValidatePort("port"); if (username == null) - throw new ArgumentNullException("username"); + { + throw new ArgumentNullException(nameof(username)); + } + if (username.All(char.IsWhiteSpace)) - throw new ArgumentException("Cannot be empty or contain only whitespace.", "username"); + { + throw new ArgumentException("Cannot be empty or contain only whitespace.", nameof(username)); + } if (proxyType != ProxyTypes.None) { if (proxyHost == null) - throw new ArgumentNullException("proxyHost"); + { + throw new ArgumentNullException(nameof(proxyHost)); + } + proxyPort.ValidatePort("proxyPort"); } if (authenticationMethods == null) - throw new ArgumentNullException("authenticationMethods"); + { + throw new ArgumentNullException(nameof(authenticationMethods)); + } + if (authenticationMethods.Length == 0) - throw new ArgumentException("At least one authentication method should be specified.", "authenticationMethods"); + { + throw new ArgumentException("At least one authentication method should be specified.", nameof(authenticationMethods)); + } - // Set default connection values + // Set default connection values Timeout = DefaultTimeout; ChannelCloseTimeout = DefaultChannelCloseTimeout; RetryAttempts = 10; @@ -325,98 +343,83 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy KeyExchangeAlgorithms = new Dictionary { - {"curve25519-sha256", typeof(KeyExchangeECCurve25519)}, - {"curve25519-sha256@libssh.org", typeof(KeyExchangeECCurve25519)}, - {"ecdh-sha2-nistp256", typeof(KeyExchangeECDH256)}, - {"ecdh-sha2-nistp384", typeof(KeyExchangeECDH384)}, - {"ecdh-sha2-nistp521", typeof(KeyExchangeECDH521)}, - {"diffie-hellman-group-exchange-sha256", typeof (KeyExchangeDiffieHellmanGroupExchangeSha256)}, - {"diffie-hellman-group-exchange-sha1", typeof (KeyExchangeDiffieHellmanGroupExchangeSha1)}, - {"diffie-hellman-group16-sha512", typeof(KeyExchangeDiffieHellmanGroup16Sha512)}, - {"diffie-hellman-group14-sha256", typeof (KeyExchangeDiffieHellmanGroup14Sha256)}, - {"diffie-hellman-group14-sha1", typeof (KeyExchangeDiffieHellmanGroup14Sha1)}, - {"diffie-hellman-group1-sha1", typeof (KeyExchangeDiffieHellmanGroup1Sha1)}, + { "curve25519-sha256", typeof(KeyExchangeECCurve25519) }, + { "curve25519-sha256@libssh.org", typeof(KeyExchangeECCurve25519) }, + { "ecdh-sha2-nistp256", typeof(KeyExchangeECDH256) }, + { "ecdh-sha2-nistp384", typeof(KeyExchangeECDH384) }, + { "ecdh-sha2-nistp521", typeof(KeyExchangeECDH521) }, + { "diffie-hellman-group-exchange-sha256", typeof(KeyExchangeDiffieHellmanGroupExchangeSha256) }, + { "diffie-hellman-group-exchange-sha1", typeof(KeyExchangeDiffieHellmanGroupExchangeSha1) }, + { "diffie-hellman-group16-sha512", typeof(KeyExchangeDiffieHellmanGroup16Sha512) }, + { "diffie-hellman-group14-sha256", typeof(KeyExchangeDiffieHellmanGroup14Sha256) }, + { "diffie-hellman-group14-sha1", typeof(KeyExchangeDiffieHellmanGroup14Sha1) }, + { "diffie-hellman-group1-sha1", typeof(KeyExchangeDiffieHellmanGroup1Sha1) }, }; Encryptions = new Dictionary { - {"aes256-ctr", new CipherInfo(256, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), null))}, - {"3des-cbc", new CipherInfo(192, (key, iv) => new TripleDesCipher(key, new CbcCipherMode(iv), null))}, - {"aes128-cbc", new CipherInfo(128, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), null))}, - {"aes192-cbc", new CipherInfo(192, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), null))}, - {"aes256-cbc", new CipherInfo(256, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), null))}, - {"blowfish-cbc", new CipherInfo(128, (key, iv) => new BlowfishCipher(key, new CbcCipherMode(iv), null))}, - {"twofish-cbc", new CipherInfo(256, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), null))}, - {"twofish192-cbc", new CipherInfo(192, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), null))}, - {"twofish128-cbc", new CipherInfo(128, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), null))}, - {"twofish256-cbc", new CipherInfo(256, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), null))}, - ////{"serpent256-cbc", typeof(CipherSerpent256CBC)}, - ////{"serpent192-cbc", typeof(...)}, - ////{"serpent128-cbc", typeof(...)}, - {"arcfour", new CipherInfo(128, (key, iv) => new Arc4Cipher(key, false))}, - {"arcfour128", new CipherInfo(128, (key, iv) => new Arc4Cipher(key, true))}, - {"arcfour256", new CipherInfo(256, (key, iv) => new Arc4Cipher(key, true))}, - ////{"idea-cbc", typeof(...)}, - {"cast128-cbc", new CipherInfo(128, (key, iv) => new CastCipher(key, new CbcCipherMode(iv), null))}, - ////{"rijndael-cbc@lysator.liu.se", typeof(...)}, - {"aes128-ctr", new CipherInfo(128, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), null))}, - {"aes192-ctr", new CipherInfo(192, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), null))}, + { "aes256-ctr", new CipherInfo(256, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), padding: null)) }, + { "3des-cbc", new CipherInfo(192, (key, iv) => new TripleDesCipher(key, new CbcCipherMode(iv), padding: null)) }, + { "aes128-cbc", new CipherInfo(128, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), padding: null)) }, + { "aes192-cbc", new CipherInfo(192, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), padding: null)) }, + { "aes256-cbc", new CipherInfo(256, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), padding: null)) }, + { "blowfish-cbc", new CipherInfo(128, (key, iv) => new BlowfishCipher(key, new CbcCipherMode(iv), padding: null)) }, + { "twofish-cbc", new CipherInfo(256, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), padding: null)) }, + { "twofish192-cbc", new CipherInfo(192, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), padding: null)) }, + { "twofish128-cbc", new CipherInfo(128, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), padding: null)) }, + { "twofish256-cbc", new CipherInfo(256, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), padding: null)) }, + { "arcfour", new CipherInfo(128, (key, iv) => new Arc4Cipher(key, dischargeFirstBytes: false)) }, + { "arcfour128", new CipherInfo(128, (key, iv) => new Arc4Cipher(key, dischargeFirstBytes: true)) }, + { "arcfour256", new CipherInfo(256, (key, iv) => new Arc4Cipher(key, dischargeFirstBytes: true)) }, + { "cast128-cbc", new CipherInfo(128, (key, iv) => new CastCipher(key, new CbcCipherMode(iv), padding: null)) }, + { "aes128-ctr", new CipherInfo(128, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), padding: null)) }, + { "aes192-ctr", new CipherInfo(192, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), padding: null)) }, }; HmacAlgorithms = new Dictionary { - {"hmac-md5", new HashInfo(16*8, CryptoAbstraction.CreateHMACMD5)}, - {"hmac-md5-96", new HashInfo(16*8, key => CryptoAbstraction.CreateHMACMD5(key, 96))}, - {"hmac-sha1", new HashInfo(20*8, CryptoAbstraction.CreateHMACSHA1)}, - {"hmac-sha1-96", new HashInfo(20*8, key => CryptoAbstraction.CreateHMACSHA1(key, 96))}, - {"hmac-sha2-256", new HashInfo(32*8, CryptoAbstraction.CreateHMACSHA256)}, - {"hmac-sha2-256-96", new HashInfo(32*8, key => CryptoAbstraction.CreateHMACSHA256(key, 96))}, - {"hmac-sha2-512", new HashInfo(64 * 8, CryptoAbstraction.CreateHMACSHA512)}, - {"hmac-sha2-512-96", new HashInfo(64 * 8, key => CryptoAbstraction.CreateHMACSHA512(key, 96))}, - //{"umac-64@openssh.com", typeof(HMacSha1)}, - {"hmac-ripemd160", new HashInfo(160, CryptoAbstraction.CreateHMACRIPEMD160)}, - {"hmac-ripemd160@openssh.com", new HashInfo(160, CryptoAbstraction.CreateHMACRIPEMD160)}, - //{"none", typeof(...)}, + { "hmac-md5", new HashInfo(16*8, CryptoAbstraction.CreateHMACMD5) }, + { "hmac-md5-96", new HashInfo(16*8, key => CryptoAbstraction.CreateHMACMD5(key, 96)) }, + { "hmac-sha1", new HashInfo(20*8, CryptoAbstraction.CreateHMACSHA1) }, + { "hmac-sha1-96", new HashInfo(20*8, key => CryptoAbstraction.CreateHMACSHA1(key, 96)) }, + { "hmac-sha2-256", new HashInfo(32*8, CryptoAbstraction.CreateHMACSHA256) }, + { "hmac-sha2-256-96", new HashInfo(32*8, key => CryptoAbstraction.CreateHMACSHA256(key, 96)) }, + { "hmac-sha2-512", new HashInfo(64 * 8, CryptoAbstraction.CreateHMACSHA512) }, + { "hmac-sha2-512-96", new HashInfo(64 * 8, key => CryptoAbstraction.CreateHMACSHA512(key, 96)) }, + { "hmac-ripemd160", new HashInfo(160, CryptoAbstraction.CreateHMACRIPEMD160) }, + { "hmac-ripemd160@openssh.com", new HashInfo(160, CryptoAbstraction.CreateHMACRIPEMD160) }, }; HostKeyAlgorithms = new Dictionary> { - {"ssh-ed25519", data => new KeyHostAlgorithm("ssh-ed25519", new ED25519Key(), data)}, - {"ecdsa-sha2-nistp256", data => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(), data)}, - {"ecdsa-sha2-nistp384", data => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(), data)}, - {"ecdsa-sha2-nistp521", data => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(), data)}, - {"ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data)}, - {"ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(), data)}, - //{"x509v3-sign-rsa", () => { ... }, - //{"x509v3-sign-dss", () => { ... }, - //{"spki-sign-rsa", () => { ... }, - //{"spki-sign-dss", () => { ... }, - //{"pgp-sign-rsa", () => { ... }, - //{"pgp-sign-dss", () => { ... }, + { "ssh-ed25519", data => new KeyHostAlgorithm("ssh-ed25519", new ED25519Key(), data) }, + { "ecdsa-sha2-nistp256", data => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(), data) }, + { "ecdsa-sha2-nistp384", data => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(), data) }, + { "ecdsa-sha2-nistp521", data => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(), data) }, + { "ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data) }, + { "ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(), data) }, }; CompressionAlgorithms = new Dictionary { - //{"zlib@openssh.com", typeof(ZlibOpenSsh)}, - //{"zlib", typeof(Zlib)}, - {"none", null}, + { "none", null }, }; ChannelRequests = new Dictionary { - {EnvironmentVariableRequestInfo.Name, new EnvironmentVariableRequestInfo()}, - {ExecRequestInfo.Name, new ExecRequestInfo()}, - {ExitSignalRequestInfo.Name, new ExitSignalRequestInfo()}, - {ExitStatusRequestInfo.Name, new ExitStatusRequestInfo()}, - {PseudoTerminalRequestInfo.Name, new PseudoTerminalRequestInfo()}, - {ShellRequestInfo.Name, new ShellRequestInfo()}, - {SignalRequestInfo.Name, new SignalRequestInfo()}, - {SubsystemRequestInfo.Name, new SubsystemRequestInfo()}, - {WindowChangeRequestInfo.Name, new WindowChangeRequestInfo()}, - {X11ForwardingRequestInfo.Name, new X11ForwardingRequestInfo()}, - {XonXoffRequestInfo.Name, new XonXoffRequestInfo()}, - {EndOfWriteRequestInfo.Name, new EndOfWriteRequestInfo()}, - {KeepAliveRequestInfo.Name, new KeepAliveRequestInfo()}, + { EnvironmentVariableRequestInfo.Name, new EnvironmentVariableRequestInfo() }, + { ExecRequestInfo.Name, new ExecRequestInfo() }, + { ExitSignalRequestInfo.Name, new ExitSignalRequestInfo() }, + { ExitStatusRequestInfo.Name, new ExitStatusRequestInfo() }, + { PseudoTerminalRequestInfo.Name, new PseudoTerminalRequestInfo() }, + { ShellRequestInfo.Name, new ShellRequestInfo() }, + { SignalRequestInfo.Name, new SignalRequestInfo() }, + { SubsystemRequestInfo.Name, new SubsystemRequestInfo() }, + { WindowChangeRequestInfo.Name, new WindowChangeRequestInfo() }, + { X11ForwardingRequestInfo.Name, new X11ForwardingRequestInfo() }, + { XonXoffRequestInfo.Name, new XonXoffRequestInfo() }, + { EndOfWriteRequestInfo.Name, new EndOfWriteRequestInfo() }, + { KeepAliveRequestInfo.Name, new KeepAliveRequestInfo() }, }; Host = host; @@ -443,7 +446,9 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy internal void Authenticate(ISession session, IServiceFactory serviceFactory) { if (serviceFactory == null) - throw new ArgumentNullException("serviceFactory"); + { + throw new ArgumentNullException(nameof(serviceFactory)); + } IsAuthenticated = false; var clientAuthentication = serviceFactory.CreateClientAuthentication(); @@ -455,15 +460,10 @@ internal void Authenticate(ISession session, IServiceFactory serviceFactory) /// Signals that an authentication banner message was received from the server. /// /// The session in which the banner message was received. - /// The banner message.{ + /// The banner message. void IConnectionInfoInternal.UserAuthenticationBannerReceived(object sender, MessageEventArgs e) { - var authenticationBanner = AuthenticationBanner; - if (authenticationBanner != null) - { - authenticationBanner(this, - new AuthenticationBannerEventArgs(Username, e.Message.Message, e.Message.Language)); - } + AuthenticationBanner?.Invoke(this, new AuthenticationBannerEventArgs(Username, e.Message.Message, e.Message.Language)); } IAuthenticationMethod IConnectionInfoInternal.CreateNoneAuthenticationMethod() diff --git a/src/Renci.SshNet/ExpectAction.cs b/src/Renci.SshNet/ExpectAction.cs index c2ff3a6a1..4a52c889d 100644 --- a/src/Renci.SshNet/ExpectAction.cs +++ b/src/Renci.SshNet/ExpectAction.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet { /// - /// Specifies behavior for expected expression + /// Specifies behavior for expected expression. /// public class ExpectAction { @@ -27,10 +27,14 @@ public class ExpectAction public ExpectAction(Regex expect, Action action) { if (expect == null) - throw new ArgumentNullException("expect"); + { + throw new ArgumentNullException(nameof(expect)); + } if (action == null) - throw new ArgumentNullException("action"); + { + throw new ArgumentNullException(nameof(action)); + } Expect = expect; Action = action; @@ -45,10 +49,14 @@ public ExpectAction(Regex expect, Action action) public ExpectAction(string expect, Action action) { if (expect == null) - throw new ArgumentNullException("expect"); + { + throw new ArgumentNullException(nameof(expect)); + } if (action == null) - throw new ArgumentNullException("action"); + { + throw new ArgumentNullException(nameof(action)); + } Expect = new Regex(Regex.Escape(expect)); Action = action; diff --git a/src/Renci.SshNet/ExpectAsyncResult.cs b/src/Renci.SshNet/ExpectAsyncResult.cs index 0f911c0b8..f83d32f75 100644 --- a/src/Renci.SshNet/ExpectAsyncResult.cs +++ b/src/Renci.SshNet/ExpectAsyncResult.cs @@ -1,10 +1,11 @@ -锘縰sing Renci.SshNet.Common; -using System; +锘縰sing System; + +using Renci.SshNet.Common; namespace Renci.SshNet { /// - /// Provides additional information for asynchronous command execution + /// Provides additional information for asynchronous command execution. /// public class ExpectAsyncResult : AsyncResult { @@ -13,7 +14,7 @@ public class ExpectAsyncResult : AsyncResult /// /// The async callback. /// The state. - internal ExpectAsyncResult(AsyncCallback asyncCallback, Object state) + internal ExpectAsyncResult(AsyncCallback asyncCallback, object state) : base(asyncCallback, state) { } diff --git a/src/Renci.SshNet/ForwardedPort.cs b/src/Renci.SshNet/ForwardedPort.cs index 26baaa1db..deca52423 100644 --- a/src/Renci.SshNet/ForwardedPort.cs +++ b/src/Renci.SshNet/ForwardedPort.cs @@ -56,11 +56,19 @@ public virtual void Start() CheckDisposed(); if (IsStarted) + { throw new InvalidOperationException("Forwarded port is already started."); + } + if (Session == null) + { throw new InvalidOperationException("Forwarded port is not added to a client."); + } + if (!Session.IsConnected) + { throw new SshConnectionException("Client not connected."); + } Session.ErrorOccured += Session_ErrorOccured; StartPort(); @@ -127,11 +135,7 @@ protected virtual void Dispose(bool disposing) /// The exception. protected void RaiseExceptionEvent(Exception exception) { - var handlers = Exception; - if (handlers != null) - { - handlers(this, new ExceptionEventArgs(exception)); - } + Exception?.Invoke(this, new ExceptionEventArgs(exception)); } /// @@ -141,11 +145,7 @@ protected void RaiseExceptionEvent(Exception exception) /// Request originator port. protected void RaiseRequestReceived(string host, uint port) { - var handlers = RequestReceived; - if (handlers != null) - { - handlers(this, new PortForwardEventArgs(host, port)); - } + RequestReceived?.Invoke(this, new PortForwardEventArgs(host, port)); } /// @@ -153,11 +153,7 @@ protected void RaiseRequestReceived(string host, uint port) /// private void RaiseClosing() { - var handlers = Closing; - if (handlers != null) - { - handlers(this, EventArgs.Empty); - } + Closing?.Invoke(this, EventArgs.Empty); } /// diff --git a/src/Renci.SshNet/ForwardedPortDynamic.NET.cs b/src/Renci.SshNet/ForwardedPortDynamic.NET.cs index 31b3a0ab9..957483f71 100644 --- a/src/Renci.SshNet/ForwardedPortDynamic.NET.cs +++ b/src/Renci.SshNet/ForwardedPortDynamic.NET.cs @@ -1,9 +1,10 @@ 锘縰sing System; using System.Linq; -using System.Text; using System.Net; using System.Net.Sockets; +using System.Text; using System.Threading; + using Renci.SshNet.Abstractions; using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -78,7 +79,7 @@ private void StartAccept(SocketAsyncEventArgs e) private void AcceptCompleted(object sender, SocketAsyncEventArgs e) { - if (e.SocketError == SocketError.OperationAborted || e.SocketError == SocketError.NotSocket) + if (e.SocketError is SocketError.OperationAborted or SocketError.NotSocket) { // server was stopped return; @@ -91,6 +92,7 @@ private void AcceptCompleted(object sender, SocketAsyncEventArgs e) { // accept new connection StartAccept(e); + // dispose broken client socket CloseClientSocket(clientSocket); return; @@ -98,6 +100,7 @@ private void AcceptCompleted(object sender, SocketAsyncEventArgs e) // accept new connection StartAccept(e); + // process connection ProcessAccept(clientSocket); } @@ -146,7 +149,7 @@ private void ProcessAccept(Socket clientSocket) // the CountdownEvent will be disposed try { - pendingChannelCountdown.Signal(); + _ = pendingChannelCountdown.Signal(); } catch (ObjectDisposedException) { @@ -170,10 +173,7 @@ private void ProcessAccept(Socket clientSocket) private void InitializePendingChannelCountdown() { var original = Interlocked.Exchange(ref _pendingChannelCountdown, new CountdownEvent(1)); - if (original != null) - { - original.Dispose(); - } + original?.Dispose(); } private bool HandleSocks(IChannelDirectTcpip channel, Socket clientSocket, TimeSpan timeout) @@ -251,11 +251,7 @@ private static void CloseClientSocket(Socket clientSocket) partial void StopListener() { // close listener socket - var listener = _listener; - if (listener != null) - { - listener.Dispose(); - } + _listener?.Dispose(); // unsubscribe from session events var session = Session; @@ -272,7 +268,8 @@ partial void StopListener() /// The maximum time to wait for the pending channels to close. partial void InternalStop(TimeSpan timeout) { - _pendingChannelCountdown.Signal(); + _ = _pendingChannelCountdown.Signal(); + if (!_pendingChannelCountdown.Wait(timeout)) { // TODO: log as warning @@ -401,12 +398,12 @@ private bool HandleSocks5(Socket socket, IChannelDirectTcpip channel, TimeSpan t { // no user authentication is one of the authentication methods supported // by the SOCKS client - SocketAbstraction.Send(socket, new byte[] {0x05, 0x00}, 0, 2); + SocketAbstraction.Send(socket, new byte[] { 0x05, 0x00 }, 0, 2); } else { // the SOCKS client requires authentication, which we currently do not support - SocketAbstraction.Send(socket, new byte[] {0x05, 0xFF}, 0, 2); + SocketAbstraction.Send(socket, new byte[] { 0x05, 0xFF }, 0, 2); // we continue business as usual but expect the client to close the connection // so one of the subsequent reads should return -1 signaling that the client @@ -592,11 +589,10 @@ private static string ReadString(Socket socket, TimeSpan timeout) break; } - var c = (char) byteRead; - text.Append(c); + _ = text.Append((char) byteRead); } + return text.ToString(); } } } - diff --git a/src/Renci.SshNet/ForwardedPortDynamic.cs b/src/Renci.SshNet/ForwardedPortDynamic.cs index dbe9794db..1331557a8 100644 --- a/src/Renci.SshNet/ForwardedPortDynamic.cs +++ b/src/Renci.SshNet/ForwardedPortDynamic.cs @@ -10,15 +10,23 @@ public partial class ForwardedPortDynamic : ForwardedPort { private ForwardedPortStatus _status; + /// + /// Holds a value indicating whether the current instance is disposed. + /// + /// + /// true if the current instance is disposed; otherwise, false. + /// + private bool _isDisposed; + /// /// Gets the bound host. /// - public string BoundHost { get; private set; } + public string BoundHost { get; } /// /// Gets the bound port. /// - public uint BoundPort { get; private set; } + public uint BoundPort { get; } /// /// Gets a value indicating whether port forwarding is started. @@ -35,7 +43,8 @@ public override bool IsStarted /// Initializes a new instance of the class. /// /// The port. - public ForwardedPortDynamic(uint port) : this(string.Empty, port) + public ForwardedPortDynamic(uint port) + : this(string.Empty, port) { } @@ -57,7 +66,9 @@ public ForwardedPortDynamic(string host, uint port) protected override void StartPort() { if (!ForwardedPortStatus.ToStarting(ref _status)) + { return; + } try { @@ -78,14 +89,19 @@ protected override void StartPort() protected override void StopPort(TimeSpan timeout) { if (!ForwardedPortStatus.ToStopping(ref _status)) + { return; + } // signal existing channels that the port is closing base.StopPort(timeout); + // prevent new requests from getting processed StopListener(); + // wait for open channels to close InternalStop(timeout); + // mark port stopped _status = ForwardedPortStatus.Stopped; } @@ -97,7 +113,9 @@ protected override void StopPort(TimeSpan timeout) protected override void CheckDisposed() { if (_isDisposed) + { throw new ObjectDisposedException(GetType().FullName); + } } partial void InternalStart(); @@ -113,51 +131,40 @@ protected override void CheckDisposed() /// The maximum time to wait for the forwarded port to stop. partial void InternalStop(TimeSpan timeout); - #region IDisposable Members - - /// - /// Holds a value indicating whether the current instance is disposed. - /// - /// - /// true if the current instance is disposed; otherwise, false. - /// - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } partial void InternalDispose(bool disposing); /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool disposing) { if (_isDisposed) + { return; + } base.Dispose(disposing); - InternalDispose(disposing); + InternalDispose(disposing); _isDisposed = true; } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~ForwardedPortDynamic() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } } diff --git a/src/Renci.SshNet/ForwardedPortLocal.NET.cs b/src/Renci.SshNet/ForwardedPortLocal.NET.cs index ba01ddbd3..60777b97a 100644 --- a/src/Renci.SshNet/ForwardedPortLocal.NET.cs +++ b/src/Renci.SshNet/ForwardedPortLocal.NET.cs @@ -1,7 +1,8 @@ 锘縰sing System; -using System.Net.Sockets; using System.Net; +using System.Net.Sockets; using System.Threading; + using Renci.SshNet.Abstractions; using Renci.SshNet.Common; @@ -73,7 +74,7 @@ private void StartAccept(SocketAsyncEventArgs e) private void AcceptCompleted(object sender, SocketAsyncEventArgs e) { - if (e.SocketError == SocketError.OperationAborted || e.SocketError == SocketError.NotSocket) + if (e.SocketError is SocketError.OperationAborted or SocketError.NotSocket) { // server was stopped return; @@ -86,6 +87,7 @@ private void AcceptCompleted(object sender, SocketAsyncEventArgs e) { // accept new connection StartAccept(e); + // dispose broken client socket CloseClientSocket(clientSocket); return; @@ -93,6 +95,7 @@ private void AcceptCompleted(object sender, SocketAsyncEventArgs e) // accept new connection StartAccept(e); + // process connection ProcessAccept(clientSocket); } @@ -139,7 +142,7 @@ private void ProcessAccept(Socket clientSocket) // the CountdownEvent will be disposed try { - pendingChannelCountdown.Signal(); + _ = pendingChannelCountdown.Signal(); } catch (ObjectDisposedException) { @@ -163,10 +166,7 @@ private void ProcessAccept(Socket clientSocket) private void InitializePendingChannelCountdown() { var original = Interlocked.Exchange(ref _pendingChannelCountdown, new CountdownEvent(1)); - if (original != null) - { - original.Dispose(); - } + original?.Dispose(); } private static void CloseClientSocket(Socket clientSocket) @@ -192,11 +192,7 @@ private static void CloseClientSocket(Socket clientSocket) partial void StopListener() { // close listener socket - var listener = _listener; - if (listener != null) - { - listener.Dispose(); - } + _listener?.Dispose(); // unsubscribe from session events var session = Session; @@ -213,7 +209,8 @@ partial void StopListener() /// The maximum time to wait for the pending channels to close. partial void InternalStop(TimeSpan timeout) { - _pendingChannelCountdown.Signal(); + _ = _pendingChannelCountdown.Signal(); + if (!_pendingChannelCountdown.Wait(timeout)) { // TODO: log as warning diff --git a/src/Renci.SshNet/ForwardedPortLocal.cs b/src/Renci.SshNet/ForwardedPortLocal.cs index 79246bd73..fe3215de2 100644 --- a/src/Renci.SshNet/ForwardedPortLocal.cs +++ b/src/Renci.SshNet/ForwardedPortLocal.cs @@ -1,14 +1,17 @@ 锘縰sing System; +using System.Net; + using Renci.SshNet.Common; namespace Renci.SshNet { /// - /// Provides functionality for local port forwarding + /// Provides functionality for local port forwarding. /// public partial class ForwardedPortLocal : ForwardedPort, IDisposable { private ForwardedPortStatus _status; + private bool _isDisposed; /// /// Gets the bound host. @@ -47,9 +50,9 @@ public override bool IsStarted /// The bound port. /// The host. /// The port. - /// is greater than . + /// is greater than . /// is null. - /// is greater than . + /// is greater than . /// /// /// @@ -66,9 +69,9 @@ public ForwardedPortLocal(uint boundPort, string host, uint port) /// The port. /// is null. /// is null. - /// is greater than . + /// is greater than . public ForwardedPortLocal(string boundHost, string host, uint port) - : this(boundHost, 0, host, port) + : this(boundHost, 0, host, port) { } @@ -81,15 +84,19 @@ public ForwardedPortLocal(string boundHost, string host, uint port) /// The port. /// is null. /// is null. - /// is greater than . - /// is greater than . + /// is greater than . + /// is greater than . public ForwardedPortLocal(string boundHost, uint boundPort, string host, uint port) { if (boundHost == null) - throw new ArgumentNullException("boundHost"); + { + throw new ArgumentNullException(nameof(boundHost)); + } if (host == null) - throw new ArgumentNullException("host"); + { + throw new ArgumentNullException(nameof(host)); + } boundPort.ValidatePort("boundPort"); port.ValidatePort("port"); @@ -107,7 +114,9 @@ public ForwardedPortLocal(string boundHost, uint boundPort, string host, uint po protected override void StartPort() { if (!ForwardedPortStatus.ToStarting(ref _status)) + { return; + } try { @@ -128,14 +137,19 @@ protected override void StartPort() protected override void StopPort(TimeSpan timeout) { if (!ForwardedPortStatus.ToStopping(ref _status)) + { return; + } // signal existing channels that the port is closing base.StopPort(timeout); + // prevent new requests from getting processed StopListener(); + // wait for open channels to close InternalStop(timeout); + // mark port stopped _status = ForwardedPortStatus.Stopped; } @@ -147,7 +161,9 @@ protected override void StopPort(TimeSpan timeout) protected override void CheckDisposed() { if (_isDisposed) + { throw new ObjectDisposedException(GetType().FullName); + } } partial void InternalStart(); @@ -162,45 +178,40 @@ protected override void CheckDisposed() partial void InternalStop(TimeSpan timeout); - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } partial void InternalDispose(bool disposing); /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool disposing) { if (_isDisposed) + { return; + } base.Dispose(disposing); - InternalDispose(disposing); + InternalDispose(disposing); _isDisposed = true; } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~ForwardedPortLocal() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } } diff --git a/src/Renci.SshNet/ForwardedPortRemote.cs b/src/Renci.SshNet/ForwardedPortRemote.cs index b2ed15fe4..6405f13a1 100644 --- a/src/Renci.SshNet/ForwardedPortRemote.cs +++ b/src/Renci.SshNet/ForwardedPortRemote.cs @@ -1,23 +1,24 @@ 锘縰sing System; -using System.Threading; -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Common; using System.Globalization; using System.Net; +using System.Threading; + using Renci.SshNet.Abstractions; +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Connection; namespace Renci.SshNet { /// - /// Provides functionality for remote port forwarding + /// Provides functionality for remote port forwarding. /// public class ForwardedPortRemote : ForwardedPort, IDisposable { private ForwardedPortStatus _status; private bool _requestStatus; - private EventWaitHandle _globalRequestResponse = new AutoResetEvent(false); private CountdownEvent _pendingChannelCountdown; + private bool _isDisposed; /// /// Gets a value indicating whether port forwarding is started. @@ -81,14 +82,19 @@ public string Host /// The port. /// is null. /// is null. - /// is greater than . - /// is greater than . + /// is greater than . + /// is greater than . public ForwardedPortRemote(IPAddress boundHostAddress, uint boundPort, IPAddress hostAddress, uint port) { if (boundHostAddress == null) - throw new ArgumentNullException("boundHostAddress"); + { + throw new ArgumentNullException(nameof(boundHostAddress)); + } + if (hostAddress == null) - throw new ArgumentNullException("hostAddress"); + { + throw new ArgumentNullException(nameof(hostAddress)); + } boundPort.ValidatePort("boundPort"); port.ValidatePort("port"); @@ -135,7 +141,9 @@ public ForwardedPortRemote(string boundHost, uint boundPort, string host, uint p protected override void StartPort() { if (!ForwardedPortStatus.ToStarting(ref _status)) + { return; + } InitializePendingChannelCountdown(); @@ -151,6 +159,7 @@ protected override void StartPort() // send global request to start forwarding Session.SendMessage(new TcpIpForwardGlobalRequestMessage(BoundHost, BoundPort)); + // wat for response on global request to start direct tcpip Session.WaitOnHandle(_globalRequestResponse); @@ -183,15 +192,18 @@ protected override void StartPort() protected override void StopPort(TimeSpan timeout) { if (!ForwardedPortStatus.ToStopping(ref _status)) + { return; + } base.StopPort(timeout); // send global request to cancel direct tcpip Session.SendMessage(new CancelTcpIpForwardGlobalRequestMessage(BoundHost, BoundPort)); + // wait for response on global request to cancel direct tcpip or completion of message // listener loop (in which case response on global request can never be received) - WaitHandle.WaitAny(new[] { _globalRequestResponse, Session.MessageListenerCompleted }, timeout); + _ = WaitHandle.WaitAny(new[] { _globalRequestResponse, Session.MessageListenerCompleted }, timeout); // unsubscribe from session events as either the tcpip forward is cancelled at the // server, or our session message loop has completed @@ -200,8 +212,8 @@ protected override void StopPort(TimeSpan timeout) Session.ChannelOpenReceived -= Session_ChannelOpening; // wait for pending channels to close - _pendingChannelCountdown.Signal(); - + _ = _pendingChannelCountdown.Signal(); + if (!_pendingChannelCountdown.Wait(timeout)) { // TODO: log as warning @@ -218,21 +230,24 @@ protected override void StopPort(TimeSpan timeout) protected override void CheckDisposed() { if (_isDisposed) + { throw new ObjectDisposedException(GetType().FullName); + } } private void Session_ChannelOpening(object sender, MessageEventArgs e) { var channelOpenMessage = e.Message; - var info = channelOpenMessage.Info as ForwardedTcpipChannelInfo; - if (info != null) + if (channelOpenMessage.Info is ForwardedTcpipChannelInfo info) { - // Ensure this is the corresponding request + // Ensure this is the corresponding request if (info.ConnectedAddress == BoundHost && info.ConnectedPort == BoundPort) { if (!IsStarted) { - Session.SendMessage(new ChannelOpenFailureMessage(channelOpenMessage.LocalChannelNumber, "", ChannelOpenFailureMessage.AdministrativelyProhibited)); + Session.SendMessage(new ChannelOpenFailureMessage(channelOpenMessage.LocalChannelNumber, + string.Empty, + ChannelOpenFailureMessage.AdministrativelyProhibited)); return; } @@ -266,7 +281,7 @@ private void Session_ChannelOpening(object sender, MessageEventArgs e) { _requestStatus = true; + if (BoundPort == 0) { BoundPort = (e.Message.BoundPort == null) ? 0 : e.Message.BoundPort.Value; } - _globalRequestResponse.Set(); + _ = _globalRequestResponse.Set(); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } @@ -341,7 +350,9 @@ public void Dispose() protected override void Dispose(bool disposing) { if (_isDisposed) + { return; + } base.Dispose(disposing); @@ -375,14 +386,11 @@ protected override void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~ForwardedPortRemote() { Dispose(false); } - - #endregion } } diff --git a/src/Renci.SshNet/ForwardedPortStatus.cs b/src/Renci.SshNet/ForwardedPortStatus.cs index 7fce9ee7e..133c6d5f7 100644 --- a/src/Renci.SshNet/ForwardedPortStatus.cs +++ b/src/Renci.SshNet/ForwardedPortStatus.cs @@ -5,14 +5,14 @@ namespace Renci.SshNet { internal class ForwardedPortStatus { - private readonly int _value; - private readonly string _name; - public static readonly ForwardedPortStatus Stopped = new ForwardedPortStatus(1, "Stopped"); public static readonly ForwardedPortStatus Stopping = new ForwardedPortStatus(2, "Stopping"); public static readonly ForwardedPortStatus Started = new ForwardedPortStatus(3, "Started"); public static readonly ForwardedPortStatus Starting = new ForwardedPortStatus(4, "Starting"); + private readonly int _value; + private readonly string _name; + private ForwardedPortStatus(int value, string name) { _value = value; @@ -21,15 +21,21 @@ private ForwardedPortStatus(int value, string name) public override bool Equals(object other) { - if (ReferenceEquals(other, null)) + if (other is null) + { return false; + } if (ReferenceEquals(this, other)) + { return true; + } var forwardedPortStatus = other as ForwardedPortStatus; if (forwardedPortStatus == null) + { return false; + } return forwardedPortStatus._value == _value; } @@ -37,10 +43,10 @@ public override bool Equals(object other) public static bool operator ==(ForwardedPortStatus left, ForwardedPortStatus right) { // check if lhs is null - if (ReferenceEquals(left, null)) + if (left is null) { // check if both lhs and rhs are null - return (ReferenceEquals(right, null)); + return right is null; } return left.Equals(right); @@ -85,7 +91,9 @@ public static bool ToStopping(ref ForwardedPortStatus status) // we've successfully transitioned from Started to Stopping if (status == Stopping) + { return true; + } // attempt to transition from Starting to Stopping previousStatus = Interlocked.CompareExchange(ref status, Stopping, Starting); @@ -97,7 +105,9 @@ public static bool ToStopping(ref ForwardedPortStatus status) // we've successfully transitioned from Starting to Stopping if (status == Stopping) + { return true; + } // there's no valid transition from status to Stopping throw new InvalidOperationException(string.Format("Forwarded port cannot transition from '{0}' to '{1}'.", @@ -129,7 +139,9 @@ public static bool ToStarting(ref ForwardedPortStatus status) // we've successfully transitioned from Stopped to Starting if (status == Starting) + { return true; + } // there's no valid transition from status to Starting throw new InvalidOperationException(string.Format("Forwarded port cannot transition from '{0}' to '{1}'.", diff --git a/src/Renci.SshNet/IBaseClient.cs b/src/Renci.SshNet/IBaseClient.cs index c11adb4f6..56828f9b4 100644 --- a/src/Renci.SshNet/IBaseClient.cs +++ b/src/Renci.SshNet/IBaseClient.cs @@ -1,9 +1,10 @@ -锘縰sing Renci.SshNet.Common; -using System; +锘縰sing System; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; +using Renci.SshNet.Common; + namespace Renci.SshNet { /// @@ -101,4 +102,4 @@ public interface IBaseClient /// The method was called after the client was disposed. void SendKeepAlive(); } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/IConnectionInfo.cs b/src/Renci.SshNet/IConnectionInfo.cs index 22abefda2..77908d2d7 100644 --- a/src/Renci.SshNet/IConnectionInfo.cs +++ b/src/Renci.SshNet/IConnectionInfo.cs @@ -1,6 +1,7 @@ 锘縰sing System; using System.Collections.Generic; using System.Text; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Messages.Connection; @@ -13,7 +14,7 @@ internal interface IConnectionInfoInternal : IConnectionInfo /// Signals that an authentication banner message was received from the server. /// /// The session in which the banner message was received. - /// The banner message.{ + /// The banner message. void UserAuthenticationBannerReceived(object sender, MessageEventArgs e); /// @@ -41,7 +42,7 @@ internal interface IConnectionInfoInternal : IConnectionInfo internal interface IConnectionInfo { /// - /// Gets or sets the timeout to used when waiting for a server to acknowledge closing a channel. + /// Gets the timeout to used when waiting for a server to acknowledge closing a channel. /// /// /// The channel close timeout. The default value is 1 second. @@ -121,7 +122,7 @@ internal interface IConnectionInfo int RetryAttempts { get; } /// - /// Gets or sets connection timeout. + /// Gets the connection timeout. /// /// /// The connection timeout. The default value is 30 seconds. diff --git a/src/Renci.SshNet/IRemotePathTransformation.cs b/src/Renci.SshNet/IRemotePathTransformation.cs index 30c52421c..d139db5db 100644 --- a/src/Renci.SshNet/IRemotePathTransformation.cs +++ b/src/Renci.SshNet/IRemotePathTransformation.cs @@ -14,6 +14,4 @@ public interface IRemotePathTransformation /// string Transform(string path); } - - } diff --git a/src/Renci.SshNet/IServiceFactory.cs b/src/Renci.SshNet/IServiceFactory.cs index dad93e237..cb20ae064 100644 --- a/src/Renci.SshNet/IServiceFactory.cs +++ b/src/Renci.SshNet/IServiceFactory.cs @@ -75,10 +75,10 @@ internal partial interface IServiceFactory /// The TERM environment variable. /// The terminal width in columns. /// The terminal width in rows. - /// The terminal height in pixels. + /// The terminal width in pixels. /// The terminal height in pixels. - /// Size of the buffer. /// The terminal mode values. + /// Size of the buffer. /// /// The created instance. /// diff --git a/src/Renci.SshNet/ISession.cs b/src/Renci.SshNet/ISession.cs index bc123c776..bc0239b07 100644 --- a/src/Renci.SshNet/ISession.cs +++ b/src/Renci.SshNet/ISession.cs @@ -1,12 +1,13 @@ 锘縰sing System; using System.Net.Sockets; using System.Threading; +using System.Threading.Tasks; + using Renci.SshNet.Channels; using Renci.SshNet.Common; using Renci.SshNet.Messages; using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Messages.Connection; -using System.Threading.Tasks; namespace Renci.SshNet { diff --git a/src/Renci.SshNet/ISftpClient.cs b/src/Renci.SshNet/ISftpClient.cs index 99e1e7b06..82117295c 100644 --- a/src/Renci.SshNet/ISftpClient.cs +++ b/src/Renci.SshNet/ISftpClient.cs @@ -2,11 +2,12 @@ using System.Collections.Generic; using System.IO; using System.Text; -using Renci.SshNet.Sftp; -using Renci.SshNet.Common; using System.Threading; using System.Threading.Tasks; +using Renci.SshNet.Common; +using Renci.SshNet.Sftp; + namespace Renci.SshNet { /// @@ -55,7 +56,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// one (-1) milliseconds, which indicates an infinite timeout period. /// /// The method was called after the client was disposed. - /// represents a value that is less than -1 or greater than milliseconds. + /// represents a value that is less than -1 or greater than milliseconds. TimeSpan OperationTimeout { get; set; } /// @@ -1138,4 +1139,4 @@ public interface ISftpClient : IBaseClient, IDisposable /// void WriteAllText(string path, string contents, Encoding encoding); } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs b/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs index f8c78cbf5..90fc1f283 100644 --- a/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs +++ b/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs @@ -1,10 +1,11 @@ 锘縰sing System; using System.Linq; using System.Threading; + using Renci.SshNet.Abstractions; +using Renci.SshNet.Common; using Renci.SshNet.Messages; using Renci.SshNet.Messages.Authentication; -using Renci.SshNet.Common; namespace Renci.SshNet { @@ -13,16 +14,19 @@ namespace Renci.SshNet /// public class KeyboardInteractiveAuthenticationMethod : AuthenticationMethod, IDisposable { + private readonly RequestMessage _requestMessage; private AuthenticationResult _authenticationResult = AuthenticationResult.Failure; - private Session _session; private EventWaitHandle _authenticationCompleted = new AutoResetEvent(false); private Exception _exception; - private readonly RequestMessage _requestMessage; + private bool _isDisposed; /// - /// Gets authentication method name + /// Gets the name of the authentication method. /// + /// + /// The name of the authentication method. + /// public override string Name { get { return _requestMessage.MethodName; } @@ -73,7 +77,9 @@ public override AuthenticationResult Authenticate(Session session) } if (_exception != null) + { throw _exception; + } return _authenticationResult; } @@ -81,20 +87,24 @@ public override AuthenticationResult Authenticate(Session session) private void Session_UserAuthenticationSuccessReceived(object sender, MessageEventArgs e) { _authenticationResult = AuthenticationResult.Success; - _authenticationCompleted.Set(); + _ = _authenticationCompleted.Set(); } private void Session_UserAuthenticationFailureReceived(object sender, MessageEventArgs e) { if (e.Message.PartialSuccess) + { _authenticationResult = AuthenticationResult.PartialSuccess; + } else + { _authenticationResult = AuthenticationResult.Failure; + } // Copy allowed authentication methods AllowedAuthentications = e.Message.AllowedAuthentications; - _authenticationCompleted.Set(); + _ = _authenticationCompleted.Set(); } private void Session_UserAuthenticationInformationRequestReceived(object sender, MessageEventArgs e) @@ -110,10 +120,7 @@ private void Session_UserAuthenticationInformationRequestReceived(object sender, { try { - if (AuthenticationPrompt != null) - { - AuthenticationPrompt(this, eventArgs); - } + AuthenticationPrompt?.Invoke(this, eventArgs); var informationResponse = new InformationResponseMessage(); @@ -122,38 +129,36 @@ private void Session_UserAuthenticationInformationRequestReceived(object sender, informationResponse.Responses.Add(response); } - // Send information response message + // Send information response message _session.SendMessage(informationResponse); } catch (Exception exp) { _exception = exp; - _authenticationCompleted.Set(); + _ = _authenticationCompleted.Set(); } }); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -169,14 +174,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~KeyboardInteractiveAuthenticationMethod() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } } diff --git a/src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs b/src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs index d8780caa7..af2667842 100644 --- a/src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs +++ b/src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs @@ -4,13 +4,15 @@ namespace Renci.SshNet { /// - /// Provides connection information when keyboard interactive authentication method is used + /// Provides connection information when keyboard interactive authentication method is used. /// /// /// /// public class KeyboardInteractiveConnectionInfo : ConnectionInfo, IDisposable { + private bool _isDisposed; + /// /// Occurs when server prompts for more authentication information. /// @@ -19,8 +21,6 @@ public class KeyboardInteractiveConnectionInfo : ConnectionInfo, IDisposable /// public event EventHandler AuthenticationPrompt; - // TODO: DOCS Add exception documentation for this class. - /// /// Initializes a new instance of the class. /// @@ -29,7 +29,6 @@ public class KeyboardInteractiveConnectionInfo : ConnectionInfo, IDisposable public KeyboardInteractiveConnectionInfo(string host, string username) : this(host, DefaultPort, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty) { - } /// @@ -41,7 +40,6 @@ public KeyboardInteractiveConnectionInfo(string host, string username) public KeyboardInteractiveConnectionInfo(string host, int port, string username) : this(host, port, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty) { - } /// @@ -131,8 +129,7 @@ public KeyboardInteractiveConnectionInfo(string host, int port, string username, { foreach (var authenticationMethod in AuthenticationMethods) { - var kbdInteractive = authenticationMethod as KeyboardInteractiveAuthenticationMethod; - if (kbdInteractive != null) + if (authenticationMethod is KeyboardInteractiveAuthenticationMethod kbdInteractive) { kbdInteractive.AuthenticationPrompt += AuthenticationMethod_AuthenticationPrompt; } @@ -142,34 +139,28 @@ public KeyboardInteractiveConnectionInfo(string host, int port, string username, private void AuthenticationMethod_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e) { - if (AuthenticationPrompt != null) - { - AuthenticationPrompt(sender, e); - } + AuthenticationPrompt?.Invoke(sender, e); } - - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -177,8 +168,7 @@ protected virtual void Dispose(bool disposing) { foreach (var authenticationMethods in AuthenticationMethods) { - var disposable = authenticationMethods as IDisposable; - if (disposable != null) + if (authenticationMethods is IDisposable disposable) { disposable.Dispose(); } @@ -190,14 +180,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~KeyboardInteractiveConnectionInfo() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } } diff --git a/src/Renci.SshNet/MessageEventArgs.cs b/src/Renci.SshNet/MessageEventArgs.cs index 216b8adae..fead62e1e 100644 --- a/src/Renci.SshNet/MessageEventArgs.cs +++ b/src/Renci.SshNet/MessageEventArgs.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet /// /// Provides data for message events. /// - /// Message type + /// Message type. public class MessageEventArgs : EventArgs { /// @@ -14,14 +14,16 @@ public class MessageEventArgs : EventArgs public T Message { get; private set; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The message. /// is null. public MessageEventArgs(T message) { if (message == null) - throw new ArgumentNullException("message"); + { + throw new ArgumentNullException(nameof(message)); + } Message = message; } diff --git a/src/Renci.SshNet/Messages/Authentication/RequestMessageHost.cs b/src/Renci.SshNet/Messages/Authentication/RequestMessageHost.cs index 5d5a22dce..ec9fd2047 100644 --- a/src/Renci.SshNet/Messages/Authentication/RequestMessageHost.cs +++ b/src/Renci.SshNet/Messages/Authentication/RequestMessageHost.cs @@ -3,44 +3,44 @@ /// /// Represents "hostbased" SSH_MSG_USERAUTH_REQUEST message. /// - internal class RequestMessageHost : RequestMessage + internal sealed class RequestMessageHost : RequestMessage { /// /// Gets the public key algorithm for host key as ASCII encoded byte array. /// - public byte[] PublicKeyAlgorithm { get; private set; } + public byte[] PublicKeyAlgorithm { get; } /// - /// Gets or sets the public host key and certificates for client host. + /// Gets the public host key and certificates for client host. /// /// /// The public host key. /// - public byte[] PublicHostKey { get; private set; } + public byte[] PublicHostKey { get; } /// - /// Gets or sets the name of the client host as ASCII encoded byte array. + /// Gets the name of the client host as ASCII encoded byte array. /// /// /// The name of the client host. /// - public byte[] ClientHostName { get; private set; } + public byte[] ClientHostName { get; } /// - /// Gets or sets the client username on the client host as UTF-8 encoded byte array. + /// Gets the client username on the client host as UTF-8 encoded byte array. /// /// /// The client username. /// - public byte[] ClientUsername { get; private set; } + public byte[] ClientUsername { get; } /// - /// Gets or sets the signature. + /// Gets the signature. /// /// /// The signature. /// - public byte[] Signature { get; private set; } + public byte[] Signature { get; } /// /// Gets the size of the message in bytes. diff --git a/src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs index 76c98f364..7e88d2828 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs @@ -11,7 +11,7 @@ public class ChannelDataMessage : ChannelMessage internal const byte MessageNumber = 94; /// - /// Gets or sets message data. + /// Gets the message data. /// /// /// The data. @@ -27,7 +27,7 @@ public class ChannelDataMessage : ChannelMessage /// /// The zero-based offset in at which the data begins. /// - public int Offset { get; set; } + public int Offset { get; private set; } /// /// Gets the number of bytes of to read or write. @@ -35,7 +35,7 @@ public class ChannelDataMessage : ChannelMessage /// /// The number of bytes of to read or write. /// - public int Size { get; set; } + public int Size { get; private set; } /// /// Gets the size of the message in bytes. @@ -75,7 +75,9 @@ public ChannelDataMessage(uint localChannelNumber, byte[] data) : base(localChannelNumber) { if (data == null) - throw new ArgumentNullException("data"); + { + throw new ArgumentNullException(nameof(data)); + } Data = data; Offset = 0; @@ -93,7 +95,9 @@ public ChannelDataMessage(uint localChannelNumber, byte[] data, int offset, int : base(localChannelNumber) { if (data == null) - throw new ArgumentNullException("data"); + { + throw new ArgumentNullException(nameof(data)); + } Data = data; Offset = offset; @@ -106,6 +110,7 @@ public ChannelDataMessage(uint localChannelNumber, byte[] data, int offset, int protected override void LoadData() { base.LoadData(); + Data = ReadBinary(); Offset = 0; Size = Data.Length; @@ -117,6 +122,7 @@ protected override void LoadData() protected override void SaveData() { base.SaveData(); + WriteBinary(Data, Offset, Size); } } diff --git a/src/Renci.SshNet/Messages/Connection/ChannelMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelMessage.cs index b47852b95..e1d6ee995 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelMessage.cs @@ -32,14 +32,14 @@ protected override int BufferCapacity } /// - /// Initializes a new . + /// Initializes a new instance of the class. /// protected ChannelMessage() { } /// - /// Initializes a new with the specified local channel number. + /// Initializes a new instance of the class with the specified local channel number. /// /// The local channel number. protected ChannelMessage(uint localChannelNumber) @@ -64,10 +64,10 @@ protected override void SaveData() } /// - /// Returns a that represents this instance. + /// Returns a that represents this instance. /// /// - /// A that represents this instance. + /// A that represents this instance. /// public override string ToString() { diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenMessage.cs index 1f8bb3e92..b4cac43b4 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenMessage.cs @@ -76,7 +76,7 @@ protected override int BufferCapacity /// public ChannelOpenMessage() { - // Required for dynamicly loading request type when it comes from the server + // Required for dynamicly loading request type when it comes from the server } /// @@ -90,7 +90,9 @@ public ChannelOpenMessage() public ChannelOpenMessage(uint channelNumber, uint initialWindowSize, uint maximumPacketSize, ChannelOpenInfo info) { if (info == null) - throw new ArgumentNullException("info"); + { + throw new ArgumentNullException(nameof(info)); + } ChannelType = Ascii.GetBytes(info.ChannelType); LocalChannelNumber = channelNumber; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpen/DirectTcpipChannelInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpen/DirectTcpipChannelInfo.cs index 8ad47fbb7..596043915 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpen/DirectTcpipChannelInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpen/DirectTcpipChannelInfo.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Messages.Connection /// /// Used to open "direct-tcpip" channel type /// - internal class DirectTcpipChannelInfo : ChannelOpenInfo + internal sealed class DirectTcpipChannelInfo : ChannelOpenInfo { private byte[] _hostToConnect; private byte[] _originatorAddress; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfo.cs index 64d0ebba9..aec13dc01 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfo.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Messages.Connection /// /// Used to open "forwarded-tcpip" channel type /// - internal class ForwardedTcpipChannelInfo : ChannelOpenInfo + internal sealed class ForwardedTcpipChannelInfo : ChannelOpenInfo { private byte[] _connectedAddress; private byte[] _originatorAddress; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpen/SessionChannelOpenInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpen/SessionChannelOpenInfo.cs index bfe047688..edcc9dae9 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpen/SessionChannelOpenInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpen/SessionChannelOpenInfo.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Messages.Connection /// /// Used to open "session" channel type /// - internal class SessionChannelOpenInfo : ChannelOpenInfo + internal sealed class SessionChannelOpenInfo : ChannelOpenInfo { /// /// Specifies channel open type diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpen/X11ChannelOpenInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpen/X11ChannelOpenInfo.cs index 6f62cfdaf..6eef2d510 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpen/X11ChannelOpenInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpen/X11ChannelOpenInfo.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Messages.Connection /// /// Used to open "x11" channel type /// - internal class X11ChannelOpenInfo : ChannelOpenInfo + internal sealed class X11ChannelOpenInfo : ChannelOpenInfo { private byte[] _originatorAddress; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/BreakRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/BreakRequestInfo.cs index 0cadd6379..472f8cb8e 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/BreakRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/BreakRequestInfo.cs @@ -3,7 +3,7 @@ /// /// Represents "break" type channel request information /// - internal class BreakRequestInfo : RequestInfo + internal sealed class BreakRequestInfo : RequestInfo { /// /// Channel request name diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExecRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExecRequestInfo.cs index 673f4c2bf..877dd4326 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExecRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExecRequestInfo.cs @@ -4,14 +4,14 @@ namespace Renci.SshNet.Messages.Connection { /// - /// Represents "exec" type channel request information + /// Represents "exec" type channel request information. /// internal class ExecRequestInfo : RequestInfo { private byte[] _command; /// - /// Channel request name + /// Channel request name. /// public const string Name = "exec"; @@ -80,9 +80,14 @@ public ExecRequestInfo(string command, Encoding encoding) : this() { if (command == null) - throw new ArgumentNullException("command"); + { + throw new ArgumentNullException(nameof(command)); + } + if (encoding == null) - throw new ArgumentNullException("encoding"); + { + throw new ArgumentNullException(nameof(encoding)); + } _command = encoding.GetBytes(command); Encoding = encoding; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs index 6fdc681cb..af57bb2d7 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs @@ -1,15 +1,16 @@ -锘縰sing Renci.SshNet.Common; -using System.Collections.Generic; +锘縰sing System.Collections.Generic; + +using Renci.SshNet.Common; namespace Renci.SshNet.Messages.Connection { /// - /// Represents "pty-req" type channel request information + /// Represents "pty-req" type channel request information. /// internal class PseudoTerminalRequestInfo : RequestInfo { /// - /// Channel request name + /// Channel request name. /// public const string Name = "pty-req"; @@ -98,7 +99,7 @@ public PseudoTerminalRequestInfo() /// The TERM environment variable which a identifier for the text window鈥檚 capabilities. /// The terminal width in columns. /// The terminal width in rows. - /// The terminal height in pixels. + /// The terminal width in pixels. /// The terminal height in pixels. /// The terminal mode values. /// @@ -153,7 +154,7 @@ protected override void SaveData() else { // when there are no terminal mode, the length of the string is zero - Write((uint) 0); + Write(0u); } } } diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ShellRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ShellRequestInfo.cs index 4b570d708..42fc9cf1d 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ShellRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ShellRequestInfo.cs @@ -3,7 +3,7 @@ /// /// Represents "shell" type channel request information /// - internal class ShellRequestInfo : RequestInfo + internal sealed class ShellRequestInfo : RequestInfo { /// /// Channel request name diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/SignalRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/SignalRequestInfo.cs index 493681b44..bb69e5ed2 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/SignalRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/SignalRequestInfo.cs @@ -3,7 +3,7 @@ /// /// Represents "signal" type channel request information /// - internal class SignalRequestInfo : RequestInfo + internal sealed class SignalRequestInfo : RequestInfo { private byte[] _signalName; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/SubsystemRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/SubsystemRequestInfo.cs index 1af72be8e..6871b9fe3 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/SubsystemRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/SubsystemRequestInfo.cs @@ -3,7 +3,7 @@ /// /// Represents "subsystem" type channel request information /// - internal class SubsystemRequestInfo : RequestInfo + internal sealed class SubsystemRequestInfo : RequestInfo { private byte[] _subsystemName; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/WindowChangeRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/WindowChangeRequestInfo.cs index 4f0813bd8..edcd9af54 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/WindowChangeRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/WindowChangeRequestInfo.cs @@ -3,7 +3,7 @@ /// /// Represents "window-change" type channel request information /// - internal class WindowChangeRequestInfo : RequestInfo + internal sealed class WindowChangeRequestInfo : RequestInfo { /// /// Channe request name diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/X11ForwardingRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/X11ForwardingRequestInfo.cs index 89ebfe4f9..4d27872eb 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/X11ForwardingRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/X11ForwardingRequestInfo.cs @@ -1,14 +1,14 @@ 锘縩amespace Renci.SshNet.Messages.Connection { /// - /// Represents "x11-req" type channel request information + /// Represents "x11-req" type channel request information. /// - internal class X11ForwardingRequestInfo : RequestInfo + internal sealed class X11ForwardingRequestInfo : RequestInfo { private byte[] _authenticationProtocol; /// - /// Channel request name + /// Channel request name. /// public const string Name = "x11-req"; @@ -27,7 +27,7 @@ public override string RequestName /// Gets or sets a value indicating whether it is a single connection. /// /// - /// true if it is a single connection; otherwise, false. + /// true if it is a single connection; otherwise, false. /// public bool IsSingleConnection { get; set; } diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/XonXoffRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/XonXoffRequestInfo.cs index ff10a73ab..b53578de9 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/XonXoffRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/XonXoffRequestInfo.cs @@ -3,10 +3,10 @@ /// /// Represents "xon-xoff" type channel request information /// - internal class XonXoffRequestInfo : RequestInfo + internal sealed class XonXoffRequestInfo : RequestInfo { /// - /// Channel request type + /// Channel request type. /// public const string Name = "xon-xoff"; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelWindowAdjustMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelWindowAdjustMessage.cs index 364b81300..315c98c8a 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelWindowAdjustMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelWindowAdjustMessage.cs @@ -32,7 +32,6 @@ protected override int BufferCapacity /// public ChannelWindowAdjustMessage() { - } /// @@ -52,6 +51,7 @@ public ChannelWindowAdjustMessage(uint localChannelNumber, uint bytesToAdd) protected override void LoadData() { base.LoadData(); + BytesToAdd = ReadUInt32(); } @@ -61,6 +61,7 @@ protected override void LoadData() protected override void SaveData() { base.SaveData(); + Write(BytesToAdd); } diff --git a/src/Renci.SshNet/Messages/Connection/RequestFailureMessage.cs b/src/Renci.SshNet/Messages/Connection/RequestFailureMessage.cs index af9df7501..553f95473 100644 --- a/src/Renci.SshNet/Messages/Connection/RequestFailureMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/RequestFailureMessage.cs @@ -1,5 +1,4 @@ -锘 -namespace Renci.SshNet.Messages.Connection +锘縩amespace Renci.SshNet.Messages.Connection { /// /// Represents SSH_MSG_REQUEST_FAILURE message. diff --git a/src/Renci.SshNet/Messages/Connection/RequestSuccessMessage.cs b/src/Renci.SshNet/Messages/Connection/RequestSuccessMessage.cs index b456efe85..00ad1059d 100644 --- a/src/Renci.SshNet/Messages/Connection/RequestSuccessMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/RequestSuccessMessage.cs @@ -22,8 +22,12 @@ protected override int BufferCapacity get { var capacity = base.BufferCapacity; + if (BoundPort.HasValue) + { capacity += 4; // BoundPort + } + return capacity; } } @@ -33,7 +37,6 @@ protected override int BufferCapacity /// public RequestSuccessMessage() { - } /// @@ -51,7 +54,9 @@ public RequestSuccessMessage(uint boundPort) protected override void LoadData() { if (!IsEndOfData) + { BoundPort = ReadUInt32(); + } } /// @@ -60,7 +65,9 @@ protected override void LoadData() protected override void SaveData() { if (BoundPort.HasValue) + { Write(BoundPort.Value); + } } internal override void Process(Session session) diff --git a/src/Renci.SshNet/Messages/Connection/TcpIpForwardGlobalRequestMessage.cs b/src/Renci.SshNet/Messages/Connection/TcpIpForwardGlobalRequestMessage.cs index 83d0b013c..fdfbfb8df 100644 --- a/src/Renci.SshNet/Messages/Connection/TcpIpForwardGlobalRequestMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/TcpIpForwardGlobalRequestMessage.cs @@ -2,7 +2,7 @@ namespace Renci.SshNet.Messages.Connection { - internal class TcpIpForwardGlobalRequestMessage : GlobalRequestMessage + internal sealed class TcpIpForwardGlobalRequestMessage : GlobalRequestMessage { private byte[] _addressToBind; diff --git a/src/Renci.SshNet/Messages/Message.cs b/src/Renci.SshNet/Messages/Message.cs index 2bbfb7b9e..d2fc3274a 100644 --- a/src/Renci.SshNet/Messages/Message.cs +++ b/src/Renci.SshNet/Messages/Message.cs @@ -1,7 +1,8 @@ -锘縰sing System.IO; -using Renci.SshNet.Common; -using System.Globalization; +锘縰sing System.Globalization; +using System.IO; + using Renci.SshNet.Abstractions; +using Renci.SshNet.Common; using Renci.SshNet.Compression; namespace Renci.SshNet.Messages @@ -30,7 +31,7 @@ protected override int BufferCapacity /// protected override void WriteBytes(SshDataStream stream) { - var enumerator = GetType().GetCustomAttributes(true).GetEnumerator(); + var enumerator = GetType().GetCustomAttributes(inherit: true).GetEnumerator(); try { if (!enumerator.MoveNext()) @@ -64,7 +65,7 @@ internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor) // * 4 bytes for the outbound packet sequence // * 4 bytes for the packet data length // * one byte for the packet padding length - sshDataStream.Seek(outboundPacketSequenceSize + 4 + 1, SeekOrigin.Begin); + _ = sshDataStream.Seek(outboundPacketSequenceSize + 4 + 1, SeekOrigin.Begin); if (compressor != null) { @@ -99,12 +100,12 @@ internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor) var packetDataLength = GetPacketDataLength(messageLength, paddingLength); // skip bytes for outbound packet sequence - sshDataStream.Seek(outboundPacketSequenceSize, SeekOrigin.Begin); + _ = sshDataStream.Seek(outboundPacketSequenceSize, SeekOrigin.Begin); // add packet data length sshDataStream.Write(packetDataLength); - // add packet padding length + // add packet padding length sshDataStream.WriteByte(paddingLength); } else @@ -120,12 +121,12 @@ internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor) sshDataStream = new SshDataStream(packetLength + paddingLength + outboundPacketSequenceSize); // skip bytes for outbound packet sequenceSize - sshDataStream.Seek(outboundPacketSequenceSize, SeekOrigin.Begin); + _ = sshDataStream.Seek(outboundPacketSequenceSize, SeekOrigin.Begin); // add packet data length sshDataStream.Write(packetDataLength); - // add packet padding length + // add packet padding length sshDataStream.WriteByte(paddingLength); // add message payload @@ -148,10 +149,12 @@ private static uint GetPacketDataLength(int messageLength, byte paddingLength) private static byte GetPaddingLength(byte paddingMultiplier, long packetLength) { var paddingLength = (byte)((-packetLength) & (paddingMultiplier - 1)); + if (paddingLength < paddingMultiplier) { paddingLength += paddingMultiplier; } + return paddingLength; } @@ -163,8 +166,7 @@ private static byte GetPaddingLength(byte paddingMultiplier, long packetLength) /// public override string ToString() { - var enumerator = GetType().GetCustomAttributes(true).GetEnumerator(); - try + using (var enumerator = GetType().GetCustomAttributes(inherit: true).GetEnumerator()) { if (!enumerator.MoveNext()) { @@ -173,10 +175,6 @@ public override string ToString() return enumerator.Current.Name; } - finally - { - enumerator.Dispose(); - } } /// @@ -185,4 +183,4 @@ public override string ToString() /// The for which to process the current message. internal abstract void Process(Session session); } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs b/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs index 580cd3b21..72fc10699 100644 --- a/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs @@ -50,7 +50,9 @@ protected override int BufferCapacity public IgnoreMessage(byte[] data) { if (data == null) - throw new ArgumentNullException("data"); + { + throw new ArgumentNullException(nameof(data)); + } Data = data; } diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs index c8af4724d..381c534b9 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs @@ -4,7 +4,7 @@ /// Represents SSH_MSG_KEX_DH_GEX_INIT message. /// [Message("SSH_MSG_KEX_DH_GEX_INIT", 32)] - internal class KeyExchangeDhGroupExchangeInit : Message, IKeyExchangedAllowed + internal sealed class KeyExchangeDhGroupExchangeInit : Message, IKeyExchangedAllowed { /// /// Gets the E value. diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs index 88bad74e2..7b446d962 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs @@ -1,19 +1,19 @@ -锘縰sing Renci.SshNet.Common; - -namespace Renci.SshNet.Messages.Transport +锘縩amespace Renci.SshNet.Messages.Transport { /// /// Represents SSH_MSG_KEX_DH_GEX_REPLY message. /// [Message("SSH_MSG_KEX_DH_GEX_REPLY", MessageNumber)] - internal class KeyExchangeDhGroupExchangeReply : Message + internal sealed class KeyExchangeDhGroupExchangeReply : Message { internal const byte MessageNumber = 33; /// - /// Gets server public host key and certificates + /// Gets server public host key and certificates. /// - /// The host key. + /// + /// The host key. + /// public byte[] HostKey { get; private set; } /// diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeRequest.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeRequest.cs index d31335910..9bb6c6bc8 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeRequest.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeRequest.cs @@ -4,12 +4,12 @@ /// Represents SSH_MSG_KEX_DH_GEX_REQUEST message. /// [Message("SSH_MSG_KEX_DH_GEX_REQUEST", MessageNumber)] - internal class KeyExchangeDhGroupExchangeRequest : Message, IKeyExchangedAllowed + internal sealed class KeyExchangeDhGroupExchangeRequest : Message, IKeyExchangedAllowed { internal const byte MessageNumber = 34; /// - /// Gets or sets the minimal size in bits of an acceptable group. + /// Gets the minimum size, in bits, of an acceptable group. /// /// /// The minimum. @@ -17,7 +17,7 @@ internal class KeyExchangeDhGroupExchangeRequest : Message, IKeyExchangedAllowed public uint Minimum { get; private set; } /// - /// Gets or sets the preferred size in bits of the group the server will send. + /// Gets the preferred size, in bits, of the group the server will send. /// /// /// The preferred. @@ -25,7 +25,7 @@ internal class KeyExchangeDhGroupExchangeRequest : Message, IKeyExchangedAllowed public uint Preferred { get; private set; } /// - /// Gets or sets the maximal size in bits of an acceptable group. + /// Gets the maximum size, in bits, of an acceptable group. /// /// /// The maximum. diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs index 9d1d76850..5b681d1b4 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs @@ -4,7 +4,7 @@ /// Represents SSH_MSG_KEXDH_INIT message. /// [Message("SSH_MSG_KEXDH_INIT", 30)] - internal class KeyExchangeDhInitMessage : Message, IKeyExchangedAllowed + internal sealed class KeyExchangeDhInitMessage : Message, IKeyExchangedAllowed { /// /// Gets the E value. diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs index ddcf03f19..4bd508f54 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs @@ -7,7 +7,7 @@ namespace Renci.SshNet.Messages.Transport /// Represents SSH_MSG_KEXECDH_INIT message. /// [Message("SSH_MSG_KEX_ECDH_INIT", 30)] - internal class KeyExchangeEcdhInitMessage : Message, IKeyExchangedAllowed + internal sealed class KeyExchangeEcdhInitMessage : Message, IKeyExchangedAllowed { /// /// Gets the client's ephemeral contribution to the ECDH exchange, encoded as an octet string @@ -75,4 +75,4 @@ internal override void Process(Session session) throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/NetConfClient.cs b/src/Renci.SshNet/NetConfClient.cs index b7ec82ec2..bbedca3c2 100644 --- a/src/Renci.SshNet/NetConfClient.cs +++ b/src/Renci.SshNet/NetConfClient.cs @@ -1,13 +1,13 @@ 锘縰sing System; -using Renci.SshNet.Common; -using Renci.SshNet.NetConf; -using System.Xml; using System.Diagnostics.CodeAnalysis; using System.Net; +using System.Xml; + +using Renci.SshNet.Common; +using Renci.SshNet.NetConf; namespace Renci.SshNet { - // TODO: Please help with documentation here, as I don't know the details, specially for the methods not documented. /// /// Contains operation for working with NetConf server. /// @@ -16,7 +16,7 @@ public class NetConfClient : BaseClient private int _operationTimeout; /// - /// Holds instance that used to communicate to the server + /// Holds instance that used to communicate to the server. /// private INetConfSession _netConfSession; @@ -27,14 +27,20 @@ public class NetConfClient : BaseClient /// The timeout to wait until an operation completes. The default value is negative /// one (-1) milliseconds, which indicates an infinite time-out period. /// - /// represents a value that is less than -1 or greater than milliseconds. - public TimeSpan OperationTimeout { - get { return TimeSpan.FromMilliseconds(_operationTimeout); } + /// represents a value that is less than -1 or greater than milliseconds. + public TimeSpan OperationTimeout + { + get + { + return TimeSpan.FromMilliseconds(_operationTimeout); + } set { var timeoutInMilliseconds = value.TotalMilliseconds; - if (timeoutInMilliseconds < -1d || timeoutInMilliseconds > int.MaxValue) - throw new ArgumentOutOfRangeException("value", "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); + if (timeoutInMilliseconds is < -1d or > int.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(value), "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); + } _operationTimeout = (int) timeoutInMilliseconds; } @@ -51,15 +57,13 @@ internal INetConfSession NetConfSession get { return _netConfSession; } } - #region Constructors - /// /// Initializes a new instance of the class. /// /// The connection info. /// is null. public NetConfClient(ConnectionInfo connectionInfo) - : this(connectionInfo, false) + : this(connectionInfo, ownsConnectionInfo: false) { } @@ -75,7 +79,7 @@ public NetConfClient(ConnectionInfo connectionInfo) /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] public NetConfClient(string host, int port, string username, string password) - : this(new PasswordConnectionInfo(host, port, username, password), true) + : this(new PasswordConnectionInfo(host, port, username, password), ownsConnectionInfo: true) { } @@ -104,7 +108,7 @@ public NetConfClient(string host, string username, string password) /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] public NetConfClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) - : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) + : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -155,8 +159,6 @@ internal NetConfClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, I AutomaticMessageIdHandling = true; } - #endregion - /// /// Gets the NetConf server capabilities. /// @@ -193,7 +195,9 @@ public XmlDocument ClientCapabilities /// Sends the receive RPC. /// /// The RPC. - /// Reply message to RPC request + /// + /// Reply message to RPC request. + /// /// Client is not connected. public XmlDocument SendReceiveRpc(XmlDocument rpc) { @@ -204,7 +208,9 @@ public XmlDocument SendReceiveRpc(XmlDocument rpc) /// Sends the receive RPC. /// /// The XML. - /// Reply message to RPC request + /// + /// Reply message to RPC request. + /// public XmlDocument SendReceiveRpc(string xml) { var rpc = new XmlDocument(); @@ -215,7 +221,9 @@ public XmlDocument SendReceiveRpc(string xml) /// /// Sends the close RPC. /// - /// Reply message to closing RPC request + /// + /// Reply message to closing RPC request. + /// /// Client is not connected. public XmlDocument SendCloseRpc() { @@ -245,7 +253,7 @@ protected override void OnDisconnecting() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool disposing) @@ -277,4 +285,4 @@ private INetConfSession CreateAndConnectNetConfSession() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Netconf/NetConfSession.cs b/src/Renci.SshNet/Netconf/NetConfSession.cs index 14ba00a6e..6e4e251f7 100644 --- a/src/Renci.SshNet/Netconf/NetConfSession.cs +++ b/src/Renci.SshNet/Netconf/NetConfSession.cs @@ -1,10 +1,11 @@ 锘縰sing System; using System.Globalization; using System.Text; +using System.Text.RegularExpressions; using System.Threading; -using Renci.SshNet.Common; using System.Xml; -using System.Text.RegularExpressions; + +using Renci.SshNet.Common; namespace Renci.SshNet.NetConf { @@ -14,8 +15,8 @@ internal class NetConfSession : SubsystemSession, INetConfSession private readonly StringBuilder _data = new StringBuilder(); private bool _usingFramingProtocol; - private EventWaitHandle _serverCapabilitiesConfirmed = new AutoResetEvent(false); - private EventWaitHandle _rpcReplyReceived = new AutoResetEvent(false); + private EventWaitHandle _serverCapabilitiesConfirmed = new AutoResetEvent(initialState: false); + private EventWaitHandle _rpcReplyReceived = new AutoResetEvent(initialState: false); private StringBuilder _rpcReply = new StringBuilder(); private int _messageId; @@ -46,12 +47,11 @@ public NetConfSession(ISession session, int operationTimeout) "" + "" + ""); - } public XmlDocument SendReceiveRpc(XmlDocument rpc, bool automaticMessageIdHandling) { - _data.Clear(); + _ = _data.Clear(); XmlNamespaceManager nsMgr = null; if (automaticMessageIdHandling) @@ -61,15 +61,16 @@ public XmlDocument SendReceiveRpc(XmlDocument rpc, bool automaticMessageIdHandli nsMgr.AddNamespace("nc", "urn:ietf:params:xml:ns:netconf:base:1.0"); rpc.SelectSingleNode("/nc:rpc/@message-id", nsMgr).Value = _messageId.ToString(CultureInfo.InvariantCulture); } + _rpcReply = new StringBuilder(); - _rpcReplyReceived.Reset(); + _ = _rpcReplyReceived.Reset(); var reply = new XmlDocument(); if (_usingFramingProtocol) { var command = new StringBuilder(rpc.InnerXml.Length + 10); - command.AppendFormat("\n#{0}\n", rpc.InnerXml.Length); - command.Append(rpc.InnerXml); - command.Append("\n##\n"); + _ = command.AppendFormat(CultureInfo.InvariantCulture, "\n#{0}\n", rpc.InnerXml.Length); + _ = command.Append(rpc.InnerXml); + _ = command.Append("\n##\n"); SendData(Encoding.UTF8.GetBytes(command.ToString())); WaitOnHandle(_rpcReplyReceived, OperationTimeout); @@ -81,6 +82,7 @@ public XmlDocument SendReceiveRpc(XmlDocument rpc, bool automaticMessageIdHandli WaitOnHandle(_rpcReplyReceived, OperationTimeout); reply.LoadXml(_rpcReply.ToString()); } + if (automaticMessageIdHandling) { var replyId = rpc.SelectSingleNode("/nc:rpc/@message-id", nsMgr).Value; @@ -89,14 +91,15 @@ public XmlDocument SendReceiveRpc(XmlDocument rpc, bool automaticMessageIdHandli throw new NetConfServerException("The rpc message id does not match the rpc-reply message id."); } } + return reply; } protected override void OnChannelOpen() { - _data.Clear(); + _ = _data.Clear(); - var message = string.Format("{0}{1}", ClientCapabilities.InnerXml, Prompt); + var message = string.Concat(ClientCapabilities.InnerXml, Prompt); SendData(Encoding.UTF8.GetBytes(message)); @@ -107,21 +110,22 @@ protected override void OnDataReceived(byte[] data) { var chunk = Encoding.UTF8.GetString(data); - if (ServerCapabilities == null) // This must be server capabilities, old protocol + if (ServerCapabilities == null) { - _data.Append(chunk); + _ = _data.Append(chunk); if (!chunk.Contains(Prompt)) { return; } + try { - chunk = _data.ToString(); - _data.Clear(); + chunk = _data.ToString(); + _ = _data.Clear(); ServerCapabilities = new XmlDocument(); - ServerCapabilities.LoadXml(chunk.Replace(Prompt, "")); + ServerCapabilities.LoadXml(chunk.Replace(Prompt, string.Empty)); } catch (XmlException e) { @@ -131,9 +135,9 @@ protected override void OnDataReceived(byte[] data) var nsMgr = new XmlNamespaceManager(ServerCapabilities.NameTable); nsMgr.AddNamespace("nc", "urn:ietf:params:xml:ns:netconf:base:1.0"); - _usingFramingProtocol = (ServerCapabilities.SelectSingleNode("/nc:hello/nc:capabilities/nc:capability[text()='urn:ietf:params:netconf:base:1.1']", nsMgr) != null); + _usingFramingProtocol = ServerCapabilities.SelectSingleNode("/nc:hello/nc:capabilities/nc:capability[text()='urn:ietf:params:netconf:base:1.1']", nsMgr) != null; - _serverCapabilitiesConfirmed.Set(); + _ = _serverCapabilitiesConfirmed.Set(); } else if (_usingFramingProtocol) { @@ -146,30 +150,31 @@ protected override void OnDataReceived(byte[] data) { break; } - var fractionLength = Convert.ToInt32(match.Groups["length"].Value); - _rpcReply.Append(chunk, position + match.Index + match.Length, fractionLength); + + var fractionLength = Convert.ToInt32(match.Groups["length"].Value, CultureInfo.InvariantCulture); + _ = _rpcReply.Append(chunk, position + match.Index + match.Length, fractionLength); position += match.Index + match.Length + fractionLength; } + if (Regex.IsMatch(chunk.Substring(position), @"\n##\n")) { - _rpcReplyReceived.Set(); + _ = _rpcReplyReceived.Set(); } } - else // Old protocol + else { - _data.Append(chunk); + _ = _data.Append(chunk); if (!chunk.Contains(Prompt)) { return; - //throw new NetConfServerException("Server XML message does not end with the prompt " + _prompt); } - + chunk = _data.ToString(); - _data.Clear(); + _ = _data.Clear(); - _rpcReply.Append(chunk.Replace(Prompt, "")); - _rpcReplyReceived.Set(); + _ = _rpcReply.Append(chunk.Replace(Prompt, string.Empty)); + _ = _rpcReplyReceived.Set(); } } diff --git a/src/Renci.SshNet/NoneAuthenticationMethod.cs b/src/Renci.SshNet/NoneAuthenticationMethod.cs index 93586ade9..468d46559 100644 --- a/src/Renci.SshNet/NoneAuthenticationMethod.cs +++ b/src/Renci.SshNet/NoneAuthenticationMethod.cs @@ -1,20 +1,22 @@ 锘縰sing System; using System.Threading; -using Renci.SshNet.Messages.Authentication; + using Renci.SshNet.Messages; +using Renci.SshNet.Messages.Authentication; namespace Renci.SshNet { /// - /// Provides functionality for "none" authentication method + /// Provides functionality for "none" authentication method. /// public class NoneAuthenticationMethod : AuthenticationMethod, IDisposable { private AuthenticationResult _authenticationResult = AuthenticationResult.Failure; private EventWaitHandle _authenticationCompleted = new AutoResetEvent(false); + private bool _isDisposed; /// - /// Gets connection name + /// Gets the name of the authentication method. /// public override string Name { @@ -42,7 +44,9 @@ public NoneAuthenticationMethod(string username) public override AuthenticationResult Authenticate(Session session) { if (session == null) - throw new ArgumentNullException("session"); + { + throw new ArgumentNullException(nameof(session)); + } session.UserAuthenticationSuccessReceived += Session_UserAuthenticationSuccessReceived; session.UserAuthenticationFailureReceived += Session_UserAuthenticationFailureReceived; @@ -65,43 +69,45 @@ private void Session_UserAuthenticationSuccessReceived(object sender, MessageEve { _authenticationResult = AuthenticationResult.Success; - _authenticationCompleted.Set(); + _ = _authenticationCompleted.Set(); } private void Session_UserAuthenticationFailureReceived(object sender, MessageEventArgs e) { if (e.Message.PartialSuccess) + { _authenticationResult = AuthenticationResult.PartialSuccess; + } else + { _authenticationResult = AuthenticationResult.Failure; + } // Copy allowed authentication methods AllowedAuthentications = e.Message.AllowedAuthentications; - _authenticationCompleted.Set(); + _ = _authenticationCompleted.Set(); } - - #region IDisposable Members - - private bool _isDisposed; /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -117,15 +123,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~NoneAuthenticationMethod() { - Dispose(false); + Dispose(disposing: false); } - - #endregion - } } diff --git a/src/Renci.SshNet/PasswordAuthenticationMethod.cs b/src/Renci.SshNet/PasswordAuthenticationMethod.cs index 48e46bef3..a60b40ebf 100644 --- a/src/Renci.SshNet/PasswordAuthenticationMethod.cs +++ b/src/Renci.SshNet/PasswordAuthenticationMethod.cs @@ -1,10 +1,11 @@ 锘縰sing System; using System.Text; using System.Threading; + using Renci.SshNet.Abstractions; using Renci.SshNet.Common; -using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Messages; +using Renci.SshNet.Messages.Authentication; namespace Renci.SshNet { @@ -13,15 +14,16 @@ namespace Renci.SshNet /// public class PasswordAuthenticationMethod : AuthenticationMethod, IDisposable { + private readonly RequestMessage _requestMessage; + private readonly byte[] _password; private AuthenticationResult _authenticationResult = AuthenticationResult.Failure; private Session _session; private EventWaitHandle _authenticationCompleted = new AutoResetEvent(false); private Exception _exception; - private readonly RequestMessage _requestMessage; - private readonly byte[] _password; + private bool _isDisposed; /// - /// Gets authentication method name + /// Gets the name of the authentication method. /// public override string Name { @@ -67,7 +69,9 @@ public PasswordAuthenticationMethod(string username, byte[] password) : base(username) { if (password == null) - throw new ArgumentNullException("password"); + { + throw new ArgumentNullException(nameof(password)); + } _password = password; _requestMessage = new RequestMessagePassword(ServiceName.Connection, Username, _password); @@ -84,7 +88,9 @@ public PasswordAuthenticationMethod(string username, byte[] password) public override AuthenticationResult Authenticate(Session session) { if (session == null) - throw new ArgumentNullException("session"); + { + throw new ArgumentNullException(nameof(session)); + } _session = session; @@ -107,7 +113,9 @@ public override AuthenticationResult Authenticate(Session session) } if (_exception != null) + { throw _exception; + } return _authenticationResult; } @@ -116,20 +124,24 @@ private void Session_UserAuthenticationSuccessReceived(object sender, MessageEve { _authenticationResult = AuthenticationResult.Success; - _authenticationCompleted.Set(); + _ = _authenticationCompleted.Set(); } private void Session_UserAuthenticationFailureReceived(object sender, MessageEventArgs e) { if (e.Message.PartialSuccess) + { _authenticationResult = AuthenticationResult.PartialSuccess; + } else + { _authenticationResult = AuthenticationResult.Failure; + } - // Copy allowed authentication methods + // Copy allowed authentication methods AllowedAuthentications = e.Message.AllowedAuthentications; - _authenticationCompleted.Set(); + _ = _authenticationCompleted.Set(); } private void Session_UserAuthenticationPasswordChangeRequiredReceived(object sender, MessageEventArgs e) @@ -142,45 +154,40 @@ private void Session_UserAuthenticationPasswordChangeRequiredReceived(object sen { var eventArgs = new AuthenticationPasswordChangeEventArgs(Username); - // Raise an event to allow user to supply a new password - if (PasswordExpired != null) - { - PasswordExpired(this, eventArgs); - } + // Raise an event to allow user to supply a new password + PasswordExpired?.Invoke(this, eventArgs); - // Send new authentication request with new password + // Send new authentication request with new password _session.SendMessage(new RequestMessagePassword(ServiceName.Connection, Username, _password, eventArgs.NewPassword)); } catch (Exception exp) { _exception = exp; - _authenticationCompleted.Set(); + _ = _authenticationCompleted.Set(); } }); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; - + } + if (disposing) { var authenticationCompleted = _authenticationCompleted; @@ -195,14 +202,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~PasswordAuthenticationMethod() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } } diff --git a/src/Renci.SshNet/PasswordConnectionInfo.cs b/src/Renci.SshNet/PasswordConnectionInfo.cs index d42ff5094..28317411d 100644 --- a/src/Renci.SshNet/PasswordConnectionInfo.cs +++ b/src/Renci.SshNet/PasswordConnectionInfo.cs @@ -15,6 +15,8 @@ namespace Renci.SshNet /// public class PasswordConnectionInfo : ConnectionInfo, IDisposable { + private bool _isDisposed; + /// /// Occurs when user's password has expired and needs to be changed. /// @@ -249,8 +251,7 @@ public PasswordConnectionInfo(string host, int port, string username, byte[] pas { foreach (var authenticationMethod in AuthenticationMethods) { - var pwdAuthentication = authenticationMethod as PasswordAuthenticationMethod; - if (pwdAuthentication != null) + if (authenticationMethod is PasswordAuthenticationMethod pwdAuthentication) { pwdAuthentication.PasswordExpired += AuthenticationMethod_PasswordExpired; } @@ -259,33 +260,28 @@ public PasswordConnectionInfo(string host, int port, string username, byte[] pas private void AuthenticationMethod_PasswordExpired(object sender, AuthenticationPasswordChangeEventArgs e) { - if (PasswordExpired != null) - { - PasswordExpired(sender, e); - } + PasswordExpired?.Invoke(sender, e); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -293,8 +289,7 @@ protected virtual void Dispose(bool disposing) { foreach (var authenticationMethod in AuthenticationMethods) { - var disposable = authenticationMethod as IDisposable; - if (disposable != null) + if (authenticationMethod is IDisposable disposable) { disposable.Dispose(); } @@ -306,17 +301,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~PasswordConnectionInfo() { - // Do not re-create Dispose clean-up code here. - // Calling Dispose(false) is optimal in terms of - // readability and maintainability. - Dispose(false); + Dispose(disposing: false); } - - #endregion } } diff --git a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs index 43d80b506..25f3f7605 100644 --- a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs +++ b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs @@ -1,11 +1,12 @@ 锘縰sing System; using System.Collections.Generic; using System.Collections.ObjectModel; -using Renci.SshNet.Messages.Authentication; -using Renci.SshNet.Messages; -using Renci.SshNet.Common; using System.Threading; +using Renci.SshNet.Common; +using Renci.SshNet.Messages; +using Renci.SshNet.Messages.Authentication; + namespace Renci.SshNet { /// @@ -16,9 +17,10 @@ public class PrivateKeyAuthenticationMethod : AuthenticationMethod, IDisposable private AuthenticationResult _authenticationResult = AuthenticationResult.Failure; private EventWaitHandle _authenticationCompleted = new ManualResetEvent(false); private bool _isSignatureRequired; + private bool _isDisposed; /// - /// Gets authentication method name + /// Gets the name of the authentication method. /// public override string Name { @@ -40,7 +42,9 @@ public PrivateKeyAuthenticationMethod(string username, params IPrivateKeySource[ : base(username) { if (keyFiles == null) - throw new ArgumentNullException("keyFiles"); + { + throw new ArgumentNullException(nameof(keyFiles)); + } KeyFiles = new Collection(keyFiles); } @@ -64,7 +68,7 @@ public override AuthenticationResult Authenticate(Session session) { foreach (var keyFile in KeyFiles) { - _authenticationCompleted.Reset(); + _ = _authenticationCompleted.Reset(); _isSignatureRequired = false; var message = new RequestMessagePublicKey(ServiceName.Connection, @@ -74,20 +78,20 @@ public override AuthenticationResult Authenticate(Session session) if (KeyFiles.Count < 2) { - // If only one key file provided then send signature for very first request + // If only one key file provided then send signature for very first request var signatureData = new SignatureData(message, session.SessionId).GetBytes(); message.Signature = keyFile.HostKey.Sign(signatureData); } - // Send public key authentication request + // Send public key authentication request session.SendMessage(message); session.WaitOnHandle(_authenticationCompleted); if (_isSignatureRequired) { - _authenticationCompleted.Reset(); + _ = _authenticationCompleted.Reset(); var signatureMessage = new RequestMessagePublicKey(ServiceName.Connection, Username, @@ -98,7 +102,7 @@ public override AuthenticationResult Authenticate(Session session) signatureMessage.Signature = keyFile.HostKey.Sign(signatureData); - // Send public key authentication request with signature + // Send public key authentication request with signature session.SendMessage(signatureMessage); } @@ -125,38 +129,38 @@ private void Session_UserAuthenticationSuccessReceived(object sender, MessageEve { _authenticationResult = AuthenticationResult.Success; - _authenticationCompleted.Set(); + _ = _authenticationCompleted.Set(); } private void Session_UserAuthenticationFailureReceived(object sender, MessageEventArgs e) { if (e.Message.PartialSuccess) + { _authenticationResult = AuthenticationResult.PartialSuccess; + } else + { _authenticationResult = AuthenticationResult.Failure; + } - // Copy allowed authentication methods + // Copy allowed authentication methods AllowedAuthentications = e.Message.AllowedAuthentications; - _authenticationCompleted.Set(); + _ = _authenticationCompleted.Set(); } private void Session_UserAuthenticationPublicKeyReceived(object sender, MessageEventArgs e) { _isSignatureRequired = true; - _authenticationCompleted.Set(); + _ = _authenticationCompleted.Set(); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } @@ -167,7 +171,9 @@ public void Dispose() protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -183,17 +189,14 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~PrivateKeyAuthenticationMethod() { - Dispose(false); + Dispose(disposing: false); } - #endregion - - private class SignatureData : SshData + private sealed class SignatureData : SshData { private readonly RequestMessagePublicKey _message; @@ -250,4 +253,4 @@ protected override void SaveData() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs index 1f717631b..29b48ffaa 100644 --- a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs +++ b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs @@ -5,13 +5,15 @@ namespace Renci.SshNet { /// - /// Provides connection information when private key authentication method is used + /// Provides connection information when private key authentication method is used. /// /// /// /// public class PrivateKeyConnectionInfo : ConnectionInfo, IDisposable { + private bool _isDisposed; + /// /// Gets the key files used for authentication. /// @@ -30,7 +32,6 @@ public class PrivateKeyConnectionInfo : ConnectionInfo, IDisposable public PrivateKeyConnectionInfo(string host, string username, params PrivateKeyFile[] keyFiles) : this(host, DefaultPort, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty, keyFiles) { - } /// @@ -46,7 +47,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, params I } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// The port. @@ -61,7 +62,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// The port. @@ -77,7 +78,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// Connection username. @@ -91,7 +92,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// Connection username. @@ -106,7 +107,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// Connection username. @@ -122,7 +123,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Connection host. /// The port. @@ -139,27 +140,25 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp KeyFiles = new Collection(keyFiles); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -168,8 +167,7 @@ protected virtual void Dispose(bool disposing) { foreach (var authenticationMethod in AuthenticationMethods) { - var disposable = authenticationMethod as IDisposable; - if (disposable != null) + if (authenticationMethod is IDisposable disposable) { disposable.Dispose(); } @@ -181,17 +179,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~PrivateKeyConnectionInfo() { - // Do not re-create Dispose clean-up code here. - // Calling Dispose(false) is optimal in terms of - // readability and maintainability. - Dispose(false); + Dispose(disposing: false); } - - #endregion } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 5ec7f248d..4da514384 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -1,17 +1,17 @@ 锘縰sing System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Text; using System.Text.RegularExpressions; + using Renci.SshNet.Abstractions; -using Renci.SshNet.Security; using Renci.SshNet.Common; -using System.Globalization; +using Renci.SshNet.Security; +using Renci.SshNet.Security.Cryptography; using Renci.SshNet.Security.Cryptography.Ciphers; using Renci.SshNet.Security.Cryptography.Ciphers.Modes; using Renci.SshNet.Security.Cryptography.Ciphers.Paddings; -using System.Diagnostics.CodeAnalysis; -using Renci.SshNet.Security.Cryptography; namespace Renci.SshNet { @@ -68,8 +68,8 @@ public class PrivateKeyFile : IPrivateKeySource, IDisposable private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?[A-Z0-9-]+),(?[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?([a-zA-Z0-9/+=]{1,80}\r?\n)+)-+ *END \k PRIVATE KEY *-+", RegexOptions.Compiled | RegexOptions.Multiline); - private Key _key; + private bool _isDisposed; /// /// Gets the host key. @@ -91,7 +91,7 @@ public PrivateKeyFile(Key key) /// The private key. public PrivateKeyFile(Stream privateKey) { - Open(privateKey, null); + Open(privateKey, passPhrase: null); } /// @@ -99,9 +99,11 @@ public PrivateKeyFile(Stream privateKey) /// /// Name of the file. /// is null or empty. - /// This method calls internally, this method does not catch exceptions from . + /// + /// This method calls internally, this method does not catch exceptions from . + /// public PrivateKeyFile(string fileName) - : this(fileName, null) + : this(fileName, passPhrase: null) { } @@ -111,11 +113,15 @@ public PrivateKeyFile(string fileName) /// Name of the file. /// The pass phrase. /// is null or empty, or is null. - /// This method calls internally, this method does not catch exceptions from . + /// + /// This method calls internally, this method does not catch exceptions from . + /// public PrivateKeyFile(string fileName, string passPhrase) { if (string.IsNullOrEmpty(fileName)) - throw new ArgumentNullException("fileName"); + { + throw new ArgumentNullException(nameof(fileName)); + } using (var keyFile = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { @@ -139,11 +145,12 @@ public PrivateKeyFile(Stream privateKey, string passPhrase) /// /// The private key. /// The pass phrase. - [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "this._key disposed in Dispose(bool) method.")] private void Open(Stream privateKey, string passPhrase) { if (privateKey == null) - throw new ArgumentNullException("privateKey"); + { + throw new ArgumentNullException(nameof(privateKey)); + } Match privateKeyMatch; @@ -170,11 +177,15 @@ private void Open(Stream privateKey, string passPhrase) if (!string.IsNullOrEmpty(cipherName) && !string.IsNullOrEmpty(salt)) { if (string.IsNullOrEmpty(passPhrase)) + { throw new SshPassPhraseNullOrEmptyException("Private key is encrypted but passphrase is empty."); + } var binarySalt = new byte[salt.Length / 2]; for (var i = 0; i < binarySalt.Length; i++) + { binarySalt[i] = Convert.ToByte(salt.Substring(i * 2, 2), 16); + } CipherInfo cipher; switch (cipherName) @@ -234,7 +245,7 @@ private void Open(Stream privateKey, string passPhrase) throw new SshException("Invalid SSH2 private key."); } - reader.ReadUInt32(); // Read total bytes length including magic number + _ = reader.ReadUInt32(); // Read total bytes length including magic number var keyType = reader.ReadString(SshData.Ascii); var ssh2CipherName = reader.ReadString(SshData.Ascii); var blobSize = (int)reader.ReadUInt32(); @@ -258,23 +269,25 @@ private void Open(Stream privateKey, string passPhrase) throw new SshException(string.Format("Cipher method '{0}' is not supported.", cipherName)); } - // TODO: Create two specific data types to avoid using SshDataReader class + // TODO: Create two specific data types to avoid using SshDataReader class reader = new SshDataReader(keyData); var decryptedLength = reader.ReadUInt32(); if (decryptedLength > blobSize - 4) + { throw new SshException("Invalid passphrase."); + } if (keyType == "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}") { - var exponent = reader.ReadBigIntWithBits();//e - var d = reader.ReadBigIntWithBits();//d - var modulus = reader.ReadBigIntWithBits();//n - var inverseQ = reader.ReadBigIntWithBits();//u - var q = reader.ReadBigIntWithBits();//p - var p = reader.ReadBigIntWithBits();//q + var exponent = reader.ReadBigIntWithBits(); // e + var d = reader.ReadBigIntWithBits(); // d + var modulus = reader.ReadBigIntWithBits(); // n + var inverseQ = reader.ReadBigIntWithBits(); // u + var q = reader.ReadBigIntWithBits(); // p + var p = reader.ReadBigIntWithBits(); // q _key = new RsaKey(modulus, exponent, d, p, q, inverseQ); HostKey = new KeyHostAlgorithm("ssh-rsa", _key); } @@ -337,13 +350,19 @@ private static byte[] GetCipherKey(string passphrase, int length) private static byte[] DecryptKey(CipherInfo cipherInfo, byte[] cipherData, string passPhrase, byte[] binarySalt) { if (cipherInfo == null) - throw new ArgumentNullException("cipherInfo"); + { + throw new ArgumentNullException(nameof(cipherInfo)); + } if (cipherData == null) - throw new ArgumentNullException("cipherData"); + { + throw new ArgumentNullException(nameof(cipherData)); + } if (binarySalt == null) - throw new ArgumentNullException("binarySalt"); + { + throw new ArgumentNullException(nameof(binarySalt)); + } var cipherKey = new List(); @@ -351,7 +370,7 @@ private static byte[] DecryptKey(CipherInfo cipherInfo, byte[] cipherData, strin { var passwordBytes = Encoding.UTF8.GetBytes(passPhrase); - // Use 8 bytes binary salt + // Use 8 bytes binary salt var initVector = passwordBytes.Concat(binarySalt.Take(8)); var hash = md5.ComputeHash(initVector); @@ -376,12 +395,14 @@ private static byte[] DecryptKey(CipherInfo cipherInfo, byte[] cipherData, strin /// /// the key file data (i.e. base64 encoded data between the header/footer) /// passphrase or null if there isn't one - /// + /// + /// The OpenSSH V1 key. + /// private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) { var keyReader = new SshDataReader(keyFileData); - //check magic header + // check magic header var authMagic = Encoding.UTF8.GetBytes("openssh-key-v1\0"); var keyHeaderBytes = keyReader.ReadBytes(authMagic.Length); if (!authMagic.IsEqualTo(keyHeaderBytes)) @@ -389,16 +410,16 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) throw new SshException("This openssh key does not contain the 'openssh-key-v1' format magic header"); } - //cipher will be "aes256-cbc" if using a passphrase, "none" otherwise + // cipher will be "aes256-cbc" if using a passphrase, "none" otherwise var cipherName = keyReader.ReadString(Encoding.UTF8); - //key derivation function (kdf): bcrypt or nothing + // key derivation function (kdf): bcrypt or nothing var kdfName = keyReader.ReadString(Encoding.UTF8); - //kdf options length: 24 if passphrase, 0 if no passphrase + // kdf options length: 24 if passphrase, 0 if no passphrase var kdfOptionsLen = (int)keyReader.ReadUInt32(); byte[] salt = null; - int rounds = 0; + var rounds = 0; if (kdfOptionsLen > 0) { var saltLength = (int)keyReader.ReadUInt32(); @@ -406,21 +427,21 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) rounds = (int)keyReader.ReadUInt32(); } - //number of public keys, only supporting 1 for now + // number of public keys, only supporting 1 for now var numberOfPublicKeys = (int)keyReader.ReadUInt32(); if (numberOfPublicKeys != 1) { throw new SshException("At this time only one public key in the openssh key is supported."); } - //read public key in ssh-format, but we dont need it - keyReader.ReadString(Encoding.UTF8); + // read public key in ssh-format, but we dont need it + _ = keyReader.ReadString(Encoding.UTF8); - //possibly encrypted private key + // possibly encrypted private key var privateKeyLength = (int)keyReader.ReadUInt32(); var privateKeyBytes = keyReader.ReadBytes(privateKeyLength); - //decrypt private key if necessary + // decrypt private key if necessary if (cipherName != "none") { if (string.IsNullOrEmpty(passPhrase)) @@ -433,14 +454,14 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) throw new SshException("kdf " + kdfName + " is not supported for openssh key file"); } - //inspired by the SSHj library (https://github.com/hierynomus/sshj) - //apply the kdf to derive a key and iv from the passphrase + // inspired by the SSHj library (https://github.com/hierynomus/sshj) + // apply the kdf to derive a key and iv from the passphrase var passPhraseBytes = Encoding.UTF8.GetBytes(passPhrase); - byte[] keyiv = new byte[48]; + var keyiv = new byte[48]; new BCrypt().Pbkdf(passPhraseBytes, salt, rounds, keyiv); - byte[] key = new byte[32]; + var key = new byte[32]; Array.Copy(keyiv, 0, key, 0, 32); - byte[] iv = new byte[16]; + var iv = new byte[16]; Array.Copy(keyiv, 32, iv, 0, 16); AesCipher cipher; @@ -459,25 +480,27 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) privateKeyBytes = cipher.Decrypt(privateKeyBytes); } - //validate private key length + // validate private key length privateKeyLength = privateKeyBytes.Length; if (privateKeyLength % 8 != 0) { throw new SshException("The private key section must be a multiple of the block size (8)"); } - //now parse the data we called the private key, it actually contains the public key again - //so we need to parse through it to get the private key bytes, plus there's some - //validation we need to do. + // now parse the data we called the private key, it actually contains the public key again + // so we need to parse through it to get the private key bytes, plus there's some + // validation we need to do. var privateKeyReader = new SshDataReader(privateKeyBytes); - //check ints should match, they wouldn't match for example if the wrong passphrase was supplied - int checkInt1 = (int)privateKeyReader.ReadUInt32(); - int checkInt2 = (int)privateKeyReader.ReadUInt32(); + // check ints should match, they wouldn't match for example if the wrong passphrase was supplied + var checkInt1 = (int) privateKeyReader.ReadUInt32(); + var checkInt2 = (int) privateKeyReader.ReadUInt32(); if (checkInt1 != checkInt2) + { throw new SshException("The random check bytes of the OpenSSH key do not match (" + checkInt1 + " <->" + checkInt2 + ")."); + } - //key type + // key type var keyType = privateKeyReader.ReadString(Encoding.UTF8); Key parsedKey; @@ -486,9 +509,10 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) switch (keyType) { case "ssh-ed25519": - //public key + // public key publicKey = privateKeyReader.ReadBignum2(); - //private key + + // private key unencryptedPrivateKey = privateKeyReader.ReadBignum2(); parsedKey = new ED25519Key(publicKey.Reverse(), unencryptedPrivateKey); break; @@ -496,21 +520,23 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) case "ecdsa-sha2-nistp384": case "ecdsa-sha2-nistp521": // curve - int len = (int)privateKeyReader.ReadUInt32(); + var len = (int) privateKeyReader.ReadUInt32(); var curve = Encoding.ASCII.GetString(privateKeyReader.ReadBytes(len)); - //public key + + // public key publicKey = privateKeyReader.ReadBignum2(); - //private key + + // private key unencryptedPrivateKey = privateKeyReader.ReadBignum2(); parsedKey = new EcdsaKey(curve, publicKey, unencryptedPrivateKey.TrimLeadingZeros()); break; case "ssh-rsa": - var modulus = privateKeyReader.ReadBignum(); //n - var exponent = privateKeyReader.ReadBignum(); //e - var d = privateKeyReader.ReadBignum(); //d + var modulus = privateKeyReader.ReadBignum(); // n + var exponent = privateKeyReader.ReadBignum(); // e + var d = privateKeyReader.ReadBignum(); // d var inverseQ = privateKeyReader.ReadBignum(); // iqmp - var p = privateKeyReader.ReadBignum(); //p - var q = privateKeyReader.ReadBignum(); //q + var p = privateKeyReader.ReadBignum(); // p + var q = privateKeyReader.ReadBignum(); // q parsedKey = new RsaKey(modulus, exponent, d, p, q, inverseQ); break; default: @@ -519,12 +545,12 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) parsedKey.Comment = privateKeyReader.ReadString(Encoding.UTF8); - //The list of privatekey/comment pairs is padded with the bytes 1, 2, 3, ... - //until the total length is a multiple of the cipher block size. + // The list of privatekey/comment pairs is padded with the bytes 1, 2, 3, ... + // until the total length is a multiple of the cipher block size. var padding = privateKeyReader.ReadBytes(); - for (int i = 0; i < padding.Length; i++) + for (var i = 0; i < padding.Length; i++) { - if ((int)padding[i] != i + 1) + if ((int) padding[i] != i + 1) { throw new SshException("Padding of openssh key format contained wrong byte at position: " + i); } @@ -533,27 +559,25 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) return parsedKey; } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -569,16 +593,13 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~PrivateKeyFile() { - Dispose(false); + Dispose(disposing: false); } - #endregion - private class SshDataReader : SshData { public SshDataReader(byte[] data) @@ -643,4 +664,4 @@ protected override void SaveData() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Properties/AssemblyInfo.cs b/src/Renci.SshNet/Properties/AssemblyInfo.cs index 22e4125ce..cde7dcdeb 100644 --- a/src/Renci.SshNet/Properties/AssemblyInfo.cs +++ b/src/Renci.SshNet/Properties/AssemblyInfo.cs @@ -1,6 +1,6 @@ 锘縰sing System.Reflection; -using System.Runtime.InteropServices; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; [assembly: AssemblyTitle("SSH.NET")] [assembly: Guid("ad816c5e-6f13-4589-9f3e-59523f8b77a4")] diff --git a/src/Renci.SshNet/RemotePathDoubleQuoteTransformation.cs b/src/Renci.SshNet/RemotePathDoubleQuoteTransformation.cs index 70af535a2..e4f5496f2 100644 --- a/src/Renci.SshNet/RemotePathDoubleQuoteTransformation.cs +++ b/src/Renci.SshNet/RemotePathDoubleQuoteTransformation.cs @@ -52,19 +52,24 @@ public string Transform(string path) { if (path == null) { - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(path)); } var transformed = new StringBuilder(path.Length); - transformed.Append('"'); + _ = transformed.Append('"'); + foreach (var c in path) { if (c == '"') - transformed.Append('\\'); - transformed.Append(c); + { + _ = transformed.Append('\\'); + } + + _ = transformed.Append(c); } - transformed.Append('"'); + + _ = transformed.Append('"'); return transformed.ToString(); } diff --git a/src/Renci.SshNet/RemotePathNoneTransformation.cs b/src/Renci.SshNet/RemotePathNoneTransformation.cs index ef51531d3..f7bfbab6a 100644 --- a/src/Renci.SshNet/RemotePathNoneTransformation.cs +++ b/src/Renci.SshNet/RemotePathNoneTransformation.cs @@ -23,7 +23,7 @@ public string Transform(string path) { if (path == null) { - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(path)); } return path; diff --git a/src/Renci.SshNet/RemotePathShellQuoteTransformation.cs b/src/Renci.SshNet/RemotePathShellQuoteTransformation.cs index 5093cafd8..53424286c 100644 --- a/src/Renci.SshNet/RemotePathShellQuoteTransformation.cs +++ b/src/Renci.SshNet/RemotePathShellQuoteTransformation.cs @@ -82,7 +82,7 @@ public string Transform(string path) { if (path == null) { - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(path)); } // result is at least value and (likely) leading/trailing single-quotes @@ -99,42 +99,52 @@ public string Transform(string path) { case ShellQuoteState.Unquoted: // Start quoted string - sb.Append('"'); + _ = sb.Append('"'); break; case ShellQuoteState.Quoted: // Continue quoted string break; case ShellQuoteState.SingleQuoted: // Close single-quoted string - sb.Append('\''); + _ = sb.Append('\''); + // Start quoted string - sb.Append('"'); + _ = sb.Append('"'); + break; + default: break; } + state = ShellQuoteState.Quoted; break; case '!': - // In C-Shell, an exclamatation point can only be protected from shell interpretation - // when escaped by a backslash - // Source: - // https://earthsci.stanford.edu/computing/unix/shell/specialchars.php + /* + * In C-Shell, an exclamatation point can only be protected from shell interpretation + * when escaped by a backslash. + * + * Source: + * https://earthsci.stanford.edu/computing/unix/shell/specialchars.php + */ switch (state) { case ShellQuoteState.Unquoted: - sb.Append('\\'); + _ = sb.Append('\\'); break; case ShellQuoteState.Quoted: // Close quoted string - sb.Append('"'); - sb.Append('\\'); + _ = sb.Append('"'); + _ = sb.Append('\\'); break; case ShellQuoteState.SingleQuoted: // Close single quoted string - sb.Append('\''); - sb.Append('\\'); + _ = sb.Append('\''); + _ = sb.Append('\\'); + break; + default: break; } + state = ShellQuoteState.Unquoted; break; default: @@ -142,23 +152,27 @@ public string Transform(string path) { case ShellQuoteState.Unquoted: // Start single-quoted string - sb.Append('\''); + _ = sb.Append('\''); break; case ShellQuoteState.Quoted: // Close quoted string - sb.Append('"'); + _ = sb.Append('"'); + // Start single-quoted string - sb.Append('\''); + _ = sb.Append('\''); break; case ShellQuoteState.SingleQuoted: // Continue single-quoted string break; + default: + break; } + state = ShellQuoteState.SingleQuoted; break; } - sb.Append(c); + _ = sb.Append(c); } switch (state) @@ -167,17 +181,19 @@ public string Transform(string path) break; case ShellQuoteState.Quoted: // Close quoted string - sb.Append('"'); + _ = sb.Append('"'); break; case ShellQuoteState.SingleQuoted: // Close single-quoted string - sb.Append('\''); + _ = sb.Append('\''); + break; + default: break; } if (sb.Length == 0) { - sb.Append("''"); + _ = sb.Append("''"); } return sb.ToString(); diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index 21b0128a8..9fcd62fd3 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -1,12 +1,7 @@ 锘 - true - true false Renci.SshNet - ../Renci.SshNet.snk - 7.3 - true net462;netstandard2.0;net6.0;net7.0 diff --git a/src/Renci.SshNet/ScpClient.NET.cs b/src/Renci.SshNet/ScpClient.NET.cs index cb23cb695..8ca396e7d 100644 --- a/src/Renci.SshNet/ScpClient.NET.cs +++ b/src/Renci.SshNet/ScpClient.NET.cs @@ -1,9 +1,10 @@ 锘縰sing System; -using Renci.SshNet.Channels; using System.IO; -using Renci.SshNet.Common; using System.Text.RegularExpressions; +using Renci.SshNet.Channels; +using Renci.SshNet.Common; + namespace Renci.SshNet { /// @@ -27,7 +28,9 @@ public partial class ScpClient public void Upload(FileInfo fileInfo, string path) { if (fileInfo == null) - throw new ArgumentNullException("fileInfo"); + { + throw new ArgumentNullException(nameof(fileInfo)); + } var posixPath = PosixPath.CreateAbsoluteOrRelativeFilePath(path); @@ -43,6 +46,7 @@ public void Upload(FileInfo fileInfo, string path) { throw SecureExecutionRequestRejectedException(); } + CheckReturnCode(input); using (var source = fileInfo.OpenRead()) @@ -67,11 +71,19 @@ public void Upload(FileInfo fileInfo, string path) public void Upload(DirectoryInfo directoryInfo, string path) { if (directoryInfo == null) - throw new ArgumentNullException("directoryInfo"); + { + throw new ArgumentNullException(nameof(directoryInfo)); + } + if (path == null) - throw new ArgumentNullException("path"); + { + throw new ArgumentNullException(nameof(path)); + } + if (path.Length == 0) - throw new ArgumentException("The path cannot be a zero-length string.", "path"); + { + throw new ArgumentException("The path cannot be a zero-length string.", nameof(path)); + } using (var input = ServiceFactory.CreatePipeStream()) using (var channel = Session.CreateChannelSession()) @@ -107,9 +119,14 @@ public void Upload(DirectoryInfo directoryInfo, string path) public void Download(string filename, FileInfo fileInfo) { if (string.IsNullOrEmpty(filename)) + { throw new ArgumentException("filename"); + } + if (fileInfo == null) - throw new ArgumentNullException("fileInfo"); + { + throw new ArgumentNullException(nameof(fileInfo)); + } using (var input = ServiceFactory.CreatePipeStream()) using (var channel = Session.CreateChannelSession()) @@ -122,6 +139,7 @@ public void Download(string filename, FileInfo fileInfo) { throw SecureExecutionRequestRejectedException(); } + // Send reply SendSuccessConfirmation(channel); @@ -141,9 +159,14 @@ public void Download(string filename, FileInfo fileInfo) public void Download(string directoryName, DirectoryInfo directoryInfo) { if (string.IsNullOrEmpty(directoryName)) + { throw new ArgumentException("directoryName"); + } + if (directoryInfo == null) - throw new ArgumentNullException("directoryInfo"); + { + throw new ArgumentNullException(nameof(directoryInfo)); + } using (var input = ServiceFactory.CreatePipeStream()) using (var channel = Session.CreateChannelSession()) @@ -156,6 +179,7 @@ public void Download(string directoryName, DirectoryInfo directoryInfo) { throw SecureExecutionRequestRejectedException(); } + // Send reply SendSuccessConfirmation(channel); @@ -187,7 +211,7 @@ private void UploadTimes(IChannelSession channel, Stream input, FileSystemInfo f /// The directory to upload. private void UploadDirectoryContent(IChannelSession channel, Stream input, DirectoryInfo directoryInfo) { - // Upload files + // Upload files var files = directoryInfo.GetFiles(); foreach (var file in files) { @@ -199,7 +223,7 @@ private void UploadDirectoryContent(IChannelSession channel, Stream input, Direc } } - // Upload directories + // Upload directories var directories = directoryInfo.GetDirectories(); foreach (var directory in directories) { @@ -237,23 +261,26 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI if (message == "E") { - SendSuccessConfirmation(channel); // Send reply + SendSuccessConfirmation(channel); // Send reply directoryCounter--; currentDirectoryFullName = new DirectoryInfo(currentDirectoryFullName).Parent.FullName; if (directoryCounter == 0) + { break; + } + continue; } var match = DirectoryInfoRe.Match(message); if (match.Success) { - SendSuccessConfirmation(channel); // Send reply + SendSuccessConfirmation(channel); // Send reply - // Read directory + // Read directory var filename = match.Result("${filename}"); DirectoryInfo newDirectoryInfo; @@ -265,7 +292,7 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI } else { - // Don't create directory for first level + // Don't create directory for first level newDirectoryInfo = fileSystemInfo as DirectoryInfo; } @@ -278,16 +305,16 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI match = FileInfoRe.Match(message); if (match.Success) { - // Read file + // Read file SendSuccessConfirmation(channel); // Send reply var length = long.Parse(match.Result("${length}")); var fileName = match.Result("${filename}"); - var fileInfo = fileSystemInfo as FileInfo; - - if (fileInfo == null) + if (fileSystemInfo is not FileInfo fileInfo) + { fileInfo = new FileInfo(Path.Combine(currentDirectoryFullName, fileName)); + } using (var output = fileInfo.OpenWrite()) { @@ -298,14 +325,17 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI fileInfo.LastWriteTime = modifiedTime; if (directoryCounter == 0) + { break; + } + continue; } match = TimestampRe.Match(message); if (match.Success) { - // Read timestamp + // Read timestamp SendSuccessConfirmation(channel); // Send reply var mtime = long.Parse(match.Result("${mtime}")); @@ -320,39 +350,5 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI SendErrorConfirmation(channel, string.Format("\"{0}\" is not valid protocol message.", message)); } } - - /// - /// Return a value indicating whether the specified path is a valid SCP file path. - /// - /// The path to verify. - /// - /// if is a valid SCP file path; otherwise, . - /// - /// - /// To match OpenSSH behavior (introduced as a result of CVE-2018-20685), a file path is considered - /// invalid in any of the following conditions: - /// - /// - /// is a zero-length string. - /// - /// - /// is ".". - /// - /// - /// is "..". - /// - /// - /// contains a forward slash (/). - /// - /// - /// - private static bool IsValidScpFilePath(string path) - { - return path != null && - path.Length != 0 && - path != "." && - path != ".." && - path.IndexOf('/') == -1; - } } } diff --git a/src/Renci.SshNet/ScpClient.cs b/src/Renci.SshNet/ScpClient.cs index d8ad55692..7907bfe7d 100644 --- a/src/Renci.SshNet/ScpClient.cs +++ b/src/Renci.SshNet/ScpClient.cs @@ -1,11 +1,13 @@ 锘縰sing System; -using Renci.SshNet.Channels; -using System.IO; -using Renci.SshNet.Common; -using System.Text.RegularExpressions; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; using System.Net; -using System.Collections.Generic; +using System.Text.RegularExpressions; + +using Renci.SshNet.Channels; +using Renci.SshNet.Common; namespace Renci.SshNet { @@ -29,8 +31,9 @@ namespace Renci.SshNet /// public partial class ScpClient : BaseClient { + private const string Message = "filename"; private static readonly Regex FileInfoRe = new Regex(@"C(?\d{4}) (?\d+) (?.+)"); - private static readonly byte[] SuccessConfirmationCode = {0}; + private static readonly byte[] SuccessConfirmationCode = { 0 }; private static readonly byte[] ErrorConfirmationCode = { 1 }; private IRemotePathTransformation _remotePathTransformation; @@ -56,7 +59,7 @@ public partial class ScpClient : BaseClient /// Gets or sets the transformation to apply to remote paths. /// /// - /// The transformation to apply to remote paths. The default is . + /// The transformation to apply to remote paths. The default is . /// /// is null. /// @@ -75,7 +78,10 @@ public IRemotePathTransformation RemotePathTransformation set { if (value == null) - throw new ArgumentNullException("value"); + { + throw new ArgumentNullException(nameof(value)); + } + _remotePathTransformation = value; } } @@ -90,15 +96,13 @@ public IRemotePathTransformation RemotePathTransformation /// public event EventHandler Uploading; - #region Constructors - /// /// Initializes a new instance of the class. /// /// The connection info. /// is null. public ScpClient(ConnectionInfo connectionInfo) - : this(connectionInfo, false) + : this(connectionInfo, ownsConnectionInfo: false) { } @@ -114,7 +118,7 @@ public ScpClient(ConnectionInfo connectionInfo) /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] public ScpClient(string host, int port, string username, string password) - : this(new PasswordConnectionInfo(host, port, username, password), true) + : this(new PasswordConnectionInfo(host, port, username, password), ownsConnectionInfo: true) { } @@ -143,7 +147,7 @@ public ScpClient(string host, string username, string password) /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] public ScpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) - : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) + : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -195,8 +199,6 @@ internal ScpClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServ _remotePathTransformation = serviceFactory.CreateRemotePathDoubleQuoteTransformation(); } - #endregion - /// /// Uploads the specified stream to the remote host. /// @@ -222,6 +224,7 @@ public void Upload(Stream source, string path) { throw SecureExecutionRequestRejectedException(); } + CheckReturnCode(input); UploadFileModeAndName(channel, input, source.Length, posixPath.File); @@ -241,10 +244,14 @@ public void Upload(Stream source, string path) public void Download(string filename, Stream destination) { if (filename.IsNullOrWhiteSpace()) - throw new ArgumentException("filename"); + { + throw new ArgumentException(Message); + } if (destination == null) - throw new ArgumentNullException("destination"); + { + throw new ArgumentNullException(nameof(destination)); + } using (var input = ServiceFactory.CreatePipeStream()) using (var channel = Session.CreateChannelSession()) @@ -252,22 +259,23 @@ public void Download(string filename, Stream destination) channel.DataReceived += (sender, e) => input.Write(e.Data, 0, e.Data.Length); channel.Open(); - // Send channel command request - if (!channel.SendExecRequest(string.Format("scp -f {0}", _remotePathTransformation.Transform(filename)))) + // Send channel command request + if (!channel.SendExecRequest(string.Concat("scp -f ", _remotePathTransformation.Transform(filename)))) { throw SecureExecutionRequestRejectedException(); } - SendSuccessConfirmation(channel); // Send reply + + SendSuccessConfirmation(channel); // Send reply var message = ReadString(input); var match = FileInfoRe.Match(message); if (match.Success) { - // Read file + // Read file SendSuccessConfirmation(channel); // Send reply - var length = long.Parse(match.Result("${length}")); + var length = long.Parse(match.Result("${length}"), CultureInfo.InvariantCulture); var fileName = match.Result("${filename}"); InternalDownload(channel, input, destination, fileName, length); @@ -364,18 +372,12 @@ private void InternalDownload(IChannel channel, Stream input, Stream output, str private void RaiseDownloadingEvent(string filename, long size, long downloaded) { - if (Downloading != null) - { - Downloading(this, new ScpDownloadEventArgs(filename, size, downloaded)); - } + Downloading?.Invoke(this, new ScpDownloadEventArgs(filename, size, downloaded)); } private void RaiseUploadingEvent(string filename, long size, long uploaded) { - if (Uploading != null) - { - Uploading(this, new ScpUploadEventArgs(filename, size, uploaded)); - } + Uploading?.Invoke(this, new ScpUploadEventArgs(filename, size, uploaded)); } private static void SendSuccessConfirmation(IChannel channel) @@ -423,8 +425,12 @@ private static void SendData(IChannel channel, byte[] buffer) private static int ReadByte(Stream stream) { var b = stream.ReadByte(); + if (b == -1) + { throw new SshException("Stream has been closed."); + } + return b; } @@ -442,7 +448,7 @@ private string ReadString(Stream stream) var buffer = new List(); var b = ReadByte(stream); - if (b == 1 || b == 2) + if (b is 1 or 2) { hasError = true; b = ReadByte(stream); @@ -457,7 +463,10 @@ private string ReadString(Stream stream) var readBytes = buffer.ToArray(); if (hasError) + { throw new ScpException(ConnectionInfo.Encoding.GetString(readBytes, 0, readBytes.Length)); + } + return ConnectionInfo.Encoding.GetString(readBytes, 0, readBytes.Length); } @@ -466,4 +475,4 @@ private static SshException SecureExecutionRequestRejectedException() throw new SshException("Secure copy execution request was rejected by the server. Please consult the server logs."); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/.editorconfig b/src/Renci.SshNet/Security/BouncyCastle/.editorconfig new file mode 100644 index 000000000..265666760 --- /dev/null +++ b/src/Renci.SshNet/Security/BouncyCastle/.editorconfig @@ -0,0 +1,7 @@ +锘縖*.cs] + +generated_code = true + +# IDE0005: Remove unnecessary using directives +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0005 +dotnet_diagnostic.IDE0005.severity = none diff --git a/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/IRandomGenerator.cs b/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/IRandomGenerator.cs index 5bb0c3540..57e49ea71 100644 --- a/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/IRandomGenerator.cs +++ b/src/Renci.SshNet/Security/BouncyCastle/crypto/prng/IRandomGenerator.cs @@ -23,4 +23,4 @@ internal interface IRandomGenerator /// Length of segment to fill. void NextBytes(byte[] bytes, int start, int len); } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/ec/endo/GlvEndomorphism.cs b/src/Renci.SshNet/Security/BouncyCastle/math/ec/endo/GlvEndomorphism.cs index 143a369b3..acfae5264 100644 --- a/src/Renci.SshNet/Security/BouncyCastle/math/ec/endo/GlvEndomorphism.cs +++ b/src/Renci.SshNet/Security/BouncyCastle/math/ec/endo/GlvEndomorphism.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Security.Org.BouncyCastle.Math.EC.Endo { internal interface GlvEndomorphism - : ECEndomorphism + : ECEndomorphism { BigInteger[] DecomposeScalar(BigInteger k); } diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/.editorconfig b/src/Renci.SshNet/Security/Chaos.NaCl/.editorconfig new file mode 100644 index 000000000..265666760 --- /dev/null +++ b/src/Renci.SshNet/Security/Chaos.NaCl/.editorconfig @@ -0,0 +1,7 @@ +锘縖*.cs] + +generated_code = true + +# IDE0005: Remove unnecessary using directives +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0005 +dotnet_diagnostic.IDE0005.severity = none diff --git a/src/Renci.SshNet/Security/Cryptography/.editorconfig b/src/Renci.SshNet/Security/Cryptography/.editorconfig new file mode 100644 index 000000000..7e36b6e59 --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/.editorconfig @@ -0,0 +1,12 @@ +锘縖Bcrypt.cs] + +generated_code = true + +# IDE0005: Remove unnecessary using directives +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0005 +dotnet_diagnostic.IDE0005.severity = none + +# IDE0007: Use var instead of explicit type +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0007-ide0008 +# +dotnet_diagnostic.IDE0007.severity = none \ No newline at end of file diff --git a/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs b/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs index 18cf81cb6..17e14c5dc 100644 --- a/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs @@ -135,6 +135,7 @@ public override byte[] Decrypt(byte[] data, int offset, int length) { throw new ArgumentException("data"); } + data = _padding.Pad(_blockSize, data, offset, length); offset = 0; length = data.Length; diff --git a/src/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs index 752f97014..7312a6292 100644 --- a/src/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs @@ -19,7 +19,9 @@ public abstract class CipherDigitalSignature : DigitalSignature protected CipherDigitalSignature(ObjectIdentifier oid, AsymmetricCipher cipher) { if (cipher == null) - throw new ArgumentNullException("cipher"); + { + throw new ArgumentNullException(nameof(cipher)); + } _cipher = cipher; _oid = oid; @@ -50,10 +52,10 @@ public override bool Verify(byte[] input, byte[] signature) /// public override byte[] Sign(byte[] input) { - // Calculate hash value + // Calculate hash value var hashData = Hash(input); - // Calculate DER string + // Calculate DER string var derEncodedHash = DerEncode(hashData); return _cipher.Encrypt(derEncodedHash).TrimLeadingZeros(); @@ -70,7 +72,9 @@ public override byte[] Sign(byte[] input) /// Encodes hash using DER. /// /// The hash data. - /// DER Encoded byte array + /// + /// DER Encoded byte array. + /// protected byte[] DerEncode(byte[] hashData) { var alg = new DerData(); diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs index b42258624..9fb8d0a25 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs @@ -569,8 +569,10 @@ public AesCipher(byte[] key, CipherMode mode, CipherPadding padding) { var keySize = key.Length * 8; - if (!(keySize == 256 || keySize == 192 || keySize == 128)) + if (keySize is not (256 or 192 or 128)) + { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "KeySize '{0}' is not valid for this algorithm.", keySize)); + } } /// @@ -589,10 +591,14 @@ public AesCipher(byte[] key, CipherMode mode, CipherPadding padding) public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer == null) - throw new ArgumentNullException("inputBuffer"); + { + throw new ArgumentNullException(nameof(inputBuffer)); + } if (outputBuffer == null) - throw new ArgumentNullException("outputBuffer"); + { + throw new ArgumentNullException(nameof(outputBuffer)); + } if ((inputOffset + (32 / 2)) > inputBuffer.Length) { @@ -604,10 +610,7 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC throw new IndexOutOfRangeException("output buffer too short"); } - if (_encryptionKey == null) - { - _encryptionKey = GenerateWorkingKey(true, Key); - } + _encryptionKey ??= GenerateWorkingKey(true, Key); UnPackBlock(inputBuffer, inputOffset); @@ -634,10 +637,14 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer == null) - throw new ArgumentNullException("inputBuffer"); + { + throw new ArgumentNullException(nameof(inputBuffer)); + } if (outputBuffer == null) - throw new ArgumentNullException("outputBuffer"); + { + throw new ArgumentNullException(nameof(outputBuffer)); + } if ((inputOffset + (32 / 2)) > inputBuffer.Length) { @@ -649,10 +656,7 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC throw new IndexOutOfRangeException("output buffer too short"); } - if (_decryptionKey == null) - { - _decryptionKey = GenerateWorkingKey(false, Key); - } + _decryptionKey ??= GenerateWorkingKey(false, Key); UnPackBlock(inputBuffer, inputOffset); @@ -668,7 +672,9 @@ private uint[] GenerateWorkingKey(bool isEncryption, byte[] key) int KC = key.Length / 4; // key length in words if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.Length)) + { throw new ArgumentException("Key length not 128/192/256 bits."); + } _rounds = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes uint[] W = new uint[(_rounds + 1) * 4]; // 4 words in a block @@ -679,7 +685,7 @@ private uint[] GenerateWorkingKey(bool isEncryption, byte[] key) int t = 0; - for (int i = 0; i < key.Length; t++) + for (var i = 0; i < key.Length; t++) { W[(t >> 2) * 4 + (t & 3)] = Pack.LittleEndianToUInt32(key, i); i += 4; diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs index 0707ce2e2..831b7f3cc 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs @@ -151,6 +151,7 @@ private int ProcessBytes(byte[] inputBuffer, int inputOffset, int inputCount, by // xor outputBuffer[i + outputOffset] = (byte)(inputBuffer[i + inputOffset] ^ _engineState[(_engineState[_x] + _engineState[_y]) & 0xff]); } + return inputCount; } @@ -161,10 +162,7 @@ private void SetKey(byte[] keyBytes) _x = 0; _y = 0; - if (_engineState == null) - { - _engineState = new byte[STATE_LENGTH]; - } + _engineState ??= new byte[STATE_LENGTH]; // reset the state of the engine for (var i = 0; i < STATE_LENGTH; i++) @@ -178,6 +176,7 @@ private void SetKey(byte[] keyBytes) for (var i = 0; i < STATE_LENGTH; i++) { i2 = ((keyBytes[i1] & 0xff) + _engineState[i] + i2) & 0xff; + // do the byte-swap inline var tmp = _engineState[i]; _engineState[i] = _engineState[i2]; diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs index d68d39886..2dfa7909e 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs @@ -348,7 +348,9 @@ public BlowfishCipher(byte[] key, CipherMode mode, CipherPadding padding) public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputCount != BlockSize) + { throw new ArgumentException("inputCount"); + } uint xl = Pack.BigEndianToUInt32(inputBuffer, inputOffset); uint xr = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4); @@ -451,6 +453,7 @@ private void SetKey(byte[] key) keyIndex = 0; } } + // XOR the newly created 32 bit chunk onto the P-array _p[i] ^= data; } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs index 1f6a2aa95..1fbe5bc4b 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs @@ -12,8 +12,6 @@ public class DesCipher : BlockCipher private int[] _decryptionKey; - #region Static tables - private static readonly short[] Bytebit = {128, 64, 32, 16, 8, 4, 2, 1}; private static readonly int[] Bigbyte = @@ -212,8 +210,6 @@ public class DesCipher : BlockCipher 0x00001040, 0x00040040, 0x10000000, 0x10041000 }; - #endregion - /// /// Initializes a new instance of the class. /// @@ -240,16 +236,17 @@ public DesCipher(byte[] key, CipherMode mode, CipherPadding padding) public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if ((inputOffset + BlockSize) > inputBuffer.Length) + { throw new IndexOutOfRangeException("input buffer too short"); + } if ((outputOffset + BlockSize) > outputBuffer.Length) - throw new IndexOutOfRangeException("output buffer too short"); - - if (_encryptionKey == null) { - _encryptionKey = GenerateWorkingKey(true, Key); + throw new IndexOutOfRangeException("output buffer too short"); } + _encryptionKey ??= GenerateWorkingKey(true, Key); + DesFunc(_encryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset); return BlockSize; @@ -269,16 +266,17 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if ((inputOffset + BlockSize) > inputBuffer.Length) + { throw new IndexOutOfRangeException("input buffer too short"); + } if ((outputOffset + BlockSize) > outputBuffer.Length) - throw new IndexOutOfRangeException("output buffer too short"); - - if (_decryptionKey == null) { - _decryptionKey = GenerateWorkingKey(false, Key); + throw new IndexOutOfRangeException("output buffer too short"); } + _decryptionKey ??= GenerateWorkingKey(false, Key); + DesFunc(_decryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset); return BlockSize; @@ -294,18 +292,18 @@ protected int[] GenerateWorkingKey(bool encrypting, byte[] key) { ValidateKey(); - int[] newKey = new int[32]; - bool[] pc1m = new bool[56]; - bool[] pcr = new bool[56]; + var newKey = new int[32]; + var pc1m = new bool[56]; + var pcr = new bool[56]; - for (int j = 0; j < 56; j++) + for (var j = 0; j < 56; j++) { int l = Pc1[j]; pc1m[j] = ((key[(uint)l >> 3] & Bytebit[l & 07]) != 0); } - for (int i = 0; i < 16; i++) + for (var i = 0; i < 16; i++) { int l, m; @@ -321,7 +319,7 @@ protected int[] GenerateWorkingKey(bool encrypting, byte[] key) var n = m + 1; newKey[m] = newKey[n] = 0; - for (int j = 0; j < 28; j++) + for (var j = 0; j < 28; j++) { l = j + Totrot[i]; if (l < 28) @@ -334,7 +332,7 @@ protected int[] GenerateWorkingKey(bool encrypting, byte[] key) } } - for (int j = 28; j < 56; j++) + for (var j = 28; j < 56; j++) { l = j + Totrot[i]; if (l < 56) @@ -347,7 +345,7 @@ protected int[] GenerateWorkingKey(bool encrypting, byte[] key) } } - for (int j = 0; j < 24; j++) + for (var j = 0; j < 24; j++) { if (pcr[Pc2[j]]) { @@ -364,7 +362,7 @@ protected int[] GenerateWorkingKey(bool encrypting, byte[] key) // // store the processed key // - for (int i = 0; i != 32; i += 2) + for (var i = 0; i != 32; i += 2) { var i1 = newKey[i]; var i2 = newKey[i + 1]; @@ -391,7 +389,9 @@ protected virtual void ValidateKey() var keySize = Key.Length * 8; if (keySize != 64) + { throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize)); + } } /// @@ -409,16 +409,16 @@ protected static void DesFunc(int[] wKey, byte[] input, int inOff, byte[] outByt var work = ((left >> 4) ^ right) & 0x0f0f0f0f; right ^= work; - left ^= (work << 4); + left ^= work << 4; work = ((left >> 16) ^ right) & 0x0000ffff; right ^= work; - left ^= (work << 16); + left ^= work << 16; work = ((right >> 2) ^ left) & 0x33333333; left ^= work; - right ^= (work << 2); + right ^= work << 2; work = ((right >> 8) ^ left) & 0x00ff00ff; left ^= work; - right ^= (work << 8); + right ^= work << 8; right = (right << 1) | (right >> 31); work = (left ^ right) & 0xaaaaaaaa; left ^= work; @@ -460,16 +460,16 @@ protected static void DesFunc(int[] wKey, byte[] input, int inOff, byte[] outByt left = (left << 31) | (left >> 1); work = ((left >> 8) ^ right) & 0x00ff00ff; right ^= work; - left ^= (work << 8); + left ^= work << 8; work = ((left >> 2) ^ right) & 0x33333333; right ^= work; - left ^= (work << 2); + left ^= work << 2; work = ((right >> 16) ^ left) & 0x0000ffff; left ^= work; - right ^= (work << 16); + right ^= work << 16; work = ((right >> 4) ^ left) & 0x0f0f0f0f; left ^= work; - right ^= (work << 4); + right ^= work << 4; Pack.UInt32ToBigEndian(right, outBytes, outOff); Pack.UInt32ToBigEndian(left, outBytes, outOff + 4); diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CbcCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CbcCipherMode.cs index c6ac2f0ab..de07141c3 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CbcCipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CbcCipherMode.cs @@ -31,20 +31,26 @@ public CbcCipherMode(byte[] iv) public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer.Length - inputOffset < _blockSize) + { throw new ArgumentException("Invalid input buffer"); + } if (outputBuffer.Length - outputOffset < _blockSize) + { throw new ArgumentException("Invalid output buffer"); + } if (inputCount != _blockSize) + { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); + } - for (int i = 0; i < _blockSize; i++) + for (var i = 0; i < _blockSize; i++) { IV[i] ^= inputBuffer[inputOffset + i]; } - Cipher.EncryptBlock(IV, 0, inputCount, outputBuffer, outputOffset); + _ = Cipher.EncryptBlock(IV, 0, inputCount, outputBuffer, outputOffset); Buffer.BlockCopy(outputBuffer, outputOffset, IV, 0, IV.Length); @@ -65,17 +71,23 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer.Length - inputOffset < _blockSize) + { throw new ArgumentException("Invalid input buffer"); + } if (outputBuffer.Length - outputOffset < _blockSize) + { throw new ArgumentException("Invalid output buffer"); + } if (inputCount != _blockSize) + { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); + } - Cipher.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); + _ = Cipher.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - for (int i = 0; i < _blockSize; i++) + for (var i = 0; i < _blockSize; i++) { outputBuffer[outputOffset + i] ^= IV[i]; } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CfbCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CfbCipherMode.cs index 3171e2bbc..ae889e875 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CfbCipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CfbCipherMode.cs @@ -34,17 +34,23 @@ public CfbCipherMode(byte[] iv) public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer.Length - inputOffset < _blockSize) + { throw new ArgumentException("Invalid input buffer"); + } if (outputBuffer.Length - outputOffset < _blockSize) + { throw new ArgumentException("Invalid output buffer"); + } if (inputCount != _blockSize) + { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); + } - Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); + _ = Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); - for (int i = 0; i < _blockSize; i++) + for (var i = 0; i < _blockSize; i++) { outputBuffer[outputOffset + i] = (byte)(_ivOutput[i] ^ inputBuffer[inputOffset + i]); } @@ -69,20 +75,26 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer.Length - inputOffset < _blockSize) + { throw new ArgumentException("Invalid input buffer"); + } if (outputBuffer.Length - outputOffset < _blockSize) + { throw new ArgumentException("Invalid output buffer"); + } if (inputCount != _blockSize) + { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); + } - Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); + _ = Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); Buffer.BlockCopy(IV, _blockSize, IV, 0, IV.Length - _blockSize); Buffer.BlockCopy(inputBuffer, inputOffset, IV, IV.Length - _blockSize, _blockSize); - for (int i = 0; i < _blockSize; i++) + for (var i = 0; i < _blockSize; i++) { outputBuffer[outputOffset + i] = (byte)(_ivOutput[i] ^ inputBuffer[inputOffset + i]); } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CtrCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CtrCipherMode.cs index cbe5d7e60..47146567b 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CtrCipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CtrCipherMode.cs @@ -34,22 +34,28 @@ public CtrCipherMode(byte[] iv) public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer.Length - inputOffset < _blockSize) + { throw new ArgumentException("Invalid input buffer"); + } if (outputBuffer.Length - outputOffset < _blockSize) + { throw new ArgumentException("Invalid output buffer"); + } if (inputCount != _blockSize) + { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); + } - Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); + _ = Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); - for (int i = 0; i < _blockSize; i++) + for (var i = 0; i < _blockSize; i++) { outputBuffer[outputOffset + i] = (byte)(_ivOutput[i] ^ inputBuffer[inputOffset + i]); } - int j = IV.Length; + var j = IV.Length; while (--j >= 0 && ++IV[j] == 0) ; return _blockSize; @@ -69,22 +75,28 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer.Length - inputOffset < _blockSize) + { throw new ArgumentException("Invalid input buffer"); + } if (outputBuffer.Length - outputOffset < _blockSize) + { throw new ArgumentException("Invalid output buffer"); + } if (inputCount != _blockSize) + { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); + } - Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); + _ = Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); - for (int i = 0; i < _blockSize; i++) + for (var i = 0; i < _blockSize; i++) { outputBuffer[outputOffset + i] = (byte)(_ivOutput[i] ^ inputBuffer[inputOffset + i]); } - int j = IV.Length; + var j = IV.Length; while (--j >= 0 && ++IV[j] == 0) ; return _blockSize; diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs index a13cfb0a1..1f321f454 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs @@ -34,17 +34,23 @@ public OfbCipherMode(byte[] iv) public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer.Length - inputOffset < _blockSize) + { throw new ArgumentException("Invalid input buffer"); + } if (outputBuffer.Length - outputOffset < _blockSize) + { throw new ArgumentException("Invalid output buffer"); + } if (inputCount != _blockSize) + { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); + } - Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); + _ = Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); - for (int i = 0; i < _blockSize; i++) + for (var i = 0; i < _blockSize; i++) { outputBuffer[outputOffset + i] = (byte)(_ivOutput[i] ^ inputBuffer[inputOffset + i]); } @@ -69,17 +75,23 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer.Length - inputOffset < _blockSize) + { throw new ArgumentException("Invalid input buffer"); + } if (outputBuffer.Length - outputOffset < _blockSize) + { throw new ArgumentException("Invalid output buffer"); + } if (inputCount != _blockSize) + { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); + } - Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); + _ = Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); - for (int i = 0; i < _blockSize; i++) + for (var i = 0; i < _blockSize; i++) { outputBuffer[outputOffset + i] = (byte)(_ivOutput[i] ^ inputBuffer[inputOffset + i]); } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS5Padding.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS5Padding.cs index 70d94c20f..18e85c597 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS5Padding.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS5Padding.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers.Paddings { /// - /// Implements PKCS5 cipher padding + /// Implements PKCS5 cipher padding. /// public class PKCS5Padding : CipherPadding { @@ -37,10 +37,12 @@ public override byte[] Pad(byte[] input, int offset, int length, int paddingleng { var output = new byte[length + paddinglength]; Buffer.BlockCopy(input, offset, output, 0, length); + for (var i = 0; i < paddinglength; i++) { output[length + i] = (byte) paddinglength; } + return output; } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS7Padding.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS7Padding.cs index 2623d8fd0..cfe0ae9a3 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS7Padding.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS7Padding.cs @@ -37,10 +37,12 @@ public override byte[] Pad(byte[] input, int offset, int length, int paddingleng { var output = new byte[length + paddinglength]; Buffer.BlockCopy(input, offset, output, 0, length); + for (var i = 0; i < paddinglength; i++) { output[length + i] = (byte) paddinglength; } + return output; } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs index 116471bde..0bfce1aad 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs @@ -19,7 +19,9 @@ public class RsaCipher : AsymmetricCipher public RsaCipher(RsaKey key) { if (key == null) - throw new ArgumentNullException("key"); + { + throw new ArgumentNullException(nameof(key)); + } _key = key; _isPrivate = !_key.D.IsZero; @@ -34,7 +36,7 @@ public RsaCipher(RsaKey key) /// Encrypted data. public override byte[] Encrypt(byte[] data, int offset, int length) { - // Calculate signature + // Calculate signature var bitLength = _key.Modulus.BitLength; var paddedBlock = new byte[bitLength / 8 + (bitLength % 8 > 0 ? 1 : 0) - 1]; @@ -79,12 +81,18 @@ public override byte[] Decrypt(byte[] data, int offset, int length) { var paddedBlock = Transform(data, offset, length); - if (paddedBlock[0] != 1 && paddedBlock[0] != 2) + if (paddedBlock[0] is not 1 and not 2) + { throw new NotSupportedException("Only block type 01 or 02 are supported."); + } var position = 1; + while (position < paddedBlock.Length && paddedBlock[position] != 0) + { position++; + } + position++; var result = new byte[paddedBlock.Length - position]; @@ -115,28 +123,30 @@ private byte[] Transform(byte[] data, int offset, int length) var bitLength = _key.Modulus.BitLength; if (max < BigInteger.One) + { throw new SshException("Invalid RSA key."); + } while (random <= BigInteger.One || random >= max) { random = BigInteger.Random(bitLength); } - var blindedInput = BigInteger.PositiveMod((BigInteger.ModPow(random, _key.Exponent, _key.Modulus) * input), _key.Modulus); + var blindedInput = BigInteger.PositiveMod(BigInteger.ModPow(random, _key.Exponent, _key.Modulus) * input, _key.Modulus); // mP = ((input Mod p) ^ dP)) Mod p - var mP = BigInteger.ModPow((blindedInput % _key.P), _key.DP, _key.P); + var mP = BigInteger.ModPow(blindedInput % _key.P, _key.DP, _key.P); // mQ = ((input Mod q) ^ dQ)) Mod q - var mQ = BigInteger.ModPow((blindedInput % _key.Q), _key.DQ, _key.Q); + var mQ = BigInteger.ModPow(blindedInput % _key.Q, _key.DQ, _key.Q); - var h = BigInteger.PositiveMod(((mP - mQ) * _key.InverseQ), _key.P); + var h = BigInteger.PositiveMod((mP - mQ) * _key.InverseQ, _key.P); var m = h * _key.Q + mQ; var rInv = BigInteger.ModInverse(random, _key.Modulus); - result = BigInteger.PositiveMod((m * rInv), _key.Modulus); + result = BigInteger.PositiveMod(m * rInv, _key.Modulus); } else { diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs index 613059467..0f67ac204 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs @@ -11,7 +11,12 @@ public sealed class SerpentCipher : BlockCipher private const int Phi = unchecked((int)0x9E3779B9); // (Sqrt(5) - 1) * 2**31 private readonly int[] _workingKey; - private int _x0, _x1, _x2, _x3; // registers + + // registers + private int _x0; + private int _x1; + private int _x2; + private int _x3; /// /// Initializes a new instance of the class. @@ -26,8 +31,10 @@ public SerpentCipher(byte[] key, CipherMode mode, CipherPadding padding) { var keySize = key.Length * 8; - if (!(keySize == 128 || keySize == 192 || keySize == 256)) + if (keySize is not (128 or 192 or 256)) + { throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize)); + } _workingKey = MakeWorkingKey(key); } @@ -46,44 +53,77 @@ public SerpentCipher(byte[] key, CipherMode mode, CipherPadding padding) public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputCount != BlockSize) + { throw new ArgumentException("inputCount"); + } _x3 = BytesToWord(inputBuffer, inputOffset); _x2 = BytesToWord(inputBuffer, inputOffset + 4); _x1 = BytesToWord(inputBuffer, inputOffset + 8); _x0 = BytesToWord(inputBuffer, inputOffset + 12); - Sb0(_workingKey[0] ^ _x0, _workingKey[1] ^ _x1, _workingKey[2] ^ _x2, _workingKey[3] ^ _x3); LT(); - Sb1(_workingKey[4] ^ _x0, _workingKey[5] ^ _x1, _workingKey[6] ^ _x2, _workingKey[7] ^ _x3); LT(); - Sb2(_workingKey[8] ^ _x0, _workingKey[9] ^ _x1, _workingKey[10] ^ _x2, _workingKey[11] ^ _x3); LT(); - Sb3(_workingKey[12] ^ _x0, _workingKey[13] ^ _x1, _workingKey[14] ^ _x2, _workingKey[15] ^ _x3); LT(); - Sb4(_workingKey[16] ^ _x0, _workingKey[17] ^ _x1, _workingKey[18] ^ _x2, _workingKey[19] ^ _x3); LT(); - Sb5(_workingKey[20] ^ _x0, _workingKey[21] ^ _x1, _workingKey[22] ^ _x2, _workingKey[23] ^ _x3); LT(); - Sb6(_workingKey[24] ^ _x0, _workingKey[25] ^ _x1, _workingKey[26] ^ _x2, _workingKey[27] ^ _x3); LT(); - Sb7(_workingKey[28] ^ _x0, _workingKey[29] ^ _x1, _workingKey[30] ^ _x2, _workingKey[31] ^ _x3); LT(); - Sb0(_workingKey[32] ^ _x0, _workingKey[33] ^ _x1, _workingKey[34] ^ _x2, _workingKey[35] ^ _x3); LT(); - Sb1(_workingKey[36] ^ _x0, _workingKey[37] ^ _x1, _workingKey[38] ^ _x2, _workingKey[39] ^ _x3); LT(); - Sb2(_workingKey[40] ^ _x0, _workingKey[41] ^ _x1, _workingKey[42] ^ _x2, _workingKey[43] ^ _x3); LT(); - Sb3(_workingKey[44] ^ _x0, _workingKey[45] ^ _x1, _workingKey[46] ^ _x2, _workingKey[47] ^ _x3); LT(); - Sb4(_workingKey[48] ^ _x0, _workingKey[49] ^ _x1, _workingKey[50] ^ _x2, _workingKey[51] ^ _x3); LT(); - Sb5(_workingKey[52] ^ _x0, _workingKey[53] ^ _x1, _workingKey[54] ^ _x2, _workingKey[55] ^ _x3); LT(); - Sb6(_workingKey[56] ^ _x0, _workingKey[57] ^ _x1, _workingKey[58] ^ _x2, _workingKey[59] ^ _x3); LT(); - Sb7(_workingKey[60] ^ _x0, _workingKey[61] ^ _x1, _workingKey[62] ^ _x2, _workingKey[63] ^ _x3); LT(); - Sb0(_workingKey[64] ^ _x0, _workingKey[65] ^ _x1, _workingKey[66] ^ _x2, _workingKey[67] ^ _x3); LT(); - Sb1(_workingKey[68] ^ _x0, _workingKey[69] ^ _x1, _workingKey[70] ^ _x2, _workingKey[71] ^ _x3); LT(); - Sb2(_workingKey[72] ^ _x0, _workingKey[73] ^ _x1, _workingKey[74] ^ _x2, _workingKey[75] ^ _x3); LT(); - Sb3(_workingKey[76] ^ _x0, _workingKey[77] ^ _x1, _workingKey[78] ^ _x2, _workingKey[79] ^ _x3); LT(); - Sb4(_workingKey[80] ^ _x0, _workingKey[81] ^ _x1, _workingKey[82] ^ _x2, _workingKey[83] ^ _x3); LT(); - Sb5(_workingKey[84] ^ _x0, _workingKey[85] ^ _x1, _workingKey[86] ^ _x2, _workingKey[87] ^ _x3); LT(); - Sb6(_workingKey[88] ^ _x0, _workingKey[89] ^ _x1, _workingKey[90] ^ _x2, _workingKey[91] ^ _x3); LT(); - Sb7(_workingKey[92] ^ _x0, _workingKey[93] ^ _x1, _workingKey[94] ^ _x2, _workingKey[95] ^ _x3); LT(); - Sb0(_workingKey[96] ^ _x0, _workingKey[97] ^ _x1, _workingKey[98] ^ _x2, _workingKey[99] ^ _x3); LT(); - Sb1(_workingKey[100] ^ _x0, _workingKey[101] ^ _x1, _workingKey[102] ^ _x2, _workingKey[103] ^ _x3); LT(); - Sb2(_workingKey[104] ^ _x0, _workingKey[105] ^ _x1, _workingKey[106] ^ _x2, _workingKey[107] ^ _x3); LT(); - Sb3(_workingKey[108] ^ _x0, _workingKey[109] ^ _x1, _workingKey[110] ^ _x2, _workingKey[111] ^ _x3); LT(); - Sb4(_workingKey[112] ^ _x0, _workingKey[113] ^ _x1, _workingKey[114] ^ _x2, _workingKey[115] ^ _x3); LT(); - Sb5(_workingKey[116] ^ _x0, _workingKey[117] ^ _x1, _workingKey[118] ^ _x2, _workingKey[119] ^ _x3); LT(); - Sb6(_workingKey[120] ^ _x0, _workingKey[121] ^ _x1, _workingKey[122] ^ _x2, _workingKey[123] ^ _x3); LT(); + Sb0(_workingKey[0] ^ _x0, _workingKey[1] ^ _x1, _workingKey[2] ^ _x2, _workingKey[3] ^ _x3); + LT(); + Sb1(_workingKey[4] ^ _x0, _workingKey[5] ^ _x1, _workingKey[6] ^ _x2, _workingKey[7] ^ _x3); + LT(); + Sb2(_workingKey[8] ^ _x0, _workingKey[9] ^ _x1, _workingKey[10] ^ _x2, _workingKey[11] ^ _x3); + LT(); + Sb3(_workingKey[12] ^ _x0, _workingKey[13] ^ _x1, _workingKey[14] ^ _x2, _workingKey[15] ^ _x3); + LT(); + Sb4(_workingKey[16] ^ _x0, _workingKey[17] ^ _x1, _workingKey[18] ^ _x2, _workingKey[19] ^ _x3); + LT(); + Sb5(_workingKey[20] ^ _x0, _workingKey[21] ^ _x1, _workingKey[22] ^ _x2, _workingKey[23] ^ _x3); + LT(); + Sb6(_workingKey[24] ^ _x0, _workingKey[25] ^ _x1, _workingKey[26] ^ _x2, _workingKey[27] ^ _x3); + LT(); + Sb7(_workingKey[28] ^ _x0, _workingKey[29] ^ _x1, _workingKey[30] ^ _x2, _workingKey[31] ^ _x3); + LT(); + Sb0(_workingKey[32] ^ _x0, _workingKey[33] ^ _x1, _workingKey[34] ^ _x2, _workingKey[35] ^ _x3); + LT(); + Sb1(_workingKey[36] ^ _x0, _workingKey[37] ^ _x1, _workingKey[38] ^ _x2, _workingKey[39] ^ _x3); + LT(); + Sb2(_workingKey[40] ^ _x0, _workingKey[41] ^ _x1, _workingKey[42] ^ _x2, _workingKey[43] ^ _x3); + LT(); + Sb3(_workingKey[44] ^ _x0, _workingKey[45] ^ _x1, _workingKey[46] ^ _x2, _workingKey[47] ^ _x3); + LT(); + Sb4(_workingKey[48] ^ _x0, _workingKey[49] ^ _x1, _workingKey[50] ^ _x2, _workingKey[51] ^ _x3); + LT(); + Sb5(_workingKey[52] ^ _x0, _workingKey[53] ^ _x1, _workingKey[54] ^ _x2, _workingKey[55] ^ _x3); + LT(); + Sb6(_workingKey[56] ^ _x0, _workingKey[57] ^ _x1, _workingKey[58] ^ _x2, _workingKey[59] ^ _x3); + LT(); + Sb7(_workingKey[60] ^ _x0, _workingKey[61] ^ _x1, _workingKey[62] ^ _x2, _workingKey[63] ^ _x3); + LT(); + Sb0(_workingKey[64] ^ _x0, _workingKey[65] ^ _x1, _workingKey[66] ^ _x2, _workingKey[67] ^ _x3); + LT(); + Sb1(_workingKey[68] ^ _x0, _workingKey[69] ^ _x1, _workingKey[70] ^ _x2, _workingKey[71] ^ _x3); + LT(); + Sb2(_workingKey[72] ^ _x0, _workingKey[73] ^ _x1, _workingKey[74] ^ _x2, _workingKey[75] ^ _x3); + LT(); + Sb3(_workingKey[76] ^ _x0, _workingKey[77] ^ _x1, _workingKey[78] ^ _x2, _workingKey[79] ^ _x3); + LT(); + Sb4(_workingKey[80] ^ _x0, _workingKey[81] ^ _x1, _workingKey[82] ^ _x2, _workingKey[83] ^ _x3); + LT(); + Sb5(_workingKey[84] ^ _x0, _workingKey[85] ^ _x1, _workingKey[86] ^ _x2, _workingKey[87] ^ _x3); + LT(); + Sb6(_workingKey[88] ^ _x0, _workingKey[89] ^ _x1, _workingKey[90] ^ _x2, _workingKey[91] ^ _x3); + LT(); + Sb7(_workingKey[92] ^ _x0, _workingKey[93] ^ _x1, _workingKey[94] ^ _x2, _workingKey[95] ^ _x3); + LT(); + Sb0(_workingKey[96] ^ _x0, _workingKey[97] ^ _x1, _workingKey[98] ^ _x2, _workingKey[99] ^ _x3); + LT(); + Sb1(_workingKey[100] ^ _x0, _workingKey[101] ^ _x1, _workingKey[102] ^ _x2, _workingKey[103] ^ _x3); + LT(); + Sb2(_workingKey[104] ^ _x0, _workingKey[105] ^ _x1, _workingKey[106] ^ _x2, _workingKey[107] ^ _x3); + LT(); + Sb3(_workingKey[108] ^ _x0, _workingKey[109] ^ _x1, _workingKey[110] ^ _x2, _workingKey[111] ^ _x3); + LT(); + Sb4(_workingKey[112] ^ _x0, _workingKey[113] ^ _x1, _workingKey[114] ^ _x2, _workingKey[115] ^ _x3); + LT(); + Sb5(_workingKey[116] ^ _x0, _workingKey[117] ^ _x1, _workingKey[118] ^ _x2, _workingKey[119] ^ _x3); + LT(); + Sb6(_workingKey[120] ^ _x0, _workingKey[121] ^ _x1, _workingKey[122] ^ _x2, _workingKey[123] ^ _x3); + LT(); Sb7(_workingKey[124] ^ _x0, _workingKey[125] ^ _x1, _workingKey[126] ^ _x2, _workingKey[127] ^ _x3); WordToBytes(_workingKey[131] ^ _x3, outputBuffer, outputOffset); @@ -108,7 +148,9 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputCount != BlockSize) + { throw new ArgumentException("inputCount"); + } _x3 = _workingKey[131] ^ BytesToWord(inputBuffer, inputOffset); _x2 = _workingKey[130] ^ BytesToWord(inputBuffer, inputOffset + 4); @@ -116,68 +158,253 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC _x0 = _workingKey[128] ^ BytesToWord(inputBuffer, inputOffset + 12); Ib7(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[124]; _x1 ^= _workingKey[125]; _x2 ^= _workingKey[126]; _x3 ^= _workingKey[127]; - InverseLT(); Ib6(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[120]; _x1 ^= _workingKey[121]; _x2 ^= _workingKey[122]; _x3 ^= _workingKey[123]; - InverseLT(); Ib5(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[116]; _x1 ^= _workingKey[117]; _x2 ^= _workingKey[118]; _x3 ^= _workingKey[119]; - InverseLT(); Ib4(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[112]; _x1 ^= _workingKey[113]; _x2 ^= _workingKey[114]; _x3 ^= _workingKey[115]; - InverseLT(); Ib3(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[108]; _x1 ^= _workingKey[109]; _x2 ^= _workingKey[110]; _x3 ^= _workingKey[111]; - InverseLT(); Ib2(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[104]; _x1 ^= _workingKey[105]; _x2 ^= _workingKey[106]; _x3 ^= _workingKey[107]; - InverseLT(); Ib1(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[100]; _x1 ^= _workingKey[101]; _x2 ^= _workingKey[102]; _x3 ^= _workingKey[103]; - InverseLT(); Ib0(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[96]; _x1 ^= _workingKey[97]; _x2 ^= _workingKey[98]; _x3 ^= _workingKey[99]; - InverseLT(); Ib7(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[92]; _x1 ^= _workingKey[93]; _x2 ^= _workingKey[94]; _x3 ^= _workingKey[95]; - InverseLT(); Ib6(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[88]; _x1 ^= _workingKey[89]; _x2 ^= _workingKey[90]; _x3 ^= _workingKey[91]; - InverseLT(); Ib5(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[84]; _x1 ^= _workingKey[85]; _x2 ^= _workingKey[86]; _x3 ^= _workingKey[87]; - InverseLT(); Ib4(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[80]; _x1 ^= _workingKey[81]; _x2 ^= _workingKey[82]; _x3 ^= _workingKey[83]; - InverseLT(); Ib3(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[76]; _x1 ^= _workingKey[77]; _x2 ^= _workingKey[78]; _x3 ^= _workingKey[79]; - InverseLT(); Ib2(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[72]; _x1 ^= _workingKey[73]; _x2 ^= _workingKey[74]; _x3 ^= _workingKey[75]; - InverseLT(); Ib1(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[68]; _x1 ^= _workingKey[69]; _x2 ^= _workingKey[70]; _x3 ^= _workingKey[71]; - InverseLT(); Ib0(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[64]; _x1 ^= _workingKey[65]; _x2 ^= _workingKey[66]; _x3 ^= _workingKey[67]; - InverseLT(); Ib7(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[60]; _x1 ^= _workingKey[61]; _x2 ^= _workingKey[62]; _x3 ^= _workingKey[63]; - InverseLT(); Ib6(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[56]; _x1 ^= _workingKey[57]; _x2 ^= _workingKey[58]; _x3 ^= _workingKey[59]; - InverseLT(); Ib5(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[52]; _x1 ^= _workingKey[53]; _x2 ^= _workingKey[54]; _x3 ^= _workingKey[55]; - InverseLT(); Ib4(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[48]; _x1 ^= _workingKey[49]; _x2 ^= _workingKey[50]; _x3 ^= _workingKey[51]; - InverseLT(); Ib3(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[44]; _x1 ^= _workingKey[45]; _x2 ^= _workingKey[46]; _x3 ^= _workingKey[47]; - InverseLT(); Ib2(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[40]; _x1 ^= _workingKey[41]; _x2 ^= _workingKey[42]; _x3 ^= _workingKey[43]; - InverseLT(); Ib1(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[36]; _x1 ^= _workingKey[37]; _x2 ^= _workingKey[38]; _x3 ^= _workingKey[39]; - InverseLT(); Ib0(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[32]; _x1 ^= _workingKey[33]; _x2 ^= _workingKey[34]; _x3 ^= _workingKey[35]; - InverseLT(); Ib7(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[28]; _x1 ^= _workingKey[29]; _x2 ^= _workingKey[30]; _x3 ^= _workingKey[31]; - InverseLT(); Ib6(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[24]; _x1 ^= _workingKey[25]; _x2 ^= _workingKey[26]; _x3 ^= _workingKey[27]; - InverseLT(); Ib5(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[20]; _x1 ^= _workingKey[21]; _x2 ^= _workingKey[22]; _x3 ^= _workingKey[23]; - InverseLT(); Ib4(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[16]; _x1 ^= _workingKey[17]; _x2 ^= _workingKey[18]; _x3 ^= _workingKey[19]; - InverseLT(); Ib3(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[12]; _x1 ^= _workingKey[13]; _x2 ^= _workingKey[14]; _x3 ^= _workingKey[15]; - InverseLT(); Ib2(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[8]; _x1 ^= _workingKey[9]; _x2 ^= _workingKey[10]; _x3 ^= _workingKey[11]; - InverseLT(); Ib1(_x0, _x1, _x2, _x3); - _x0 ^= _workingKey[4]; _x1 ^= _workingKey[5]; _x2 ^= _workingKey[6]; _x3 ^= _workingKey[7]; - InverseLT(); Ib0(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[124]; + _x1 ^= _workingKey[125]; + _x2 ^= _workingKey[126]; + _x3 ^= _workingKey[127]; + + InverseLT(); + Ib6(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[120]; + _x1 ^= _workingKey[121]; + _x2 ^= _workingKey[122]; + _x3 ^= _workingKey[123]; + + InverseLT(); + Ib5(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[116]; + _x1 ^= _workingKey[117]; + _x2 ^= _workingKey[118]; + _x3 ^= _workingKey[119]; + + InverseLT(); + Ib4(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[112]; + _x1 ^= _workingKey[113]; + _x2 ^= _workingKey[114]; + _x3 ^= _workingKey[115]; + InverseLT(); + Ib3(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[108]; + _x1 ^= _workingKey[109]; + _x2 ^= _workingKey[110]; + _x3 ^= _workingKey[111]; + + InverseLT(); + Ib2(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[104]; + _x1 ^= _workingKey[105]; + _x2 ^= _workingKey[106]; + _x3 ^= _workingKey[107]; + + InverseLT(); + Ib1(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[100]; + _x1 ^= _workingKey[101]; + _x2 ^= _workingKey[102]; + _x3 ^= _workingKey[103]; + + InverseLT(); + Ib0(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[96]; + _x1 ^= _workingKey[97]; + _x2 ^= _workingKey[98]; + _x3 ^= _workingKey[99]; + + InverseLT(); + Ib7(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[92]; + _x1 ^= _workingKey[93]; + _x2 ^= _workingKey[94]; + _x3 ^= _workingKey[95]; + + InverseLT(); + Ib6(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[88]; + _x1 ^= _workingKey[89]; + _x2 ^= _workingKey[90]; + _x3 ^= _workingKey[91]; + + InverseLT(); + Ib5(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[84]; + _x1 ^= _workingKey[85]; + _x2 ^= _workingKey[86]; + _x3 ^= _workingKey[87]; + + InverseLT(); + Ib4(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[80]; + _x1 ^= _workingKey[81]; + _x2 ^= _workingKey[82]; + _x3 ^= _workingKey[83]; + + InverseLT(); + Ib3(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[76]; + _x1 ^= _workingKey[77]; + _x2 ^= _workingKey[78]; + _x3 ^= _workingKey[79]; + + InverseLT(); + Ib2(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[72]; + _x1 ^= _workingKey[73]; + _x2 ^= _workingKey[74]; + _x3 ^= _workingKey[75]; + + InverseLT(); + Ib1(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[68]; + _x1 ^= _workingKey[69]; + _x2 ^= _workingKey[70]; + _x3 ^= _workingKey[71]; + + InverseLT(); + Ib0(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[64]; + _x1 ^= _workingKey[65]; + _x2 ^= _workingKey[66]; + _x3 ^= _workingKey[67]; + + InverseLT(); + Ib7(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[60]; + _x1 ^= _workingKey[61]; + _x2 ^= _workingKey[62]; + _x3 ^= _workingKey[63]; + + InverseLT(); + Ib6(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[56]; + _x1 ^= _workingKey[57]; + _x2 ^= _workingKey[58]; + _x3 ^= _workingKey[59]; + + InverseLT(); + Ib5(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[52]; + _x1 ^= _workingKey[53]; + _x2 ^= _workingKey[54]; + _x3 ^= _workingKey[55]; + + InverseLT(); + Ib4(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[48]; + _x1 ^= _workingKey[49]; + _x2 ^= _workingKey[50]; + _x3 ^= _workingKey[51]; + + InverseLT(); + Ib3(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[44]; + _x1 ^= _workingKey[45]; + _x2 ^= _workingKey[46]; + _x3 ^= _workingKey[47]; + + InverseLT(); + Ib2(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[40]; + _x1 ^= _workingKey[41]; + _x2 ^= _workingKey[42]; + _x3 ^= _workingKey[43]; + + InverseLT(); + Ib1(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[36]; + _x1 ^= _workingKey[37]; + _x2 ^= _workingKey[38]; + _x3 ^= _workingKey[39]; + + InverseLT(); + Ib0(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[32]; + _x1 ^= _workingKey[33]; + _x2 ^= _workingKey[34]; + _x3 ^= _workingKey[35]; + + InverseLT(); + Ib7(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[28]; + _x1 ^= _workingKey[29]; + _x2 ^= _workingKey[30]; + _x3 ^= _workingKey[31]; + + InverseLT(); + Ib6(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[24]; + _x1 ^= _workingKey[25]; + _x2 ^= _workingKey[26]; + _x3 ^= _workingKey[27]; + + InverseLT(); + Ib5(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[20]; + _x1 ^= _workingKey[21]; + _x2 ^= _workingKey[22]; + _x3 ^= _workingKey[23]; + + InverseLT(); + Ib4(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[16]; + _x1 ^= _workingKey[17]; + _x2 ^= _workingKey[18]; + _x3 ^= _workingKey[19]; + + InverseLT(); + Ib3(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[12]; + _x1 ^= _workingKey[13]; + _x2 ^= _workingKey[14]; + _x3 ^= _workingKey[15]; + + InverseLT(); + Ib2(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[8]; + _x1 ^= _workingKey[9]; + _x2 ^= _workingKey[10]; + _x3 ^= _workingKey[11]; + + InverseLT(); + Ib1(_x0, _x1, _x2, _x3); + + _x0 ^= _workingKey[4]; + _x1 ^= _workingKey[5]; + _x2 ^= _workingKey[6]; + _x3 ^= _workingKey[7]; + + InverseLT(); + Ib0(_x0, _x1, _x2, _x3); WordToBytes(_x3 ^ _workingKey[3], outputBuffer, outputOffset); WordToBytes(_x2 ^ _workingKey[2], outputBuffer, outputOffset + 4); @@ -187,7 +414,6 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC return BlockSize; } - /// /// Expand a user-supplied key material into a session key. /// @@ -198,9 +424,7 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC /// is not multiple of 4 bytes. private int[] MakeWorkingKey(byte[] key) { - // // pad key to 256 bits - // var kPad = new int[16]; int off; var length = 0; @@ -223,15 +447,11 @@ private int[] MakeWorkingKey(byte[] key) throw new ArgumentException("key must be a multiple of 4 bytes"); } - // // expand the padded key up to 33 x 128 bits of key material - // const int amount = (Rounds + 1) * 4; var w = new int[amount]; - // // compute w0 to w7 from w-8 to w-1 - // for (var i = 8; i < 16; i++) { kPad[i] = RotateLeft(kPad[i - 8] ^ kPad[i - 5] ^ kPad[i - 3] ^ kPad[i - 1] ^ Phi ^ (i - 8), 11); @@ -239,134 +459,263 @@ private int[] MakeWorkingKey(byte[] key) Buffer.BlockCopy(kPad, 8, w, 0, 8); - // // compute w8 to w136 - // for (var i = 8; i < amount; i++) { w[i] = RotateLeft(w[i - 8] ^ w[i - 5] ^ w[i - 3] ^ w[i - 1] ^ Phi ^ i, 11); } - // // create the working keys by processing w with the Sbox and IP - // Sb3(w[0], w[1], w[2], w[3]); - w[0] = _x0; w[1] = _x1; w[2] = _x2; w[3] = _x3; + w[0] = _x0; + w[1] = _x1; + w[2] = _x2; + w[3] = _x3; + Sb2(w[4], w[5], w[6], w[7]); - w[4] = _x0; w[5] = _x1; w[6] = _x2; w[7] = _x3; + w[4] = _x0; + w[5] = _x1; + w[6] = _x2; + w[7] = _x3; + Sb1(w[8], w[9], w[10], w[11]); - w[8] = _x0; w[9] = _x1; w[10] = _x2; w[11] = _x3; + w[8] = _x0; + w[9] = _x1; + w[10] = _x2; + w[11] = _x3; + Sb0(w[12], w[13], w[14], w[15]); - w[12] = _x0; w[13] = _x1; w[14] = _x2; w[15] = _x3; + w[12] = _x0; + w[13] = _x1; + w[14] = _x2; + w[15] = _x3; + Sb7(w[16], w[17], w[18], w[19]); - w[16] = _x0; w[17] = _x1; w[18] = _x2; w[19] = _x3; + w[16] = _x0; + w[17] = _x1; + w[18] = _x2; + w[19] = _x3; + Sb6(w[20], w[21], w[22], w[23]); - w[20] = _x0; w[21] = _x1; w[22] = _x2; w[23] = _x3; + w[20] = _x0; + w[21] = _x1; + w[22] = _x2; + w[23] = _x3; + Sb5(w[24], w[25], w[26], w[27]); - w[24] = _x0; w[25] = _x1; w[26] = _x2; w[27] = _x3; + w[24] = _x0; + w[25] = _x1; + w[26] = _x2; + w[27] = _x3; + Sb4(w[28], w[29], w[30], w[31]); - w[28] = _x0; w[29] = _x1; w[30] = _x2; w[31] = _x3; + w[28] = _x0; + w[29] = _x1; + w[30] = _x2; + w[31] = _x3; + Sb3(w[32], w[33], w[34], w[35]); - w[32] = _x0; w[33] = _x1; w[34] = _x2; w[35] = _x3; + w[32] = _x0; + w[33] = _x1; + w[34] = _x2; + w[35] = _x3; + Sb2(w[36], w[37], w[38], w[39]); - w[36] = _x0; w[37] = _x1; w[38] = _x2; w[39] = _x3; + w[36] = _x0; + w[37] = _x1; + w[38] = _x2; + w[39] = _x3; + Sb1(w[40], w[41], w[42], w[43]); - w[40] = _x0; w[41] = _x1; w[42] = _x2; w[43] = _x3; + w[40] = _x0; + w[41] = _x1; + w[42] = _x2; + w[43] = _x3; + Sb0(w[44], w[45], w[46], w[47]); - w[44] = _x0; w[45] = _x1; w[46] = _x2; w[47] = _x3; + w[44] = _x0; + w[45] = _x1; + w[46] = _x2; + w[47] = _x3; + Sb7(w[48], w[49], w[50], w[51]); - w[48] = _x0; w[49] = _x1; w[50] = _x2; w[51] = _x3; + w[48] = _x0; + w[49] = _x1; + w[50] = _x2; + w[51] = _x3; + Sb6(w[52], w[53], w[54], w[55]); - w[52] = _x0; w[53] = _x1; w[54] = _x2; w[55] = _x3; + w[52] = _x0; + w[53] = _x1; + w[54] = _x2; + w[55] = _x3; + Sb5(w[56], w[57], w[58], w[59]); - w[56] = _x0; w[57] = _x1; w[58] = _x2; w[59] = _x3; + w[56] = _x0; + w[57] = _x1; + w[58] = _x2; + w[59] = _x3; + Sb4(w[60], w[61], w[62], w[63]); - w[60] = _x0; w[61] = _x1; w[62] = _x2; w[63] = _x3; + w[60] = _x0; + w[61] = _x1; + w[62] = _x2; + w[63] = _x3; + Sb3(w[64], w[65], w[66], w[67]); - w[64] = _x0; w[65] = _x1; w[66] = _x2; w[67] = _x3; + w[64] = _x0; + w[65] = _x1; + w[66] = _x2; + w[67] = _x3; + Sb2(w[68], w[69], w[70], w[71]); - w[68] = _x0; w[69] = _x1; w[70] = _x2; w[71] = _x3; + w[68] = _x0; + w[69] = _x1; + w[70] = _x2; + w[71] = _x3; + Sb1(w[72], w[73], w[74], w[75]); - w[72] = _x0; w[73] = _x1; w[74] = _x2; w[75] = _x3; + w[72] = _x0; + w[73] = _x1; + w[74] = _x2; + w[75] = _x3; + Sb0(w[76], w[77], w[78], w[79]); - w[76] = _x0; w[77] = _x1; w[78] = _x2; w[79] = _x3; + w[76] = _x0; + w[77] = _x1; + w[78] = _x2; + w[79] = _x3; + Sb7(w[80], w[81], w[82], w[83]); - w[80] = _x0; w[81] = _x1; w[82] = _x2; w[83] = _x3; + w[80] = _x0; + w[81] = _x1; + w[82] = _x2; + w[83] = _x3; + Sb6(w[84], w[85], w[86], w[87]); - w[84] = _x0; w[85] = _x1; w[86] = _x2; w[87] = _x3; + w[84] = _x0; + w[85] = _x1; + w[86] = _x2; + w[87] = _x3; + Sb5(w[88], w[89], w[90], w[91]); - w[88] = _x0; w[89] = _x1; w[90] = _x2; w[91] = _x3; + w[88] = _x0; + w[89] = _x1; + w[90] = _x2; + w[91] = _x3; + Sb4(w[92], w[93], w[94], w[95]); - w[92] = _x0; w[93] = _x1; w[94] = _x2; w[95] = _x3; + w[92] = _x0; + w[93] = _x1; + w[94] = _x2; + w[95] = _x3; + Sb3(w[96], w[97], w[98], w[99]); - w[96] = _x0; w[97] = _x1; w[98] = _x2; w[99] = _x3; + w[96] = _x0; + w[97] = _x1; + w[98] = _x2; + w[99] = _x3; + Sb2(w[100], w[101], w[102], w[103]); - w[100] = _x0; w[101] = _x1; w[102] = _x2; w[103] = _x3; + w[100] = _x0; + w[101] = _x1; + w[102] = _x2; + w[103] = _x3; + Sb1(w[104], w[105], w[106], w[107]); - w[104] = _x0; w[105] = _x1; w[106] = _x2; w[107] = _x3; + w[104] = _x0; + w[105] = _x1; + w[106] = _x2; + w[107] = _x3; + Sb0(w[108], w[109], w[110], w[111]); - w[108] = _x0; w[109] = _x1; w[110] = _x2; w[111] = _x3; + w[108] = _x0; + w[109] = _x1; + w[110] = _x2; + w[111] = _x3; + Sb7(w[112], w[113], w[114], w[115]); - w[112] = _x0; w[113] = _x1; w[114] = _x2; w[115] = _x3; + w[112] = _x0; + w[113] = _x1; + w[114] = _x2; + w[115] = _x3; + Sb6(w[116], w[117], w[118], w[119]); - w[116] = _x0; w[117] = _x1; w[118] = _x2; w[119] = _x3; + w[116] = _x0; + w[117] = _x1; + w[118] = _x2; + w[119] = _x3; + Sb5(w[120], w[121], w[122], w[123]); - w[120] = _x0; w[121] = _x1; w[122] = _x2; w[123] = _x3; + w[120] = _x0; + w[121] = _x1; + w[122] = _x2; + w[123] = _x3; + Sb4(w[124], w[125], w[126], w[127]); - w[124] = _x0; w[125] = _x1; w[126] = _x2; w[127] = _x3; + w[124] = _x0; + w[125] = _x1; + w[126] = _x2; + w[127] = _x3; + Sb3(w[128], w[129], w[130], w[131]); - w[128] = _x0; w[129] = _x1; w[130] = _x2; w[131] = _x3; + w[128] = _x0; + w[129] = _x1; + w[130] = _x2; + w[131] = _x3; return w; } private static int RotateLeft(int x, int bits) { - return ((x << bits) | (int)((uint)x >> (32 - bits))); + return (x << bits) | (int) ((uint) x >> (32 - bits)); } private static int RotateRight(int x, int bits) { - return ((int)((uint)x >> bits) | (x << (32 - bits))); + return (int) ((uint) x >> bits) | (x << (32 - bits)); } private static int BytesToWord(byte[] src, int srcOff) { - return (((src[srcOff] & 0xff) << 24) | ((src[srcOff + 1] & 0xff) << 16) | - ((src[srcOff + 2] & 0xff) << 8) | ((src[srcOff + 3] & 0xff))); + return ((src[srcOff] & 0xff) << 24) | ((src[srcOff + 1] & 0xff) << 16) | + ((src[srcOff + 2] & 0xff) << 8) | (src[srcOff + 3] & 0xff); } private static void WordToBytes(int word, byte[] dst, int dstOff) { - dst[dstOff + 3] = (byte)(word); - dst[dstOff + 2] = (byte)((uint)word >> 8); - dst[dstOff + 1] = (byte)((uint)word >> 16); - dst[dstOff] = (byte)((uint)word >> 24); + dst[dstOff + 3] = (byte) word; + dst[dstOff + 2] = (byte) ((uint)word >> 8); + dst[dstOff + 1] = (byte) ((uint)word >> 16); + dst[dstOff] = (byte) ((uint)word >> 24); } /* - * The sboxes below are based on the work of Brian Gladman and - * Sam Simpson, whose original notice appears below. - *

- * For further details see: - * http://fp.gladman.plus.com/cryptography_technology/serpent/ - *

- */ - - /* Partially optimised Serpent S Box bool functions derived */ - /* using a recursive descent analyser but without a full search */ - /* of all subtrees. This set of S boxes is the result of work */ - /* by Sam Simpson and Brian Gladman using the spare time on a */ - /* cluster of high capacity servers to search for S boxes with */ - /* this customised search engine. There are now an average of */ - /* 15.375 terms per S box. */ - /* */ - /* Copyright: Dr B. R Gladman (gladman@seven77.demon.co.uk) */ - /* and Sam Simpson (s.simpson@mia.co.uk) */ - /* 17th December 1998 */ - /* */ - /* We hereby give permission for information in this file to be */ - /* used freely subject only to acknowledgement of its origin. */ + * The sboxes below are based on the work of Brian Gladman and + * Sam Simpson, whose original notice appears below. + * + * For further details see: + * http://fp.gladman.plus.com/cryptography_technology/serpent/ + * + */ + + /* + * Partially optimised Serpent S Box bool functions derived + * using a recursive descent analyser but without a full search + * of all subtrees. This set of S boxes is the result of work + * by Sam Simpson and Brian Gladman using the spare time on a + * cluster of high capacity servers to search for S boxes with + * this customised search engine. There are now an average of + * 15.375 terms per S box. + * + * Copyright: Dr B. R Gladman (gladman@seven77.demon.co.uk) + * and Sam Simpson (s.simpson@mia.co.uk) + * 17th December 1998 + * + * We hereby give permission for information in this file to be + * used freely subject only to acknowledgement of its origin. + */ /// /// S0 - { 3, 8,15, 1,10, 6, 5,11,14,13, 4, 2, 7, 0, 9,12 } - 15 terms. @@ -377,13 +726,13 @@ private static void WordToBytes(int word, byte[] dst, int dstOff) /// The d. private void Sb0(int a, int b, int c, int d) { - int t1 = a ^ d; - int t3 = c ^ t1; - int t4 = b ^ t3; + var t1 = a ^ d; + var t3 = c ^ t1; + var t4 = b ^ t3; _x3 = (a & d) ^ t4; - int t7 = a ^ (b & t1); + var t7 = a ^ (b & t1); _x2 = t4 ^ (c | t7); - int t12 = _x3 & (t3 ^ t7); + var t12 = _x3 & (t3 ^ t7); _x1 = (~t3) ^ t12; _x0 = t12 ^ (~t7); } @@ -397,12 +746,12 @@ private void Sb0(int a, int b, int c, int d) /// The d. private void Ib0(int a, int b, int c, int d) { - int t1 = ~a; - int t2 = a ^ b; - int t4 = d ^ (t1 | t2); - int t5 = c ^ t4; + var t1 = ~a; + var t2 = a ^ b; + var t4 = d ^ (t1 | t2); + var t5 = c ^ t4; _x2 = t2 ^ t5; - int t8 = t1 ^ (d & t2); + var t8 = t1 ^ (d & t2); _x1 = t4 ^ (_x2 & t8); _x3 = (a & t4) ^ (t5 | _x1); _x0 = _x3 ^ (t5 ^ t8); @@ -417,13 +766,13 @@ private void Ib0(int a, int b, int c, int d) /// The d. private void Sb1(int a, int b, int c, int d) { - int t2 = b ^ (~a); - int t5 = c ^ (a | t2); + var t2 = b ^ (~a); + var t5 = c ^ (a | t2); _x2 = d ^ t5; - int t7 = b ^ (d | t2); - int t8 = t2 ^ _x2; + var t7 = b ^ (d | t2); + var t8 = t2 ^ _x2; _x3 = t8 ^ (t5 & t7); - int t11 = t5 ^ t7; + var t11 = t5 ^ t7; _x1 = _x3 ^ t11; _x0 = t5 ^ (t8 & t11); } @@ -437,15 +786,15 @@ private void Sb1(int a, int b, int c, int d) /// The d. private void Ib1(int a, int b, int c, int d) { - int t1 = b ^ d; - int t3 = a ^ (b & t1); - int t4 = t1 ^ t3; + var t1 = b ^ d; + var t3 = a ^ (b & t1); + var t4 = t1 ^ t3; _x3 = c ^ t4; - int t7 = b ^ (t1 & t3); - int t8 = _x3 | t7; + var t7 = b ^ (t1 & t3); + var t8 = _x3 | t7; _x1 = t3 ^ t8; - int t10 = ~_x1; - int t11 = _x3 ^ t7; + var t10 = ~_x1; + var t11 = _x3 ^ t7; _x0 = t10 ^ t11; _x2 = t4 ^ (t10 | t11); } @@ -459,13 +808,13 @@ private void Ib1(int a, int b, int c, int d) /// The d. private void Sb2(int a, int b, int c, int d) { - int t1 = ~a; - int t2 = b ^ d; - int t3 = c & t1; + var t1 = ~a; + var t2 = b ^ d; + var t3 = c & t1; _x0 = t2 ^ t3; - int t5 = c ^ t1; - int t6 = c ^ _x0; - int t7 = b & t6; + var t5 = c ^ t1; + var t6 = c ^ _x0; + var t7 = b & t6; _x3 = t5 ^ t7; _x2 = a ^ ((d | t7) & (_x0 | t5)); _x1 = (t2 ^ _x3) ^ (_x2 ^ (d | t1)); @@ -480,18 +829,18 @@ private void Sb2(int a, int b, int c, int d) /// The d. private void Ib2(int a, int b, int c, int d) { - int t1 = b ^ d; - int t2 = ~t1; - int t3 = a ^ c; - int t4 = c ^ t1; - int t5 = b & t4; + var t1 = b ^ d; + var t2 = ~t1; + var t3 = a ^ c; + var t4 = c ^ t1; + var t5 = b & t4; _x0 = t3 ^ t5; - int t7 = a | t2; - int t8 = d ^ t7; - int t9 = t3 | t8; + var t7 = a | t2; + var t8 = d ^ t7; + var t9 = t3 | t8; _x3 = t1 ^ t9; - int t11 = ~t4; - int t12 = _x0 | _x3; + var t11 = ~t4; + var t12 = _x0 | _x3; _x1 = t11 ^ t12; _x2 = (d & t11) ^ (t3 ^ t12); } @@ -505,18 +854,18 @@ private void Ib2(int a, int b, int c, int d) /// The d. private void Sb3(int a, int b, int c, int d) { - int t1 = a ^ b; - int t2 = a & c; - int t3 = a | d; - int t4 = c ^ d; - int t5 = t1 & t3; - int t6 = t2 | t5; + var t1 = a ^ b; + var t2 = a & c; + var t3 = a | d; + var t4 = c ^ d; + var t5 = t1 & t3; + var t6 = t2 | t5; _x2 = t4 ^ t6; - int t8 = b ^ t3; - int t9 = t6 ^ t8; - int t10 = t4 & t9; + var t8 = b ^ t3; + var t9 = t6 ^ t8; + var t10 = t4 & t9; _x0 = t1 ^ t10; - int t12 = _x2 & _x0; + var t12 = _x2 & _x0; _x1 = t9 ^ t12; _x3 = (b | d) ^ (t4 ^ t12); } @@ -530,18 +879,18 @@ private void Sb3(int a, int b, int c, int d) /// The d. private void Ib3(int a, int b, int c, int d) { - int t1 = a | b; - int t2 = b ^ c; - int t3 = b & t2; - int t4 = a ^ t3; - int t5 = c ^ t4; - int t6 = d | t4; + var t1 = a | b; + var t2 = b ^ c; + var t3 = b & t2; + var t4 = a ^ t3; + var t5 = c ^ t4; + var t6 = d | t4; _x0 = t2 ^ t6; - int t8 = t2 | t6; - int t9 = d ^ t8; + var t8 = t2 | t6; + var t9 = d ^ t8; _x2 = t5 ^ t9; - int t11 = t1 ^ t9; - int t12 = _x0 & t11; + var t11 = t1 ^ t9; + var t12 = _x0 & t11; _x3 = t4 ^ t12; _x1 = _x3 ^ (_x0 ^ t11); } @@ -555,17 +904,17 @@ private void Ib3(int a, int b, int c, int d) /// The d. private void Sb4(int a, int b, int c, int d) { - int t1 = a ^ d; - int t2 = d & t1; - int t3 = c ^ t2; - int t4 = b | t3; + var t1 = a ^ d; + var t2 = d & t1; + var t3 = c ^ t2; + var t4 = b | t3; _x3 = t1 ^ t4; - int t6 = ~b; - int t7 = t1 | t6; + var t6 = ~b; + var t7 = t1 | t6; _x0 = t3 ^ t7; - int t9 = a & _x0; - int t10 = t1 ^ t6; - int t11 = t4 & t10; + var t9 = a & _x0; + var t10 = t1 ^ t6; + var t11 = t4 & t10; _x2 = t9 ^ t11; _x1 = (a ^ t3) ^ (t10 & _x2); } @@ -579,17 +928,17 @@ private void Sb4(int a, int b, int c, int d) /// The d. private void Ib4(int a, int b, int c, int d) { - int t1 = c | d; - int t2 = a & t1; - int t3 = b ^ t2; - int t4 = a & t3; - int t5 = c ^ t4; + var t1 = c | d; + var t2 = a & t1; + var t3 = b ^ t2; + var t4 = a & t3; + var t5 = c ^ t4; _x1 = d ^ t5; - int t7 = ~a; - int t8 = t5 & _x1; + var t7 = ~a; + var t8 = t5 & _x1; _x3 = t3 ^ t8; - int t10 = _x1 | t7; - int t11 = d ^ t10; + var t10 = _x1 | t7; + var t11 = d ^ t10; _x0 = _x3 ^ t11; _x2 = (t3 & t11) ^ (_x1 ^ t7); } @@ -603,18 +952,18 @@ private void Ib4(int a, int b, int c, int d) /// The d. private void Sb5(int a, int b, int c, int d) { - int t1 = ~a; - int t2 = a ^ b; - int t3 = a ^ d; - int t4 = c ^ t1; - int t5 = t2 | t3; + var t1 = ~a; + var t2 = a ^ b; + var t3 = a ^ d; + var t4 = c ^ t1; + var t5 = t2 | t3; _x0 = t4 ^ t5; - int t7 = d & _x0; - int t8 = t2 ^ _x0; + var t7 = d & _x0; + var t8 = t2 ^ _x0; _x1 = t7 ^ t8; - int t10 = t1 | _x0; - int t11 = t2 | t7; - int t12 = t3 ^ t10; + var t10 = t1 | _x0; + var t11 = t2 | t7; + var t12 = t3 ^ t10; _x2 = t11 ^ t12; _x3 = (b ^ t7) ^ (_x1 & t12); } @@ -628,17 +977,17 @@ private void Sb5(int a, int b, int c, int d) /// The d. private void Ib5(int a, int b, int c, int d) { - int t1 = ~c; - int t2 = b & t1; - int t3 = d ^ t2; - int t4 = a & t3; - int t5 = b ^ t1; + var t1 = ~c; + var t2 = b & t1; + var t3 = d ^ t2; + var t4 = a & t3; + var t5 = b ^ t1; _x3 = t4 ^ t5; - int t7 = b | _x3; - int t8 = a & t7; + var t7 = b | _x3; + var t8 = a & t7; _x1 = t3 ^ t8; - int t10 = a | d; - int t11 = t1 ^ t7; + var t10 = a | d; + var t11 = t1 ^ t7; _x0 = t10 ^ t11; _x2 = (b & t10) ^ (t4 | (a ^ c)); } @@ -652,17 +1001,17 @@ private void Ib5(int a, int b, int c, int d) /// The d. private void Sb6(int a, int b, int c, int d) { - int t1 = ~a; - int t2 = a ^ d; - int t3 = b ^ t2; - int t4 = t1 | t2; - int t5 = c ^ t4; + var t1 = ~a; + var t2 = a ^ d; + var t3 = b ^ t2; + var t4 = t1 | t2; + var t5 = c ^ t4; _x1 = b ^ t5; - int t7 = t2 | _x1; - int t8 = d ^ t7; - int t9 = t5 & t8; + var t7 = t2 | _x1; + var t8 = d ^ t7; + var t9 = t5 & t8; _x2 = t3 ^ t9; - int t11 = t5 ^ t8; + var t11 = t5 ^ t8; _x0 = _x2 ^ t11; _x3 = (~t5) ^ (t3 & t11); } @@ -676,17 +1025,17 @@ private void Sb6(int a, int b, int c, int d) /// The d. private void Ib6(int a, int b, int c, int d) { - int t1 = ~a; - int t2 = a ^ b; - int t3 = c ^ t2; - int t4 = c | t1; - int t5 = d ^ t4; + var t1 = ~a; + var t2 = a ^ b; + var t3 = c ^ t2; + var t4 = c | t1; + var t5 = d ^ t4; _x1 = t3 ^ t5; - int t7 = t3 & t5; - int t8 = t2 ^ t7; - int t9 = b | t8; + var t7 = t3 & t5; + var t8 = t2 ^ t7; + var t9 = b | t8; _x3 = t5 ^ t9; - int t11 = b | _x3; + var t11 = b | _x3; _x0 = t8 ^ t11; _x2 = (d & t1) ^ (t3 ^ t11); } @@ -700,18 +1049,18 @@ private void Ib6(int a, int b, int c, int d) /// The d. private void Sb7(int a, int b, int c, int d) { - int t1 = b ^ c; - int t2 = c & t1; - int t3 = d ^ t2; - int t4 = a ^ t3; - int t5 = d | t1; - int t6 = t4 & t5; + var t1 = b ^ c; + var t2 = c & t1; + var t3 = d ^ t2; + var t4 = a ^ t3; + var t5 = d | t1; + var t6 = t4 & t5; _x1 = b ^ t6; - int t8 = t3 | _x1; - int t9 = a & t4; + var t8 = t3 | _x1; + var t9 = a & t4; _x3 = t1 ^ t9; - int t11 = t4 ^ t8; - int t12 = _x3 & t11; + var t11 = t4 ^ t8; + var t12 = _x3 & t11; _x2 = t3 ^ t12; _x0 = (~t11) ^ (_x3 & _x2); } @@ -725,12 +1074,12 @@ private void Sb7(int a, int b, int c, int d) /// The d. private void Ib7(int a, int b, int c, int d) { - int t3 = c | (a & b); - int t4 = d & (a | b); + var t3 = c | (a & b); + var t4 = d & (a | b); _x3 = t3 ^ t4; - int t6 = ~d; - int t7 = b ^ t4; - int t9 = t7 | (_x3 ^ t6); + var t6 = ~d; + var t7 = b ^ t4; + var t9 = t7 | (_x3 ^ t6); _x1 = a ^ t9; _x0 = (c ^ t7) ^ (d | _x1); _x2 = (t3 ^ _x1) ^ (_x0 ^ (a & _x3)); @@ -741,10 +1090,10 @@ private void Ib7(int a, int b, int c, int d) /// private void LT() { - int x0 = RotateLeft(_x0, 13); - int x2 = RotateLeft(_x2, 3); - int x1 = _x1 ^ x0 ^ x2; - int x3 = _x3 ^ x2 ^ x0 << 3; + var x0 = RotateLeft(_x0, 13); + var x2 = RotateLeft(_x2, 3); + var x1 = _x1 ^ x0 ^ x2; + var x3 = _x3 ^ x2 ^ x0 << 3; _x1 = RotateLeft(x1, 1); _x3 = RotateLeft(x3, 7); @@ -757,10 +1106,10 @@ private void LT() ///
private void InverseLT() { - int x2 = RotateRight(_x2, 22) ^ _x3 ^ (_x1 << 7); - int x0 = RotateRight(_x0, 5) ^ _x1 ^ _x3; - int x3 = RotateRight(_x3, 7); - int x1 = RotateRight(_x1, 1); + var x2 = RotateRight(_x2, 22) ^ _x3 ^ (_x1 << 7); + var x0 = RotateRight(_x0, 5) ^ _x1 ^ _x3; + var x3 = RotateRight(_x3, 7); + var x1 = RotateRight(_x1, 1); _x3 = x3 ^ x2 ^ x0 << 3; _x1 = x1 ^ x0 ^ x2; _x2 = RotateRight(x2, 3); diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs index a9db5db53..f83ed24d0 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs @@ -70,7 +70,7 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC } } - byte[] temp = new byte[BlockSize]; + var temp = new byte[BlockSize]; DesFunc(_encryptionKey1, inputBuffer, inputOffset, temp, 0); DesFunc(_encryptionKey2, temp, 0, temp, 0); @@ -93,10 +93,14 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if ((inputOffset + BlockSize) > inputBuffer.Length) + { throw new IndexOutOfRangeException("input buffer too short"); + } if ((outputOffset + BlockSize) > outputBuffer.Length) + { throw new IndexOutOfRangeException("output buffer too short"); + } if (_decryptionKey1 == null || _decryptionKey2 == null || _decryptionKey3 == null) { @@ -122,7 +126,7 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC } } - byte[] temp = new byte[BlockSize]; + var temp = new byte[BlockSize]; DesFunc(_decryptionKey3, inputBuffer, inputOffset, temp, 0); DesFunc(_decryptionKey2, temp, 0, temp, 0); @@ -138,8 +142,10 @@ protected override void ValidateKey() { var keySize = Key.Length * 8; - if (!(keySize == 128 || keySize == 128 + 64)) + if (keySize is not (128 or 128 + 64)) + { throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize)); + } } } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs index 8f7c8bba0..ac33dce9c 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers { /// - /// Implements Twofish cipher algorithm + /// Implements Twofish cipher algorithm. /// public sealed class TwofishCipher : BlockCipher { @@ -20,10 +20,10 @@ public TwofishCipher(byte[] key, CipherMode mode, CipherPadding padding) { var keySize = key.Length * 8; - if (!(keySize == 128 || keySize == 192 || keySize == 256)) + if (keySize is not (128 or 192 or 256)) + { throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize)); - - // TODO: Refactor this algorithm + } // calculate the MDS matrix var m1 = new int[2]; @@ -139,8 +139,6 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC return BlockSize; } - #region Static Definition Tables - private static readonly byte[] P = { // p0 @@ -160,6 +158,7 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72, 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68, 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4, 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42, 0x4A, 0x5E, 0xC1, 0xE0, + // p1 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B, 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1, 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, @@ -179,13 +178,11 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91 }; - #endregion - /** - * Define the fixed p0/p1 permutations used in keyed S-box lookup. - * By changing the following constant definitions, the S-boxes will - * automatically Get changed in the Twofish engine. - */ + * Define the fixed p0/p1 permutations used in keyed S-box lookup. + * By changing the following constant definitions, the S-boxes will + * automatically Get changed in the Twofish engine. + */ private const int P_00 = 1; private const int P_01 = 0; private const int P_02 = 0; @@ -217,10 +214,6 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC private const int RS_GF_FDBK = 0x14D; // field generator - //==================================== - // Useful constants - //==================================== - private const int ROUNDS = 16; private const int MAX_ROUNDS = 16; // bytes = 128 bits private const int MAX_KEY_BITS = 256; @@ -240,6 +233,8 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC private readonly int[] gMDS2 = new int[MAX_KEY_BITS]; private readonly int[] gMDS3 = new int[MAX_KEY_BITS]; + private readonly int _k64Cnt; + /** * gSubKeys[] and gSBox[] are eventually used in the * encryption and decryption methods. @@ -247,8 +242,6 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC private int[] gSubKeys; private int[] gSBox; - private readonly int _k64Cnt; - private void SetKey(byte[] key) { var k32e = new int[MAX_KEY_BITS / 64]; // 4 @@ -387,6 +380,7 @@ private int F32(int x, int[] k32) gMDS3[(P[P_31 * 256 + (P[P_32 * 256 + b3] & 0xff) ^ M_b3(k1)] & 0xff) ^ M_b3(k0)]; break; } + return result; } @@ -402,6 +396,7 @@ private int F32(int x, int[] k32) private static int RS_MDS_Encode(int k0, int k1) { var r = k1; + // shift 1 byte at a time r = RS_rem(r); r = RS_rem(r); @@ -432,7 +427,7 @@ private static int RS_rem(int x) ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff; var g3 = ((int)((uint)b >> 1) ^ ((b & 0x01) != 0 ? (int)((uint)RS_GF_FDBK >> 1) : 0)) ^ g2; - return ((x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b); + return (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b; } private static int LFSR1(int x) @@ -496,7 +491,7 @@ private static int Fe32_3(int[] gSBox1, int x) private static int BytesTo32Bits(byte[] b, int p) { - return ((b[p] & 0xff)) | + return (b[p] & 0xff) | ((b[p + 1] & 0xff) << 8) | ((b[p + 2] & 0xff) << 16) | ((b[p + 3] & 0xff) << 24); diff --git a/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs index 06275bdad..be84f7f83 100644 --- a/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs @@ -1,5 +1,6 @@ 锘縰sing System; using System.Security.Cryptography; + using Renci.SshNet.Abstractions; using Renci.SshNet.Common; @@ -10,9 +11,9 @@ namespace Renci.SshNet.Security.Cryptography ///
public class DsaDigitalSignature : DigitalSignature, IDisposable { - private HashAlgorithm _hash; - private readonly DsaKey _key; + private HashAlgorithm _hash; + private bool _isDisposed; /// /// Initializes a new instance of the class. @@ -22,7 +23,9 @@ public class DsaDigitalSignature : DigitalSignature, IDisposable public DsaDigitalSignature(DsaKey key) { if (key == null) - throw new ArgumentNullException("key"); + { + throw new ArgumentNullException(nameof(key)); + } _key = key; @@ -45,9 +48,11 @@ public override bool Verify(byte[] input, byte[] signature) var hm = new BigInteger(hashInput.Reverse().Concat(new byte[] { 0 })); if (signature.Length != 40) + { throw new InvalidOperationException("Invalid signature."); + } - // Extract r and s numbers from the signature + // Extract r and s numbers from the signature var rBytes = new byte[21]; var sBytes = new byte[21]; @@ -60,29 +65,33 @@ public override bool Verify(byte[] input, byte[] signature) var r = new BigInteger(rBytes); var s = new BigInteger(sBytes); - // Reject the signature if 0 < r < q or 0 < s < q is not satisfied. + // Reject the signature if 0 < r < q or 0 < s < q is not satisfied. if (r <= 0 || r >= _key.Q) + { return false; + } if (s <= 0 || s >= _key.Q) + { return false; + } - // Calculate w = s鈭1 mod q + // Calculate w = s鈭1 mod q var w = BigInteger.ModInverse(s, _key.Q); - // Calculate u1 = H(m)路w mod q + // Calculate u1 = H(m)路w mod q var u1 = hm * w % _key.Q; - // Calculate u2 = r * w mod q + // Calculate u2 = r * w mod q var u2 = r * w % _key.Q; u1 = BigInteger.ModPow(_key.G, u1, _key.P); u2 = BigInteger.ModPow(_key.Y, u2, _key.P); - // Calculate v = ((g pow u1 * y pow u2) mod p) mod q + // Calculate v = ((g pow u1 * y pow u2) mod p) mod q var v = ((u1 * u2) % _key.P) % _key.Q; - // The signature is valid if v = r + // The signature is valid if v = r return v == r; } @@ -105,37 +114,40 @@ public override byte[] Sign(byte[] input) do { - BigInteger k = BigInteger.Zero; + var k = BigInteger.Zero; do { - // Generate a random per-message value k where 0 < k < q + // Generate a random per-message value k where 0 < k < q var bitLength = _key.Q.BitLength; if (_key.Q < BigInteger.Zero) + { throw new SshException("Invalid DSA key."); + } while (k <= 0 || k >= _key.Q) { k = BigInteger.Random(bitLength); } - // Calculate r = ((g pow k) mod p) mod q + // Calculate r = ((g pow k) mod p) mod q r = BigInteger.ModPow(_key.G, k, _key.P) % _key.Q; - // In the unlikely case that r = 0, start again with a different random k - } while (r.IsZero); - + // In the unlikely case that r = 0, start again with a different random k + } + while (r.IsZero); - // Calculate s = ((k pow 鈭1)(H(m) + x*r)) mod q - k = (BigInteger.ModInverse(k, _key.Q) * (m + _key.X * r)); + // Calculate s = ((k pow 鈭1)(H(m) + x*r)) mod q + k = BigInteger.ModInverse(k, _key.Q) * (m + (_key.X * r)); s = k % _key.Q; - // In the unlikely case that s = 0, start again with a different random k - } while (s.IsZero); + // In the unlikely case that s = 0, start again with a different random k + } + while (s.IsZero); - // The signature is (r, s) + // The signature is (r, s) var signature = new byte[40]; // issue #1918: pad part with zero's on the left if length is less than 20 @@ -149,27 +161,25 @@ public override byte[] Sign(byte[] input) return signature; } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -185,14 +195,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~DsaDigitalSignature() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } } diff --git a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs index 5e9907f7b..bfb185a65 100644 --- a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs @@ -5,10 +5,13 @@ namespace Renci.SshNet.Security { /// - /// Contains DSA private and public key + /// Contains DSA private and public key. /// public class DsaKey : Key, IDisposable { + private DsaDigitalSignature _digitalSignature; + private bool _isDisposed; + /// /// Gets the P. /// @@ -78,7 +81,6 @@ public override int KeyLength } } - private DsaDigitalSignature _digitalSignature; /// /// Gets the digital signature. /// @@ -86,10 +88,7 @@ protected override DigitalSignature DigitalSignature { get { - if (_digitalSignature == null) - { - _digitalSignature = new DsaDigitalSignature(this); - } + _digitalSignature ??= new DsaDigitalSignature(this); return _digitalSignature; } } @@ -109,7 +108,9 @@ public override BigInteger[] Public set { if (value.Length != 4) + { throw new InvalidOperationException("Invalid public key."); + } _privateKey = value; } @@ -131,7 +132,9 @@ public DsaKey(byte[] data) : base(data) { if (_privateKey.Length != 5) + { throw new InvalidOperationException("Invalid private key."); + } } /// @@ -152,16 +155,12 @@ public DsaKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y, BigInteger _privateKey[4] = x; } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } @@ -172,7 +171,9 @@ public void Dispose() protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -188,14 +189,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~DsaKey() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } } diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs index be68fd481..4e32772e2 100644 --- a/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs @@ -10,6 +10,7 @@ namespace Renci.SshNet.Security.Cryptography public class ED25519DigitalSignature : DigitalSignature, IDisposable { private readonly ED25519Key _key; + private bool _isDisposed; /// /// Initializes a new instance of the class. @@ -19,7 +20,9 @@ public class ED25519DigitalSignature : DigitalSignature, IDisposable public ED25519DigitalSignature(ED25519Key key) { if (key == null) - throw new ArgumentNullException("key"); + { + throw new ArgumentNullException(nameof(key)); + } _key = key; } @@ -51,16 +54,12 @@ public override byte[] Sign(byte[] input) return Ed25519.Sign(input, _key.PrivateKey); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } @@ -71,7 +70,9 @@ public void Dispose() protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -80,14 +81,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~ED25519DigitalSignature() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs index 15f1cb019..8e0862f4d 100644 --- a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs @@ -1,19 +1,21 @@ 锘縰sing System; + using Renci.SshNet.Common; -using Renci.SshNet.Security.Cryptography; using Renci.SshNet.Security.Chaos.NaCl; +using Renci.SshNet.Security.Cryptography; namespace Renci.SshNet.Security { /// - /// Contains ED25519 private and public key + /// Contains ED25519 private and public key. /// public class ED25519Key : Key, IDisposable { private ED25519DigitalSignature _digitalSignature; private byte[] publicKey = new byte[Ed25519.PublicKeySizeInBytes]; - private byte[] privateKey = new byte[Ed25519.ExpandedPrivateKeySizeInBytes]; + private readonly byte[] privateKey = new byte[Ed25519.ExpandedPrivateKeySizeInBytes]; + private bool _isDisposed; /// /// Gets the Key String. @@ -62,16 +64,13 @@ protected override DigitalSignature DigitalSignature { get { - if (_digitalSignature == null) - { - _digitalSignature = new ED25519DigitalSignature(this); - } + _digitalSignature ??= new ED25519DigitalSignature(this); return _digitalSignature; } } /// - /// Gets the PublicKey Bytes + /// Gets the PublicKey Bytes. /// public byte[] PublicKey { @@ -82,7 +81,7 @@ public byte[] PublicKey } /// - /// Gets the PrivateKey Bytes + /// Gets the PrivateKey Bytes. /// public byte[] PrivateKey { @@ -121,16 +120,12 @@ public ED25519Key(byte[] pk, byte[] sk) Ed25519.KeyPairFromSeed(out publicKey, out privateKey, seed); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } @@ -141,7 +136,9 @@ public void Dispose() protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -150,14 +147,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~ED25519Key() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } } diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs index b5561b5da..e358c1ecf 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs @@ -1,7 +1,10 @@ 锘縰sing System; -using Renci.SshNet.Common; using System.Globalization; +#if NETFRAMEWORK using System.Security.Cryptography; +#endif // NETFRAMEWORK + +using Renci.SshNet.Common; namespace Renci.SshNet.Security.Cryptography { @@ -11,6 +14,7 @@ namespace Renci.SshNet.Security.Cryptography public class EcdsaDigitalSignature : DigitalSignature, IDisposable { private readonly EcdsaKey _key; + private bool _isDisposed; /// /// Initializes a new instance of the class. @@ -20,7 +24,9 @@ public class EcdsaDigitalSignature : DigitalSignature, IDisposable public EcdsaDigitalSignature(EcdsaKey key) { if (key == null) - throw new ArgumentNullException("key"); + { + throw new ArgumentNullException(nameof(key)); + } _key = key; } @@ -63,21 +69,16 @@ public override byte[] Sign(byte[] input) #else var signed = _key.Ecdsa.SignData(input, _key.HashAlgorithm); #endif - var ssh_data = new SshDataSignature(signed.Length); - ssh_data.Signature = signed; + var ssh_data = new SshDataSignature(signed.Length) { Signature = signed }; return ssh_data.GetBytes(); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } @@ -88,7 +89,9 @@ public void Dispose() protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -97,20 +100,17 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~EcdsaDigitalSignature() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } - class SshDataSignature : SshData + internal class SshDataSignature : SshData { - private int _signature_size; + private readonly int _signature_size; private byte[] _signature_r; private byte[] _signature_s; diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs index 1674a6677..0a5da1963 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -1,15 +1,20 @@ 锘縰sing System; +#if NETFRAMEWORK using System.IO; +#endif // NETFRAMEWORK using System.Text; +#if NETFRAMEWORK using System.Runtime.InteropServices; +#endif // NETFRAMEWORK using System.Security.Cryptography; + using Renci.SshNet.Common; using Renci.SshNet.Security.Cryptography; namespace Renci.SshNet.Security { /// - /// Contains ECDSA (ecdsa-sha2-nistp{256,384,521}) private and public key + /// Contains ECDSA (ecdsa-sha2-nistp{256,384,521}) private and public key. /// public class EcdsaKey : Key, IDisposable { @@ -17,6 +22,9 @@ public class EcdsaKey : Key, IDisposable internal const string ECDSA_P384_OID_VALUE = "1.3.132.0.34"; // Also called nistP384 or secP384r1 internal const string ECDSA_P521_OID_VALUE = "1.3.132.0.35"; // Also called nistP521or secP521r1 + private EcdsaDigitalSignature _digitalSignature; + private bool _isDisposed; + #if NETFRAMEWORK internal enum KeyBlobMagicNumber : int { @@ -49,8 +57,11 @@ internal struct BCRYPT_ECCKEY_BLOB #endif /// - /// Gets the SSH name of the ECDSA Key + /// Gets the SSH name of the ECDSA Key. /// + /// + /// The SSH name of the ECDSA Key. + /// public override string ToString() { return string.Format("ecdsa-sha2-nistp{0}", KeyLength); @@ -79,7 +90,7 @@ public CngAlgorithm HashAlgorithm } #else /// - /// Gets the HashAlgorithm to use + /// Gets the HashAlgorithm to use. /// public HashAlgorithmName HashAlgorithm { @@ -94,6 +105,7 @@ public HashAlgorithmName HashAlgorithm case 521: return HashAlgorithmName.SHA512; } + return HashAlgorithmName.SHA256; } } @@ -113,8 +125,6 @@ public override int KeyLength } } - private EcdsaDigitalSignature _digitalSignature; - /// /// Gets the digital signature. /// @@ -122,10 +132,8 @@ protected override DigitalSignature DigitalSignature { get { - if (_digitalSignature == null) - { - _digitalSignature = new EcdsaDigitalSignature(this); - } + _digitalSignature ??= new EcdsaDigitalSignature(this); + return _digitalSignature; } } @@ -150,7 +158,7 @@ public override BigInteger[] Public using (var br = new BinaryReader(new MemoryStream(blob))) { magic = (KeyBlobMagicNumber)br.ReadInt32(); - int cbKey = br.ReadInt32(); + var cbKey = br.ReadInt32(); qx = br.ReadBytes(cbKey); qy = br.ReadBytes(cbKey); } @@ -191,6 +199,7 @@ public override BigInteger[] Public throw new SshException("Unexpected Curve Name: " + parameter.Curve.Oid.FriendlyName); } #endif + // Make ECPoint from x and y // Prepend 04 (uncompressed format) + qx-bytes + qy-bytes var q = new byte[1 + qx.Length + qy.Length]; @@ -204,7 +213,7 @@ public override BigInteger[] Public set { var curve_s = Encoding.ASCII.GetString(value[0].ToByteArray().Reverse()); - string curve_oid = GetCurveOid(curve_s); + var curve_oid = GetCurveOid(curve_s); var publickey = value[1].ToByteArray().Reverse(); Import(curve_oid, publickey, null); @@ -212,12 +221,12 @@ public override BigInteger[] Public } /// - /// Gets the PrivateKey Bytes + /// Gets the PrivateKey Bytes. /// public byte[] PrivateKey { get; private set; } /// - /// Gets ECDsa Object + /// Gets the object. /// public ECDsa Ecdsa { get; private set; } @@ -231,9 +240,9 @@ public EcdsaKey() /// /// Initializes a new instance of the class. /// - /// The curve name - /// Value of publickey - /// Value of privatekey + /// The curve name. + /// Value of publickey. + /// Value of privatekey. public EcdsaKey(string curve, byte[] publickey, byte[] privatekey) { Import(GetCurveOid(curve), publickey, privatekey); @@ -246,7 +255,7 @@ public EcdsaKey(string curve, byte[] publickey, byte[] privatekey) public EcdsaKey(byte[] data) { var der = new DerData(data); - var version = der.ReadBigInteger(); // skip version + _ = der.ReadBigInteger(); // skip version // PrivateKey var privatekey = der.ReadOctetString().TrimLeadingZeros(); @@ -254,10 +263,16 @@ public EcdsaKey(byte[] data) // Construct var s0 = der.ReadByte(); if ((s0 & 0xe0) != 0xa0) + { throw new SshException(string.Format("UnexpectedDER: wanted constructed tag (0xa0-0xbf), got: {0:X}", s0)); + } + var tag = s0 & 0x1f; if (tag != 0) + { throw new SshException(string.Format("expected tag 0 in DER privkey, got: {0}", tag)); + } + var construct = der.ReadBytes(der.ReadLength()); // object length // curve OID @@ -267,10 +282,16 @@ public EcdsaKey(byte[] data) // Construct s0 = der.ReadByte(); if ((s0 & 0xe0) != 0xa0) + { throw new SshException(string.Format("UnexpectedDER: wanted constructed tag (0xa0-0xbf), got: {0:X}", s0)); + } + tag = s0 & 0x1f; if (tag != 1) + { throw new SshException(string.Format("expected tag 1 in DER privkey, got: {0}", tag)); + } + construct = der.ReadBytes(der.ReadLength()); // object length // PublicKey @@ -288,21 +309,36 @@ private void Import(string curve_oid, byte[] publickey, byte[] privatekey) { case "nistp256": if (privatekey != null) + { curve_magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P256_MAGIC; + } else + { curve_magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P256_MAGIC; + } + break; case "nistp384": if (privatekey != null) + { curve_magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P384_MAGIC; + } else + { curve_magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P384_MAGIC; + } + break; case "nistp521": if (privatekey != null) + { curve_magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PRIVATE_P521_MAGIC; + } else + { curve_magic = KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P521_MAGIC; + } + break; default: throw new SshException("Unknown: " + curve_oid); @@ -322,12 +358,14 @@ private void Import(string curve_oid, byte[] publickey, byte[] privatekey) PrivateKey = privatekey; } - int headerSize = Marshal.SizeOf(typeof(BCRYPT_ECCKEY_BLOB)); - int blobSize = headerSize + qx.Length + qy.Length; + var headerSize = Marshal.SizeOf(typeof(BCRYPT_ECCKEY_BLOB)); + var blobSize = headerSize + qx.Length + qy.Length; if (privatekey != null) + { blobSize += privatekey.Length; + } - byte[] blob = new byte[blobSize]; + var blob = new byte[blobSize]; using (var bw = new BinaryWriter(new MemoryStream(blob))) { bw.Write((int)curve_magic); @@ -335,7 +373,9 @@ private void Import(string curve_oid, byte[] publickey, byte[] privatekey) bw.Write(qx); // q.x bw.Write(qy); // q.y if (privatekey != null) + { bw.Write(privatekey); // d + } } key = CngKey.Import(blob, privatekey == null ? CngKeyBlobFormat.EccPublicBlob : CngKeyBlobFormat.EccPrivateBlob); @@ -368,7 +408,7 @@ private void Import(string curve_oid, byte[] publickey, byte[] privatekey) #endif } - private string GetCurveOid(string curve_s) + private static string GetCurveOid(string curve_s) { switch (curve_s.ToLower()) { @@ -383,6 +423,7 @@ private string GetCurveOid(string curve_s) } } +#if NETFRAMEWORK private string GetCurveName(string oid) { switch (oid) @@ -397,27 +438,29 @@ private string GetCurveName(string oid) throw new SshException("Unexpected OID: " + oid); } } +#endif // NETFRAMEWORK - private string OidByteArrayToString(byte[] oid) + private static string OidByteArrayToString(byte[] oid) { - StringBuilder retVal = new StringBuilder(); + var retVal = new StringBuilder(); - for (int i = 0; i < oid.Length; i++) + for (var i = 0; i < oid.Length; i++) { if (i == 0) { - int b = oid[0] % 40; - int a = (oid[0] - b) / 40; - retVal.AppendFormat("{0}.{1}", a, b); + var b = oid[0] % 40; + var a = (oid[0] - b) / 40; + _ = retVal.AppendFormat("{0}.{1}", a, b); } else { if (oid[i] < 128) - retVal.AppendFormat(".{0}", oid[i]); + { + _ = retVal.AppendFormat(".{0}", oid[i]); + } else { - retVal.AppendFormat(".{0}", - ((oid[i] - 128) * 128) + oid[i + 1]); + _ = retVal.AppendFormat(".{0}", ((oid[i] - 128) * 128) + oid[i + 1]); i++; } } @@ -426,27 +469,25 @@ private string OidByteArrayToString(byte[] oid) return retVal.ToString(); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -455,14 +496,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~EcdsaKey() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } } diff --git a/src/Renci.SshNet/Security/Cryptography/HMACSHA1.cs b/src/Renci.SshNet/Security/Cryptography/HMACSHA1.cs index 49ad384d4..05a9730ed 100644 --- a/src/Renci.SshNet/Security/Cryptography/HMACSHA1.cs +++ b/src/Renci.SshNet/Security/Cryptography/HMACSHA1.cs @@ -1,4 +1,5 @@ 锘縰sing System.Security.Cryptography; + using Renci.SshNet.Common; namespace Renci.SshNet.Security.Cryptography @@ -11,7 +12,7 @@ public class HMACSHA1 : System.Security.Cryptography.HMACSHA1 private readonly int _hashSize; /// - /// Initializes a with the specified key. + /// Initializes a new instance of the class with the specified key. /// /// The key. public HMACSHA1(byte[] key) @@ -21,7 +22,7 @@ public HMACSHA1(byte[] key) } /// - /// Initializes a with the specified key and size of the computed hash code. + /// Initializes a new instance of the class with the specified key and size of the computed hash code. /// /// The key. /// The size, in bits, of the computed hash code. diff --git a/src/Renci.SshNet/Security/Cryptography/Key.cs b/src/Renci.SshNet/Security/Cryptography/Key.cs index 61c5150c2..6f5a6312b 100644 --- a/src/Renci.SshNet/Security/Cryptography/Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/Key.cs @@ -1,17 +1,18 @@ 锘縰sing System; using System.Collections.Generic; + using Renci.SshNet.Common; using Renci.SshNet.Security.Cryptography; namespace Renci.SshNet.Security { /// - /// Base class for asymmetric cipher algorithms + /// Base class for asymmetric cipher algorithms. /// public abstract class Key { /// - /// Specifies array of big integers that represent private key + /// Specifies array of big integers that represent private key. /// protected BigInteger[] _privateKey; @@ -37,7 +38,7 @@ public abstract class Key public abstract int KeyLength { get; } /// - /// Gets the Key Comment + /// Gets or sets the key comment. /// public string Comment { get; set; } @@ -48,10 +49,12 @@ public abstract class Key protected Key(byte[] data) { if (data == null) - throw new ArgumentNullException("data"); + { + throw new ArgumentNullException(nameof(data)); + } var der = new DerData(data); - der.ReadBigInteger(); // skip version + _ = der.ReadBigInteger(); // skip version var keys = new List(); while (!der.IsEndOfData) diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs index ba5b17464..b80e4302c 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs @@ -174,7 +174,6 @@ public override BigInteger[] Public /// public RsaKey() { - } /// @@ -212,7 +211,7 @@ public RsaKey(BigInteger modulus, BigInteger exponent, BigInteger d, BigInteger private static BigInteger PrimeExponent(BigInteger privateExponent, BigInteger prime) { - BigInteger pe = prime - new BigInteger(1); + var pe = prime - new BigInteger(1); return privateExponent % pe; } diff --git a/src/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs b/src/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs index a1c8a2a90..f4e35c375 100644 --- a/src/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs @@ -20,7 +20,9 @@ public abstract class SymmetricCipher : Cipher protected SymmetricCipher(byte[] key) { if (key == null) - throw new ArgumentNullException("key"); + { + throw new ArgumentNullException(nameof(key)); + } Key = key; } diff --git a/src/Renci.SshNet/Security/IKeyExchange.cs b/src/Renci.SshNet/Security/IKeyExchange.cs index b6f9bb080..f12a18322 100644 --- a/src/Renci.SshNet/Security/IKeyExchange.cs +++ b/src/Renci.SshNet/Security/IKeyExchange.cs @@ -1,5 +1,6 @@ 锘縰sing System; using System.Security.Cryptography; + using Renci.SshNet.Common; using Renci.SshNet.Compression; using Renci.SshNet.Messages.Transport; diff --git a/src/Renci.SshNet/Security/KeyExchange.cs b/src/Renci.SshNet/Security/KeyExchange.cs index a13c272a6..92a61973f 100644 --- a/src/Renci.SshNet/Security/KeyExchange.cs +++ b/src/Renci.SshNet/Security/KeyExchange.cs @@ -24,7 +24,7 @@ public abstract class KeyExchange : Algorithm, IKeyExchange private Type _decompressionType; /// - /// Gets or sets the session. + /// Gets the session. /// /// /// The session. @@ -53,6 +53,7 @@ public byte[] ExchangeHash { _exchangeHash = CalculateHash(); } + return _exchangeHash; } } @@ -63,7 +64,7 @@ public byte[] ExchangeHash public event EventHandler HostKeyReceived; /// - /// Starts key exchange algorithm + /// Starts key exchange algorithm. /// /// The session. /// Key exchange init message. @@ -73,7 +74,7 @@ public virtual void Start(Session session, KeyExchangeInitMessage message) SendMessage(session.ClientInitMessage); - // Determine encryption algorithm + // Determine encryption algorithm var clientEncryptionAlgorithmName = (from b in session.ConnectionInfo.Encryptions.Keys from a in message.EncryptionAlgorithmsClientToServer where a == b @@ -86,7 +87,7 @@ from a in message.EncryptionAlgorithmsClientToServer session.ConnectionInfo.CurrentClientEncryption = clientEncryptionAlgorithmName; - // Determine encryption algorithm + // Determine encryption algorithm var serverDecryptionAlgorithmName = (from b in session.ConnectionInfo.Encryptions.Keys from a in message.EncryptionAlgorithmsServerToClient where a == b @@ -98,7 +99,7 @@ from a in message.EncryptionAlgorithmsServerToClient session.ConnectionInfo.CurrentServerEncryption = serverDecryptionAlgorithmName; - // Determine client hmac algorithm + // Determine client hmac algorithm var clientHmacAlgorithmName = (from b in session.ConnectionInfo.HmacAlgorithms.Keys from a in message.MacAlgorithmsClientToServer where a == b @@ -110,7 +111,7 @@ from a in message.MacAlgorithmsClientToServer session.ConnectionInfo.CurrentClientHmacAlgorithm = clientHmacAlgorithmName; - // Determine server hmac algorithm + // Determine server hmac algorithm var serverHmacAlgorithmName = (from b in session.ConnectionInfo.HmacAlgorithms.Keys from a in message.MacAlgorithmsServerToClient where a == b @@ -122,7 +123,7 @@ from a in message.MacAlgorithmsServerToClient session.ConnectionInfo.CurrentServerHmacAlgorithm = serverHmacAlgorithmName; - // Determine compression algorithm + // Determine compression algorithm var compressionAlgorithmName = (from b in session.ConnectionInfo.CompressionAlgorithms.Keys from a in message.CompressionAlgorithmsClientToServer where a == b @@ -134,7 +135,7 @@ from a in message.CompressionAlgorithmsClientToServer session.ConnectionInfo.CurrentClientCompressionAlgorithm = compressionAlgorithmName; - // Determine decompression algorithm + // Determine decompression algorithm var decompressionAlgorithmName = (from b in session.ConnectionInfo.CompressionAlgorithms.Keys from a in message.CompressionAlgorithmsServerToClient where a == b @@ -159,15 +160,12 @@ from a in message.CompressionAlgorithmsServerToClient /// public virtual void Finish() { - // Validate hash - if (ValidateExchangeHash()) - { - SendMessage(new NewKeysMessage()); - } - else + if (!ValidateExchangeHash()) { throw new SshConnectionException("Key exchange negotiation failed.", DisconnectReason.KeyExchangeFailed); } + + SendMessage(new NewKeysMessage()); } /// @@ -176,13 +174,13 @@ public virtual void Finish() /// Server cipher. public Cipher CreateServerCipher() { - // Resolve Session ID + // Resolve Session ID var sessionId = Session.SessionId ?? ExchangeHash; - // Calculate server to client initial IV + // Calculate server to client initial IV var serverVector = Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'B', sessionId)); - // Calculate server to client encryption + // Calculate server to client encryption var serverKey = Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'D', sessionId)); serverKey = GenerateSessionKey(SharedKey, ExchangeHash, serverKey, _serverCipherInfo.KeySize / 8); @@ -193,7 +191,7 @@ public Cipher CreateServerCipher() Session.ToHex(serverKey), Session.ToHex(serverVector))); - // Create server cipher + // Create server cipher return _serverCipherInfo.Cipher(serverKey, serverVector); } @@ -203,63 +201,71 @@ public Cipher CreateServerCipher() /// Client cipher. public Cipher CreateClientCipher() { - // Resolve Session ID + // Resolve Session ID var sessionId = Session.SessionId ?? ExchangeHash; - // Calculate client to server initial IV + // Calculate client to server initial IV var clientVector = Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'A', sessionId)); - // Calculate client to server encryption + // Calculate client to server encryption var clientKey = Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'C', sessionId)); clientKey = GenerateSessionKey(SharedKey, ExchangeHash, clientKey, _clientCipherInfo.KeySize / 8); - // Create client cipher + // Create client cipher return _clientCipherInfo.Cipher(clientKey, clientVector); } /// /// Creates the server side hash algorithm to use. /// - /// Hash algorithm + /// + /// The server-side hash algorithm. + /// public HashAlgorithm CreateServerHash() { - // Resolve Session ID + // Resolve Session ID var sessionId = Session.SessionId ?? ExchangeHash; - var serverKey = Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'F', sessionId)); + var serverKey = GenerateSessionKey(SharedKey, + ExchangeHash, + Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'F', sessionId)), + _serverHashInfo.KeySize / 8); - serverKey = GenerateSessionKey(SharedKey, ExchangeHash, serverKey, _serverHashInfo.KeySize / 8); - - //return serverHMac; return _serverHashInfo.HashAlgorithm(serverKey); } /// /// Creates the client side hash algorithm to use. /// - /// Hash algorithm + /// + /// The client-side hash algorithm. + /// public HashAlgorithm CreateClientHash() { - // Resolve Session ID + // Resolve Session ID var sessionId = Session.SessionId ?? ExchangeHash; - var clientKey = Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'E', sessionId)); - - clientKey = GenerateSessionKey(SharedKey, ExchangeHash, clientKey, _clientHashInfo.KeySize / 8); + var clientKey = GenerateSessionKey(SharedKey, + ExchangeHash, + Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'E', sessionId)), + _clientHashInfo.KeySize / 8); - //return clientHMac; return _clientHashInfo.HashAlgorithm(clientKey); } /// /// Creates the compression algorithm to use to deflate data. /// - /// Compression method. + /// + /// The compression method. + /// public Compressor CreateCompressor() { if (_compressionType == null) + { return null; + } var compressor = _compressionType.CreateInstance(); @@ -271,11 +277,15 @@ public Compressor CreateCompressor() /// /// Creates the compression algorithm to use to inflate data. /// - /// Compression method. + /// + /// The decompression method. + /// public Compressor CreateDecompressor() { - if (_compressionType == null) + if (_decompressionType == null) + { return null; + } var decompressor = _decompressionType.CreateInstance(); @@ -321,12 +331,12 @@ protected bool CanTrustHostKey(KeyHostAlgorithm host) /// /// The hash data. /// - /// Hashed bytes + /// The hash of the data. /// protected abstract byte[] Hash(byte[] hashData); /// - /// Sends SSH message to the server + /// Sends SSH message to the server. /// /// The message. protected void SendMessage(Message message) @@ -341,7 +351,9 @@ protected void SendMessage(Message message) /// The exchange hash. /// The key. /// The size. - /// + /// + /// The session key. + /// private byte[] GenerateSessionKey(byte[] sharedKey, byte[] exchangeHash, byte[] key, int size) { var result = new List(key); @@ -368,7 +380,9 @@ private byte[] GenerateSessionKey(byte[] sharedKey, byte[] exchangeHash, byte[] /// The exchange hash. /// The p. /// The session id. - /// + /// + /// The session key. + /// private static byte[] GenerateSessionKey(byte[] sharedKey, byte[] exchangeHash, char p, byte[] sessionId) { var sessionKeyGeneration = new SessionKeyGeneration @@ -381,7 +395,7 @@ private static byte[] GenerateSessionKey(byte[] sharedKey, byte[] exchangeHash, return sessionKeyGeneration.GetBytes(); } - private class SessionKeyGeneration : SshData + private sealed class SessionKeyGeneration : SshData { public byte[] SharedKey { get; set; } @@ -425,7 +439,7 @@ protected override void SaveData() } } - private class SessionKeyAdjustment : SshData + private sealed class SessionKeyAdjustment : SshData { public byte[] SharedKey { get; set; } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs index 375c3a59d..836c607f3 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs @@ -1,7 +1,8 @@ 锘縰sing System; using System.Text; -using Renci.SshNet.Messages.Transport; + using Renci.SshNet.Common; +using Renci.SshNet.Messages.Transport; namespace Renci.SshNet.Security { @@ -21,7 +22,7 @@ internal abstract class KeyExchangeDiffieHellman : KeyExchange protected BigInteger _prime; /// - /// Specifies client payload + /// Specifies client payload. /// protected byte[] _clientPayload; @@ -83,11 +84,12 @@ protected override bool ValidateExchangeHash() { return key.VerifySignature(exchangeHash, _signature); } + return false; } /// - /// Starts key exchange algorithm + /// Starts key exchange algorithm. /// /// The session. /// Key exchange init message. @@ -105,10 +107,14 @@ public override void Start(Session session, KeyExchangeInitMessage message) protected void PopulateClientExchangeValue() { if (_group.IsZero) + { throw new ArgumentNullException("_group"); + } if (_prime.IsZero) + { throw new ArgumentNullException("_prime"); + } // generate private exponent that is twice the hash size (RFC 4419) with a minimum // of 1024 bits (whatever is less) @@ -118,11 +124,13 @@ protected void PopulateClientExchangeValue() do { - // create private component + // Create private component _privateExponent = BigInteger.Random(privateExponentSize); - // generate public component + + // Generate public component clientExchangeValue = BigInteger.ModPow(_group, _privateExponent, _prime); - } while (clientExchangeValue < 1 || clientExchangeValue > (_prime - 1)); + } + while (clientExchangeValue < 1 || clientExchangeValue > (_prime - 1)); _clientExchangeValue = clientExchangeValue.ToByteArray().Reverse(); } diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha1.cs index ec7a237dd..be0bfe745 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha1.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha1.cs @@ -5,10 +5,10 @@ namespace Renci.SshNet.Security /// /// Represents "diffie-hellman-group14-sha1" algorithm implementation. /// - internal class KeyExchangeDiffieHellmanGroup14Sha1 : KeyExchangeDiffieHellmanGroupSha1 + internal sealed class KeyExchangeDiffieHellmanGroup14Sha1 : KeyExchangeDiffieHellmanGroupSha1 { /// - /// https://tools.ietf.org/html/rfc2409#section-6.2 + /// Defined in https://tools.ietf.org/html/rfc2409#section-6.2. /// private static readonly byte[] SecondOkleyGroupReversed = { @@ -59,4 +59,4 @@ public override BigInteger GroupPrime } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha256.cs index 276077a09..9687875e7 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha256.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup14Sha256.cs @@ -5,10 +5,10 @@ namespace Renci.SshNet.Security /// /// Represents "diffie-hellman-group14-sha256" algorithm implementation. /// - internal class KeyExchangeDiffieHellmanGroup14Sha256 : KeyExchangeDiffieHellmanGroupSha256 + internal sealed class KeyExchangeDiffieHellmanGroup14Sha256 : KeyExchangeDiffieHellmanGroupSha256 { /// - /// https://tools.ietf.org/html/rfc2409#section-6.2 + /// Defined in https://tools.ietf.org/html/rfc2409#section-6.2. /// private static readonly byte[] SecondOkleyGroupReversed = { @@ -59,4 +59,4 @@ public override BigInteger GroupPrime } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup16Sha512.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup16Sha512.cs index 48f7e178a..ba8403fec 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup16Sha512.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup16Sha512.cs @@ -5,45 +5,45 @@ namespace Renci.SshNet.Security /// /// Represents "diffie-hellman-group16-sha512" algorithm implementation. /// - internal class KeyExchangeDiffieHellmanGroup16Sha512 : KeyExchangeDiffieHellmanGroupSha512 + internal sealed class KeyExchangeDiffieHellmanGroup16Sha512 : KeyExchangeDiffieHellmanGroupSha512 { /// - /// https://tools.ietf.org/html/rfc3526#section-5 + /// Defined in https://tools.ietf.org/html/rfc3526#section-5. /// private static readonly byte[] MoreModularExponentialGroup16Reversed = { - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x99,0x31,0x06,0x34,0xc9,0x35,0xf4,0x4d, - 0x8f,0xc0,0xa6,0x90,0xdc,0xb7,0xff,0x86,0xc1,0xdd,0x8f,0x8d,0x98,0xea,0xb4,0x93, - 0xa9,0x5a,0xb0,0xd5,0x27,0x91,0x06,0xd0,0x1c,0x48,0x70,0x21,0x76,0xdd,0x1b,0xb8, - 0xaf,0xd7,0xe2,0xce,0x70,0x29,0x61,0x1f,0xed,0xe7,0x5b,0x51,0x86,0xa1,0x3b,0x23, - 0xa2,0xc3,0x90,0xa0,0x4f,0x96,0xb2,0x99,0x5d,0xc0,0x6b,0x4e,0x47,0x59,0x7c,0x28, - 0xa6,0xca,0xbe,0x1f,0x14,0xfc,0x8e,0x2e,0xf9,0x8e,0xde,0x04,0xdb,0xc2,0xbb,0xdb, - 0xe8,0x4c,0xd4,0x2a,0xca,0xe9,0x83,0x25,0xda,0x0b,0x15,0xb6,0x34,0x68,0x94,0x1a, - 0x3c,0xe2,0xf4,0x6a,0x18,0x27,0xc3,0x99,0x26,0x5b,0xba,0xbd,0x10,0x9a,0x71,0x88, - 0xd7,0xe6,0x87,0xa7,0x12,0x3c,0x72,0x1a,0x01,0x08,0x21,0xa9,0x20,0xd1,0x82,0x4b, - 0x8e,0x10,0xfd,0xe0,0xfc,0x5b,0xdb,0x43,0x31,0xab,0xe5,0x74,0xa0,0x4f,0xe2,0x08, - 0xe2,0x46,0xd9,0xba,0xc0,0x88,0x09,0x77,0x6c,0x5d,0x61,0x7a,0x57,0x17,0xe1,0xbb, - 0x0c,0x20,0x7b,0x17,0x18,0x2b,0x1f,0x52,0x64,0x6a,0xc8,0x3e,0x73,0x02,0x76,0xd8, - 0x64,0x08,0x8a,0xd9,0x06,0xfa,0x2f,0xf1,0x6b,0xee,0xd2,0x1a,0x26,0xd2,0xe3,0xce, - 0x9d,0x61,0x25,0x4a,0xe0,0x94,0x8c,0x1e,0xd7,0x33,0x09,0xdb,0x8c,0xae,0xf5,0xab, - 0xc7,0xe4,0xe1,0xa6,0x85,0x0f,0x97,0xb3,0x7d,0x0c,0x06,0x5d,0x57,0x71,0xea,0x8a, - 0x0a,0xef,0xdb,0x58,0x04,0x85,0xfb,0xec,0x64,0xba,0x1c,0xdf,0xab,0x21,0x55,0xa8, - 0x33,0x7a,0x50,0x04,0x0d,0x17,0x33,0xad,0x2d,0xc4,0xaa,0x8a,0x5a,0x8e,0x72,0x15, - 0x10,0x05,0xfa,0x98,0x18,0x26,0xd2,0x15,0xe5,0x6a,0x95,0xea,0x7c,0x49,0x95,0x39, - 0x18,0x17,0x58,0x95,0xf6,0xcb,0x2b,0xde,0xc9,0x52,0x4c,0x6f,0xf0,0x5d,0xc5,0xb5, - 0x8f,0xa2,0x07,0xec,0xa2,0x83,0x27,0x9b,0x03,0x86,0x0e,0x18,0x2c,0x77,0x9e,0xe3, - 0x3b,0xce,0x36,0x2e,0x46,0x5e,0x90,0x32,0x7c,0x21,0x18,0xca,0x08,0x6c,0x74,0xf1, - 0x04,0x98,0xbc,0x4a,0x4e,0x35,0x0c,0x67,0x6d,0x96,0x96,0x70,0x07,0x29,0xd5,0x9e, - 0xbb,0x52,0x85,0x20,0x56,0xf3,0x62,0x1c,0x96,0xad,0xa3,0xdc,0x23,0x5d,0x65,0x83, - 0x5f,0xcf,0x24,0xfd,0xa8,0x3f,0x16,0x69,0x9a,0xd3,0x55,0x1c,0x36,0x48,0xda,0x98, - 0x05,0xbf,0x63,0xa1,0xb8,0x7c,0x00,0xc2,0x3d,0x5b,0xe4,0xec,0x51,0x66,0x28,0x49, - 0xe6,0x1f,0x4b,0x7c,0x11,0x24,0x9f,0xae,0xa5,0x9f,0x89,0x5a,0xfb,0x6b,0x38,0xee, - 0xed,0xb7,0x06,0xf4,0xb6,0x5c,0xff,0x0b,0x6b,0xed,0x37,0xa6,0xe9,0x42,0x4c,0xf4, - 0xc6,0x7e,0x5e,0x62,0x76,0xb5,0x85,0xe4,0x45,0xc2,0x51,0x6d,0x6d,0x35,0xe1,0x4f, - 0x37,0x14,0x5f,0xf2,0x6d,0x0a,0x2b,0x30,0x1b,0x43,0x3a,0xcd,0xb3,0x19,0x95,0xef, - 0xdd,0x04,0x34,0x8e,0x79,0x08,0x4a,0x51,0x22,0x9b,0x13,0x3b,0xa6,0xbe,0x0b,0x02, - 0x74,0xcc,0x67,0x8a,0x08,0x4e,0x02,0x29,0xd1,0x1c,0xdc,0x80,0x8b,0x62,0xc6,0xc4, - 0x34,0xc2,0x68,0x21,0xa2,0xda,0x0f,0xc9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0x31, 0x06, 0x34, 0xc9, 0x35, 0xf4, 0x4d, + 0x8f, 0xc0, 0xa6, 0x90, 0xdc, 0xb7, 0xff, 0x86, 0xc1, 0xdd, 0x8f, 0x8d, 0x98, 0xea, 0xb4, 0x93, + 0xa9, 0x5a, 0xb0, 0xd5, 0x27, 0x91, 0x06, 0xd0, 0x1c, 0x48, 0x70, 0x21, 0x76, 0xdd, 0x1b, 0xb8, + 0xaf, 0xd7, 0xe2, 0xce, 0x70, 0x29, 0x61, 0x1f, 0xed, 0xe7, 0x5b, 0x51, 0x86, 0xa1, 0x3b, 0x23, + 0xa2, 0xc3, 0x90, 0xa0, 0x4f, 0x96, 0xb2, 0x99, 0x5d, 0xc0, 0x6b, 0x4e, 0x47, 0x59, 0x7c, 0x28, + 0xa6, 0xca, 0xbe, 0x1f, 0x14, 0xfc, 0x8e, 0x2e, 0xf9, 0x8e, 0xde, 0x04, 0xdb, 0xc2, 0xbb, 0xdb, + 0xe8, 0x4c, 0xd4, 0x2a, 0xca, 0xe9, 0x83, 0x25, 0xda, 0x0b, 0x15, 0xb6, 0x34, 0x68, 0x94, 0x1a, + 0x3c, 0xe2, 0xf4, 0x6a, 0x18, 0x27, 0xc3, 0x99, 0x26, 0x5b, 0xba, 0xbd, 0x10, 0x9a, 0x71, 0x88, + 0xd7, 0xe6, 0x87, 0xa7, 0x12, 0x3c, 0x72, 0x1a, 0x01, 0x08, 0x21, 0xa9, 0x20, 0xd1, 0x82, 0x4b, + 0x8e, 0x10, 0xfd, 0xe0, 0xfc, 0x5b, 0xdb, 0x43, 0x31, 0xab, 0xe5, 0x74, 0xa0, 0x4f, 0xe2, 0x08, + 0xe2, 0x46, 0xd9, 0xba, 0xc0, 0x88, 0x09, 0x77, 0x6c, 0x5d, 0x61, 0x7a, 0x57, 0x17, 0xe1, 0xbb, + 0x0c, 0x20, 0x7b, 0x17, 0x18, 0x2b, 0x1f, 0x52, 0x64, 0x6a, 0xc8, 0x3e, 0x73, 0x02, 0x76, 0xd8, + 0x64, 0x08, 0x8a, 0xd9, 0x06, 0xfa, 0x2f, 0xf1, 0x6b, 0xee, 0xd2, 0x1a, 0x26, 0xd2, 0xe3, 0xce, + 0x9d, 0x61, 0x25, 0x4a, 0xe0, 0x94, 0x8c, 0x1e, 0xd7, 0x33, 0x09, 0xdb, 0x8c, 0xae, 0xf5, 0xab, + 0xc7, 0xe4, 0xe1, 0xa6, 0x85, 0x0f, 0x97, 0xb3, 0x7d, 0x0c, 0x06, 0x5d, 0x57, 0x71, 0xea, 0x8a, + 0x0a, 0xef, 0xdb, 0x58, 0x04, 0x85, 0xfb, 0xec, 0x64, 0xba, 0x1c, 0xdf, 0xab, 0x21, 0x55, 0xa8, + 0x33, 0x7a, 0x50, 0x04, 0x0d, 0x17, 0x33, 0xad, 0x2d, 0xc4, 0xaa, 0x8a, 0x5a, 0x8e, 0x72, 0x15, + 0x10, 0x05, 0xfa, 0x98, 0x18, 0x26, 0xd2, 0x15, 0xe5, 0x6a, 0x95, 0xea, 0x7c, 0x49, 0x95, 0x39, + 0x18, 0x17, 0x58, 0x95, 0xf6, 0xcb, 0x2b, 0xde, 0xc9, 0x52, 0x4c, 0x6f, 0xf0, 0x5d, 0xc5, 0xb5, + 0x8f, 0xa2, 0x07, 0xec, 0xa2, 0x83, 0x27, 0x9b, 0x03, 0x86, 0x0e, 0x18, 0x2c, 0x77, 0x9e, 0xe3, + 0x3b, 0xce, 0x36, 0x2e, 0x46, 0x5e, 0x90, 0x32, 0x7c, 0x21, 0x18, 0xca, 0x08, 0x6c, 0x74, 0xf1, + 0x04, 0x98, 0xbc, 0x4a, 0x4e, 0x35, 0x0c, 0x67, 0x6d, 0x96, 0x96, 0x70, 0x07, 0x29, 0xd5, 0x9e, + 0xbb, 0x52, 0x85, 0x20, 0x56, 0xf3, 0x62, 0x1c, 0x96, 0xad, 0xa3, 0xdc, 0x23, 0x5d, 0x65, 0x83, + 0x5f, 0xcf, 0x24, 0xfd, 0xa8, 0x3f, 0x16, 0x69, 0x9a, 0xd3, 0x55, 0x1c, 0x36, 0x48, 0xda, 0x98, + 0x05, 0xbf, 0x63, 0xa1, 0xb8, 0x7c, 0x00, 0xc2, 0x3d, 0x5b, 0xe4, 0xec, 0x51, 0x66, 0x28, 0x49, + 0xe6, 0x1f, 0x4b, 0x7c, 0x11, 0x24, 0x9f, 0xae, 0xa5, 0x9f, 0x89, 0x5a, 0xfb, 0x6b, 0x38, 0xee, + 0xed, 0xb7, 0x06, 0xf4, 0xb6, 0x5c, 0xff, 0x0b, 0x6b, 0xed, 0x37, 0xa6, 0xe9, 0x42, 0x4c, 0xf4, + 0xc6, 0x7e, 0x5e, 0x62, 0x76, 0xb5, 0x85, 0xe4, 0x45, 0xc2, 0x51, 0x6d, 0x6d, 0x35, 0xe1, 0x4f, + 0x37, 0x14, 0x5f, 0xf2, 0x6d, 0x0a, 0x2b, 0x30, 0x1b, 0x43, 0x3a, 0xcd, 0xb3, 0x19, 0x95, 0xef, + 0xdd, 0x04, 0x34, 0x8e, 0x79, 0x08, 0x4a, 0x51, 0x22, 0x9b, 0x13, 0x3b, 0xa6, 0xbe, 0x0b, 0x02, + 0x74, 0xcc, 0x67, 0x8a, 0x08, 0x4e, 0x02, 0x29, 0xd1, 0x1c, 0xdc, 0x80, 0x8b, 0x62, 0xc6, 0xc4, + 0x34, 0xc2, 0x68, 0x21, 0xa2, 0xda, 0x0f, 0xc9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 }; diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup1Sha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup1Sha1.cs index 3a8de7f42..d0ff2c01d 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup1Sha1.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroup1Sha1.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Security /// /// Represents "diffie-hellman-group1-sha1" algorithm implementation. /// - internal class KeyExchangeDiffieHellmanGroup1Sha1 : KeyExchangeDiffieHellmanGroupSha1 + internal sealed class KeyExchangeDiffieHellmanGroup1Sha1 : KeyExchangeDiffieHellmanGroupSha1 { private static readonly byte[] SecondOkleyGroupReversed = { diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs index a7f1b7420..791e2c44b 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha1.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Security /// /// Represents "diffie-hellman-group-exchange-sha1" algorithm implementation. /// - internal class KeyExchangeDiffieHellmanGroupExchangeSha1 : KeyExchangeDiffieHellmanGroupExchangeShaBase + internal sealed class KeyExchangeDiffieHellmanGroupExchangeSha1 : KeyExchangeDiffieHellmanGroupExchangeShaBase { /// /// Gets algorithm name. @@ -31,7 +31,7 @@ protected override int HashSize /// /// The hash data. /// - /// Hashed bytes + /// The hash of the data. /// protected override byte[] Hash(byte[] hashData) { diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs index dca2de712..3302d9a94 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Security /// /// Represents "diffie-hellman-group-exchange-sha256" algorithm implementation. /// - internal class KeyExchangeDiffieHellmanGroupExchangeSha256 : KeyExchangeDiffieHellmanGroupExchangeShaBase + internal sealed class KeyExchangeDiffieHellmanGroupExchangeSha256 : KeyExchangeDiffieHellmanGroupExchangeShaBase { /// /// Gets algorithm name. @@ -31,7 +31,7 @@ protected override int HashSize /// /// Data to hash. /// - /// Hashed bytes + /// The hash of the data. /// protected override byte[] Hash(byte[] hashBytes) { diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs index 755f77f2e..93703ee8f 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs @@ -40,7 +40,7 @@ protected override byte[] CalculateHash() } /// - /// Starts key exchange algorithm + /// Starts key exchange algorithm. /// /// The session. /// Key exchange init message. @@ -50,6 +50,7 @@ public override void Start(Session session, KeyExchangeInitMessage message) // Register SSH_MSG_KEX_DH_GEX_GROUP message Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP"); + // Subscribe to KeyExchangeDhGroupExchangeGroupReceived events Session.KeyExchangeDhGroupExchangeGroupReceived += Session_KeyExchangeDhGroupExchangeGroupReceived; @@ -75,11 +76,13 @@ private void Session_KeyExchangeDhGroupExchangeGroupReceived(object sender, Mess // Unregister SSH_MSG_KEX_DH_GEX_GROUP message once received Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP"); + // Unsubscribe from KeyExchangeDhGroupExchangeGroupReceived events Session.KeyExchangeDhGroupExchangeGroupReceived -= Session_KeyExchangeDhGroupExchangeGroupReceived; // Register in order to be able to receive SSH_MSG_KEX_DH_GEX_REPLY message Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY"); + // Subscribe to KeyExchangeDhGroupExchangeReplyReceived events Session.KeyExchangeDhGroupExchangeReplyReceived += Session_KeyExchangeDhGroupExchangeReplyReceived; @@ -99,6 +102,7 @@ private void Session_KeyExchangeDhGroupExchangeReplyReceived(object sender, Mess // Unregister SSH_MSG_KEX_DH_GEX_REPLY message once received Session.UnRegisterMessage("SSH_MSG_KEX_DH_GEX_REPLY"); + // Unsubscribe from KeyExchangeDhGroupExchangeReplyReceived events Session.KeyExchangeDhGroupExchangeReplyReceived -= Session_KeyExchangeDhGroupExchangeReplyReceived; diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs index 675ee2cfe..4669eb8ae 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha1.cs @@ -23,7 +23,7 @@ protected override int HashSize /// /// The hash data. /// - /// Hashed bytes + /// The hash of the data. /// protected override byte[] Hash(byte[] hashData) { diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs index 6cb674601..ea29e6e2f 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha256.cs @@ -23,7 +23,7 @@ protected override int HashSize /// /// The hash data. /// - /// Hashed bytes + /// The hash of the data. /// protected override byte[] Hash(byte[] hashData) { @@ -33,4 +33,4 @@ protected override byte[] Hash(byte[] hashData) } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs index 54369b849..60a8e5f7c 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupSha512.cs @@ -23,7 +23,7 @@ protected override int HashSize /// /// The hash data. /// - /// Hashed bytes + /// The hash of the data. /// protected override byte[] Hash(byte[] hashData) { @@ -33,4 +33,4 @@ protected override byte[] Hash(byte[] hashData) } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs index 2618b63ac..63c2bba40 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs @@ -14,30 +14,7 @@ internal abstract class KeyExchangeDiffieHellmanGroupShaBase : KeyExchangeDiffie public abstract BigInteger GroupPrime { get; } /// - /// Calculates key exchange hash value. - /// - /// - /// Key exchange hash. - /// - protected override byte[] CalculateHash() - { - var keyExchangeHashData = new KeyExchangeHashData - { - ClientVersion = Session.ClientVersion, - ServerVersion = Session.ServerVersion, - ClientPayload = _clientPayload, - ServerPayload = _serverPayload, - HostKey = _hostKey, - ClientExchangeValue = _clientExchangeValue, - ServerExchangeValue = _serverExchangeValue, - SharedKey = SharedKey, - }; - - return Hash(keyExchangeHashData.GetBytes()); - } - - /// - /// Starts key exchange algorithm + /// Starts key exchange algorithm. /// /// The session. /// Key exchange init message. @@ -67,16 +44,39 @@ public override void Finish() Session.KeyExchangeDhReplyMessageReceived -= Session_KeyExchangeDhReplyMessageReceived; } + /// + /// Calculates key exchange hash value. + /// + /// + /// Key exchange hash. + /// + protected override byte[] CalculateHash() + { + var keyExchangeHashData = new KeyExchangeHashData + { + ClientVersion = Session.ClientVersion, + ServerVersion = Session.ServerVersion, + ClientPayload = _clientPayload, + ServerPayload = _serverPayload, + HostKey = _hostKey, + ClientExchangeValue = _clientExchangeValue, + ServerExchangeValue = _serverExchangeValue, + SharedKey = SharedKey, + }; + + return Hash(keyExchangeHashData.GetBytes()); + } + private void Session_KeyExchangeDhReplyMessageReceived(object sender, MessageEventArgs e) { var message = e.Message; - // Unregister message once received + // Unregister message once received Session.UnRegisterMessage("SSH_MSG_KEXDH_REPLY"); HandleServerDhReply(message.HostKey, message.F, message.Signature); - // When SSH_MSG_KEXDH_REPLY received key exchange is completed + // When SSH_MSG_KEXDH_REPLY received key exchange is completed Finish(); } } diff --git a/src/Renci.SshNet/Security/KeyExchangeEC.cs b/src/Renci.SshNet/Security/KeyExchangeEC.cs index 79cdf5be7..864f55d2f 100644 --- a/src/Renci.SshNet/Security/KeyExchangeEC.cs +++ b/src/Renci.SshNet/Security/KeyExchangeEC.cs @@ -1,6 +1,7 @@ 锘縰sing System.Text; -using Renci.SshNet.Messages.Transport; + using Renci.SshNet.Common; +using Renci.SshNet.Messages.Transport; namespace Renci.SshNet.Security { @@ -87,11 +88,12 @@ protected override bool ValidateExchangeHash() { return key.VerifySignature(exchangeHash, _signature); } + return false; } /// - /// Starts key exchange algorithm + /// Starts key exchange algorithm. /// /// The session. /// Key exchange init message. @@ -103,4 +105,4 @@ public override void Start(Session session, KeyExchangeInitMessage message) _clientPayload = Session.ClientInitMessage.GetBytes(); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs index b7a318bb9..18443fe73 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs @@ -6,7 +6,7 @@ namespace Renci.SshNet.Security { - internal class KeyExchangeECCurve25519 : KeyExchangeEC + internal sealed class KeyExchangeECCurve25519 : KeyExchangeEC { private byte[] _privateKey; @@ -30,7 +30,7 @@ protected override int HashSize } /// - /// Starts key exchange algorithm + /// Starts key exchange algorithm. /// /// The session. /// Key exchange init message. @@ -68,7 +68,7 @@ public override void Finish() /// /// The hash data. /// - /// Hashed bytes + /// The hash of the data. /// protected override byte[] Hash(byte[] hashData) { @@ -82,12 +82,12 @@ private void Session_KeyExchangeEcdhReplyMessageReceived(object sender, MessageE { var message = e.Message; - // Unregister message once received + // Unregister message once received Session.UnRegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); HandleServerEcdhReply(message.KS, message.QS, message.Signature); - // When SSH_MSG_KEXDH_REPLY received key exchange is completed + // When SSH_MSG_KEXDH_REPLY received key exchange is completed Finish(); } diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH.cs b/src/Renci.SshNet/Security/KeyExchangeECDH.cs index f87a5c7e4..c3fc7bfe4 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECDH.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECDH.cs @@ -2,12 +2,12 @@ using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; +using Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9; +using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Agreement; using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Generators; using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Parameters; -using Renci.SshNet.Security.Org.BouncyCastle.Security; using Renci.SshNet.Security.Org.BouncyCastle.Math.EC; -using Renci.SshNet.Security.Org.BouncyCastle.Asn1.X9; -using Renci.SshNet.Security.Org.BouncyCastle.Crypto.Agreement; +using Renci.SshNet.Security.Org.BouncyCastle.Security; namespace Renci.SshNet.Security { @@ -21,11 +21,11 @@ internal abstract class KeyExchangeECDH : KeyExchangeEC /// protected abstract X9ECParameters CurveParameter { get; } - protected ECDHCBasicAgreement KeyAgreement; - protected ECDomainParameters DomainParameters; + private ECDHCBasicAgreement _keyAgreement; + private ECDomainParameters _domainParameters; /// - /// Starts key exchange algorithm + /// Starts key exchange algorithm. /// /// The session. /// Key exchange init message. @@ -37,18 +37,18 @@ public override void Start(Session session, KeyExchangeInitMessage message) Session.KeyExchangeEcdhReplyMessageReceived += Session_KeyExchangeEcdhReplyMessageReceived; - DomainParameters = new ECDomainParameters(CurveParameter.Curve, + _domainParameters = new ECDomainParameters(CurveParameter.Curve, CurveParameter.G, CurveParameter.N, CurveParameter.H, CurveParameter.GetSeed()); var g = new ECKeyPairGenerator(); - g.Init(new ECKeyGenerationParameters(DomainParameters, new SecureRandom())); + g.Init(new ECKeyGenerationParameters(_domainParameters, new SecureRandom())); var aKeyPair = g.GenerateKeyPair(); - KeyAgreement = new ECDHCBasicAgreement(); - KeyAgreement.Init(aKeyPair.Private); + _keyAgreement = new ECDHCBasicAgreement(); + _keyAgreement.Init(aKeyPair.Private); _clientExchangeValue = ((ECPublicKeyParameters)aKeyPair.Public).Q.GetEncoded(); SendMessage(new KeyExchangeEcdhInitMessage(_clientExchangeValue)); @@ -68,12 +68,12 @@ private void Session_KeyExchangeEcdhReplyMessageReceived(object sender, MessageE { var message = e.Message; - // Unregister message once received + // Unregister message once received Session.UnRegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); HandleServerEcdhReply(message.KS, message.QS, message.Signature); - // When SSH_MSG_KEXDH_REPLY received key exchange is completed + // When SSH_MSG_KEXDH_REPLY received key exchange is completed Finish(); } @@ -95,11 +95,11 @@ private void HandleServerEcdhReply(byte[] hostKey, byte[] serverExchangeValue, b var y = new byte[cordSize]; Buffer.BlockCopy(serverExchangeValue, cordSize + 1, y, 0, y.Length); - var c = (FpCurve)DomainParameters.Curve; + var c = (FpCurve)_domainParameters.Curve; var q = c.CreatePoint(new Org.BouncyCastle.Math.BigInteger(1, x), new Org.BouncyCastle.Math.BigInteger(1, y)); - var publicKey = new ECPublicKeyParameters("ECDH", q, DomainParameters); + var publicKey = new ECPublicKeyParameters("ECDH", q, _domainParameters); - var k1 = KeyAgreement.CalculateAgreement(publicKey); + var k1 = _keyAgreement.CalculateAgreement(publicKey); SharedKey = k1.ToByteArray().ToBigInteger2().ToByteArray().Reverse(); } } diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH256.cs b/src/Renci.SshNet/Security/KeyExchangeECDH256.cs index 8f14d9bd4..b09652de8 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECDH256.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECDH256.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Security { - internal class KeyExchangeECDH256 : KeyExchangeECDH + internal sealed class KeyExchangeECDH256 : KeyExchangeECDH { /// /// Gets algorithm name. @@ -41,7 +41,7 @@ protected override int HashSize /// /// The hash data. /// - /// Hashed bytes + /// The hash of the data. /// protected override byte[] Hash(byte[] hashData) { @@ -51,4 +51,4 @@ protected override byte[] Hash(byte[] hashData) } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH384.cs b/src/Renci.SshNet/Security/KeyExchangeECDH384.cs index bbd7ced51..cba304305 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECDH384.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECDH384.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Security { - internal class KeyExchangeECDH384 : KeyExchangeECDH + internal sealed class KeyExchangeECDH384 : KeyExchangeECDH { /// /// Gets algorithm name. @@ -41,7 +41,7 @@ protected override int HashSize /// /// The hash data. /// - /// Hashed bytes + /// The hash of the data. /// protected override byte[] Hash(byte[] hashData) { diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH521.cs b/src/Renci.SshNet/Security/KeyExchangeECDH521.cs index 920089c02..ce5b35515 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECDH521.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECDH521.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Security { - internal class KeyExchangeECDH521 : KeyExchangeECDH + internal sealed class KeyExchangeECDH521 : KeyExchangeECDH { /// /// Gets algorithm name. @@ -41,7 +41,7 @@ protected override int HashSize /// /// The hash data. /// - /// Hashed bytes + /// The hash of the data. /// protected override byte[] Hash(byte[] hashData) { @@ -51,4 +51,4 @@ protected override byte[] Hash(byte[] hashData) } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Security/KeyExchangeHash.cs b/src/Renci.SshNet/Security/KeyExchangeHash.cs index e33cb14cc..f91946627 100644 --- a/src/Renci.SshNet/Security/KeyExchangeHash.cs +++ b/src/Renci.SshNet/Security/KeyExchangeHash.cs @@ -1,9 +1,10 @@ -锘縰sing Renci.SshNet.Common; -using System; +锘縰sing System; + +using Renci.SshNet.Common; namespace Renci.SshNet.Security { - internal class KeyExchangeHashData : SshData + internal sealed class KeyExchangeHashData : SshData { private byte[] _serverVersion; private byte[] _clientVersion; diff --git a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs index 11717197b..aad8e20c1 100644 --- a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs +++ b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs @@ -37,7 +37,7 @@ public KeyHostAlgorithm(string name, Key key) } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Host key name. /// Host key. @@ -80,7 +80,7 @@ public override bool VerifySignature(byte[] data, byte[] signature) return Key.VerifySignature(data, signatureData.Signature); } - private class SshKeyData : SshData + private sealed class SshKeyData : SshData { private byte[] _name; private List _keys; @@ -90,21 +90,26 @@ public BigInteger[] Keys get { var keys = new BigInteger[_keys.Count]; + for (var i = 0; i < _keys.Count; i++) { var key = _keys[i]; keys[i] = key.ToBigInteger2(); } + return keys; } private set { _keys = new List(value.Length); + foreach (var key in value) { var keyData = key.ToByteArray().Reverse(); if (Name == "ssh-ed25519") + { keyData = keyData.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + } _keys.Add(keyData); } @@ -165,7 +170,7 @@ protected override void SaveData() } } - private class SignatureKeyData : SshData + private sealed class SignatureKeyData : SshData { /// /// Gets or sets the name of the algorithm as UTF-8 encoded byte array. @@ -176,7 +181,7 @@ private class SignatureKeyData : SshData private byte[] AlgorithmName { get; set; } /// - /// Gets or sets the signature. + /// Gets the signature. /// /// /// The signature. diff --git a/src/Renci.SshNet/ServiceFactory.cs b/src/Renci.SshNet/ServiceFactory.cs index f04e6116d..42e541f0b 100644 --- a/src/Renci.SshNet/ServiceFactory.cs +++ b/src/Renci.SshNet/ServiceFactory.cs @@ -1,27 +1,28 @@ 锘縰sing System; using System.Collections.Generic; using System.Linq; +using System.Net.Sockets; using System.Text; + +using Renci.SshNet.Abstractions; using Renci.SshNet.Common; +using Renci.SshNet.Connection; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Security; using Renci.SshNet.Sftp; -using Renci.SshNet.Abstractions; -using Renci.SshNet.Connection; -using System.Net.Sockets; namespace Renci.SshNet { /// /// Basic factory for creating new services. /// - internal partial class ServiceFactory : IServiceFactory + internal sealed partial class ServiceFactory : IServiceFactory { /// /// Defines the number of times an authentication attempt with any given /// can result in before it is disregarded. /// - private static int PartialSuccessLimit = 5; + private static readonly int PartialSuccessLimit = 5; /// /// Creates a . @@ -92,9 +93,14 @@ public PipeStream CreatePipeStream() public IKeyExchange CreateKeyExchange(IDictionary clientAlgorithms, string[] serverAlgorithms) { if (clientAlgorithms == null) - throw new ArgumentNullException("clientAlgorithms"); + { + throw new ArgumentNullException(nameof(clientAlgorithms)); + } + if (serverAlgorithms == null) - throw new ArgumentNullException("serverAlgorithms"); + { + throw new ArgumentNullException(nameof(serverAlgorithms)); + } // find an algorithm that is supported by both client and server var keyExchangeAlgorithmType = (from c in clientAlgorithms @@ -157,7 +163,7 @@ public ISftpResponseFactory CreateSftpResponseFactory() /// The TERM environment variable. /// The terminal width in columns. /// The terminal width in rows. - /// The terminal height in pixels. + /// The terminal width in pixels. /// The terminal height in pixels. /// The terminal mode values. /// The size of the buffer. @@ -210,9 +216,14 @@ public IRemotePathTransformation CreateRemotePathDoubleQuoteTransformation() public IConnector CreateConnector(IConnectionInfo connectionInfo, ISocketFactory socketFactory) { if (connectionInfo == null) - throw new ArgumentNullException("connectionInfo"); + { + throw new ArgumentNullException(nameof(connectionInfo)); + } + if (socketFactory == null) - throw new ArgumentNullException("socketFactory"); + { + throw new ArgumentNullException(nameof(socketFactory)); + } switch (connectionInfo.ProxyType) { diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index 13764e386..17dd51256 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -1,8 +1,13 @@ 锘縰sing System; +using System.Globalization; +using System.Linq; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Threading; +using System.Threading.Tasks; + +using Renci.SshNet.Abstractions; using Renci.SshNet.Channels; using Renci.SshNet.Common; using Renci.SshNet.Compression; @@ -12,11 +17,7 @@ using Renci.SshNet.Messages.Connection; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Security; -using System.Globalization; -using System.Linq; -using Renci.SshNet.Abstractions; using Renci.SshNet.Security.Cryptography; -using System.Threading.Tasks; namespace Renci.SshNet { @@ -28,21 +29,13 @@ public class Session : ISession internal const byte CarriageReturn = 0x0d; internal const byte LineFeed = 0x0a; - /// - /// Specifies an infinite waiting period. - /// - /// - /// The value of this field is -1 millisecond. - /// - internal static readonly TimeSpan InfiniteTimeSpan = new TimeSpan(0, 0, 0, 0, -1); - /// /// Specifies an infinite waiting period. /// /// /// The value of this field is -1. /// - internal static readonly int Infinite = -1; + internal const int Infinite = -1; /// /// Specifies maximum packet size defined by the protocol. @@ -78,50 +71,90 @@ public class Session : ISession /// We currently do not enforce this limit. /// /// - private const int LocalChannelDataPacketSize = 1024*64; + private const int LocalChannelDataPacketSize = 1024 * 64; + + /// + /// Specifies an infinite waiting period. + /// + /// + /// The value of this field is -1 millisecond. + /// + internal static readonly TimeSpan InfiniteTimeSpan = new TimeSpan(0, 0, 0, 0, -1); /// /// Controls how many authentication attempts can take place at the same time. /// /// - /// Some server may restrict number to prevent authentication attacks + /// Some server may restrict number to prevent authentication attacks. /// private static readonly SemaphoreLight AuthenticationConnection = new SemaphoreLight(3); /// - /// Holds metada about session messages + /// Holds the factory to use for creating new services. + /// + private readonly IServiceFactory _serviceFactory; + private readonly ISocketFactory _socketFactory; + + /// + /// Holds an object that is used to ensure only a single thread can read from + /// at any given time. + /// + private readonly object _socketReadLock = new object(); + + /// + /// Holds an object that is used to ensure only a single thread can write to + /// at any given time. + /// + /// + /// This is also used to ensure that is + /// incremented atomatically. + /// + private readonly object _socketWriteLock = new object(); + + /// + /// Holds an object that is used to ensure only a single thread can dispose + /// at any given time. + /// + /// + /// This is also used to ensure that will not be disposed + /// while performing a given operation or set of operations on . + /// + private readonly object _socketDisposeLock = new object(); + + /// + /// Holds metadata about session messages. /// private SshMessageFactory _sshMessageFactory; /// /// Holds a that is signaled when the message listener loop has completed. /// - private EventWaitHandle _messageListenerCompleted; + private ManualResetEvent _messageListenerCompleted; /// - /// Specifies outbound packet number + /// Specifies outbound packet number. /// private volatile uint _outboundPacketSequence; /// - /// Specifies incoming packet number + /// Specifies incoming packet number. /// private uint _inboundPacketSequence; /// - /// WaitHandle to signal that last service request was accepted + /// WaitHandle to signal that last service request was accepted. /// - private EventWaitHandle _serviceAccepted = new AutoResetEvent(false); + private EventWaitHandle _serviceAccepted = new AutoResetEvent(initialState: false); /// /// WaitHandle to signal that exception was thrown by another thread. /// - private EventWaitHandle _exceptionWaitHandle = new ManualResetEvent(false); + private EventWaitHandle _exceptionWaitHandle = new ManualResetEvent(initialState: false); /// /// WaitHandle to signal that key exchange was completed. /// - private EventWaitHandle _keyExchangeCompletedWaitHandle = new ManualResetEvent(false); + private EventWaitHandle _keyExchangeCompletedWaitHandle = new ManualResetEvent(initialState: false); /// /// WaitHandle to signal that key exchange is in progress. @@ -129,17 +162,17 @@ public class Session : ISession private bool _keyExchangeInProgress; /// - /// Exception that need to be thrown by waiting thread + /// Exception that need to be thrown by waiting thread. /// private Exception _exception; /// - /// Specifies whether connection is authenticated + /// Specifies whether connection is authenticated. /// private bool _isAuthenticated; /// - /// Specifies whether user issued Disconnect command or not + /// Specifies whether user issued Disconnect command or not. /// private bool _isDisconnecting; @@ -159,43 +192,11 @@ public class Session : ISession private SemaphoreLight _sessionSemaphore; - /// - /// Holds the factory to use for creating new services. - /// - private readonly IServiceFactory _serviceFactory; - private readonly ISocketFactory _socketFactory; - /// /// Holds connection socket. /// private Socket _socket; - /// - /// Holds an object that is used to ensure only a single thread can read from - /// at any given time. - /// - private readonly object _socketReadLock = new object(); - - /// - /// Holds an object that is used to ensure only a single thread can write to - /// at any given time. - /// - /// - /// This is also used to ensure that is - /// incremented atomatically. - /// - private readonly object _socketWriteLock = new object(); - - /// - /// Holds an object that is used to ensure only a single thread can dispose - /// at any given time. - /// - /// - /// This is also used to ensure that will not be disposed - /// while performing a given operation or set of operations on . - /// - private readonly object _socketDisposeLock = new object(); - /// /// Gets the session semaphore that controls session channels. /// @@ -277,9 +278,14 @@ public bool IsConnected get { if (_disposed || _isDisconnectMessageSent || !_isAuthenticated) + { return false; + } + if (_messageListenerCompleted == null || _messageListenerCompleted.WaitOne(0)) + { return false; + } return IsSocketConnected(); } @@ -315,32 +321,39 @@ public Message ClientInitMessage MacAlgorithmsServerToClient = ConnectionInfo.HmacAlgorithms.Keys.ToArray(), CompressionAlgorithmsClientToServer = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(), CompressionAlgorithmsServerToClient = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(), - LanguagesClientToServer = new[] {string.Empty}, - LanguagesServerToClient = new[] {string.Empty}, + LanguagesClientToServer = new[] { string.Empty }, + LanguagesServerToClient = new[] { string.Empty }, FirstKexPacketFollows = false, Reserved = 0 }; } + return _clientInitMessage; } } /// - /// Gets or sets the server version string. + /// Gets the server version string. /// - /// The server version. + /// + /// The server version. + /// public string ServerVersion { get; private set; } /// - /// Gets or sets the client version string. + /// Gets the client version string. /// - /// The client version. + /// + /// The client version. + /// public string ClientVersion { get; private set; } /// - /// Gets or sets the connection info. + /// Gets the connection info. /// - /// The connection info. + /// + /// The connection info. + /// public ConnectionInfo ConnectionInfo { get; private set; } /// @@ -388,8 +401,6 @@ public Message ClientInitMessage /// internal event EventHandler> KeyExchangeDhGroupExchangeReplyReceived; - #region Message events - /// /// Occurs when message received /// @@ -525,8 +536,6 @@ public Message ClientInitMessage /// public event EventHandler> ChannelFailureReceived; - #endregion - /// /// Initializes a new instance of the class. /// @@ -539,17 +548,25 @@ public Message ClientInitMessage internal Session(ConnectionInfo connectionInfo, IServiceFactory serviceFactory, ISocketFactory socketFactory) { if (connectionInfo == null) - throw new ArgumentNullException("connectionInfo"); + { + throw new ArgumentNullException(nameof(connectionInfo)); + } + if (serviceFactory == null) - throw new ArgumentNullException("serviceFactory"); + { + throw new ArgumentNullException(nameof(serviceFactory)); + } + if (socketFactory == null) - throw new ArgumentNullException("socketFactory"); + { + throw new ArgumentNullException(nameof(socketFactory)); + } ClientVersion = "SSH-2.0-Renci.SshNet.SshClient.0.0.1"; ConnectionInfo = connectionInfo; _serviceFactory = serviceFactory; _socketFactory = socketFactory; - _messageListenerCompleted = new ManualResetEvent(true); + _messageListenerCompleted = new ManualResetEvent(initialState: true); } /// @@ -562,20 +579,26 @@ internal Session(ConnectionInfo connectionInfo, IServiceFactory serviceFactory, public void Connect() { if (IsConnected) + { return; + } try { AuthenticationConnection.Wait(); if (IsConnected) + { return; + } lock (this) { // If connected don't connect again if (IsConnected) + { return; + } // Reset connection specific information Reset(); @@ -614,7 +637,7 @@ public void Connect() RegisterMessage("SSH_MSG_USERAUTH_BANNER"); // Mark the message listener threads as started - _messageListenerCompleted.Reset(); + _ = _messageListenerCompleted.Reset(); // Start incoming request listener // ToDo: Make message pump async, to not consume a thread for every session @@ -665,7 +688,7 @@ public void Connect() } finally { - AuthenticationConnection.Release(); + _ = AuthenticationConnection.Release(); } } @@ -685,7 +708,9 @@ public async Task ConnectAsync(CancellationToken cancellationToken) { // If connected don't connect again if (IsConnected) + { return; + } // Reset connection specific information Reset(); @@ -724,7 +749,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken) RegisterMessage("SSH_MSG_USERAUTH_BANNER"); // Mark the message listener threads as started - _messageListenerCompleted.Reset(); + _ = _messageListenerCompleted.Reset(); // Start incoming request listener // ToDo: Make message pump async, to not consume a thread for every session @@ -792,7 +817,7 @@ public void Disconnect() // has completed if (_messageListenerCompleted != null) { - _messageListenerCompleted.WaitOne(); + _ = _messageListenerCompleted.WaitOne(); } } @@ -879,8 +904,7 @@ internal void WaitOnHandle(WaitHandle waitHandle) /// WaitResult ISession.TryWait(WaitHandle waitHandle, TimeSpan timeout) { - Exception exception; - return TryWait(waitHandle, timeout, out exception); + return TryWait(waitHandle, timeout, out _); } /// @@ -911,7 +935,9 @@ WaitResult ISession.TryWait(WaitHandle waitHandle, TimeSpan timeout, out Excepti private WaitResult TryWait(WaitHandle waitHandle, TimeSpan timeout, out Exception exception) { if (waitHandle == null) - throw new ArgumentNullException("waitHandle"); + { + throw new ArgumentNullException(nameof(waitHandle)); + } var waitHandles = new[] { @@ -928,6 +954,7 @@ private WaitResult TryWait(WaitHandle waitHandle, TimeSpan timeout, out Exceptio exception = null; return WaitResult.Disconnected; } + exception = _exception; return WaitResult.Failed; case 1: @@ -956,7 +983,9 @@ private WaitResult TryWait(WaitHandle waitHandle, TimeSpan timeout, out Exceptio internal void WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout) { if (waitHandle == null) - throw new ArgumentNullException("waitHandle"); + { + throw new ArgumentNullException(nameof(waitHandle)); + } var waitHandles = new[] { @@ -982,6 +1011,7 @@ internal void WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout) { throw new SshOperationTimeoutException("Session operation has timed out"); } + break; } } @@ -996,11 +1026,13 @@ internal void WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout) internal void SendMessage(Message message) { if (!_socket.CanWrite()) + { throw new SshConnectionException("Client not connected."); + } - if (_keyExchangeInProgress && !(message is IKeyExchangedAllowed)) + if (_keyExchangeInProgress && message is not IKeyExchangedAllowed) { - // Wait for key exchange to be completed + // Wait for key exchange to be completed WaitOnHandle(_keyExchangeCompletedWaitHandle); } @@ -1020,14 +1052,15 @@ internal void SendMessage(Message message) { // write outbound packet sequence to start of packet data Pack.UInt32ToBigEndian(_outboundPacketSequence, packetData); - // calculate packet hash + + // calculate packet hash hash = _clientMac.ComputeHash(packetData); } // Encrypt packet data if (_clientCipher != null) { - packetData = _clientCipher.Encrypt(packetData, packetDataOffset, (packetData.Length - packetDataOffset)); + packetData = _clientCipher.Encrypt(packetData, packetDataOffset, packetData.Length - packetDataOffset); packetDataOffset = 0; } @@ -1052,7 +1085,7 @@ internal void SendMessage(Message message) // increment the packet sequence number only after we're sure the packet has // been sent; even though it's only used for the MAC, it needs to be incremented // for each package sent. - // + // // the server will use it to verify the data integrity, and as such the order in // which messages are sent must follow the outbound packet sequence number _outboundPacketSequence++; @@ -1081,7 +1114,9 @@ private void SendPacket(byte[] packet, int offset, int length) lock (_socketDisposeLock) { if (!_socket.IsConnected()) + { throw new SshConnectionException("Client not connected."); + } SocketAbstraction.Send(_socket, packet, offset, length); } @@ -1131,8 +1166,10 @@ private Message ReceiveMessage(Socket socket) { // the length of the packet sequence field in bytes const int inboundPacketSequenceLength = 4; + // The length of the "packet length" field in bytes const int packetLengthFieldLength = 4; + // The length of the "padding length" field in bytes const int paddingLengthFieldLength = 1; @@ -1149,7 +1186,7 @@ private Message ReceiveMessage(Socket socket) // Socket.Available lock (_socketReadLock) { - // Read first block - which starts with the packet length + // Read first block - which starts with the packet length var firstBlock = new byte[blockSize]; if (TrySocketRead(socket, firstBlock, 0, blockSize) == 0) { @@ -1166,9 +1203,10 @@ private Message ReceiveMessage(Socket socket) // Test packet minimum and maximum boundaries if (packetLength < Math.Max((byte) 16, blockSize) - 4 || packetLength > MaximumSshPacketSize - 4) - throw new SshConnectionException( - string.Format(CultureInfo.CurrentCulture, "Bad packet length: {0}.", packetLength), - DisconnectReason.ProtocolError); + { + throw new SshConnectionException(string.Format(CultureInfo.CurrentCulture, "Bad packet length: {0}.", packetLength), + DisconnectReason.ProtocolError); + } // Determine the number of bytes left to read; We've already read "blockSize" bytes, but the // "packet length" field itself - which is 4 bytes - is not included in the length of the packet @@ -1176,12 +1214,12 @@ private Message ReceiveMessage(Socket socket) // Construct buffer for holding the payload and the inbound packet sequence as we need both in order // to generate the hash. - // + // // The total length of the "data" buffer is an addition of: // - inboundPacketSequenceLength (4 bytes) // - packetLength // - serverMacLength - // + // // We include the inbound packet sequence to allow us to have the the full SSH packet in a single // byte[] for the purpose of calculating the client hash. Room for the server MAC is foreseen // to read the packet including server MAC in a single pass (except for the initial block). @@ -1232,6 +1270,7 @@ private Message ReceiveMessage(Socket socket) // data now only contains the decompressed payload, and as such the offset is reset to zero messagePayloadOffset = 0; + // the length of the payload is now the complete decompressed content messagePayloadLength = data.Length; } @@ -1246,14 +1285,12 @@ private void TrySendDisconnect(DisconnectReason reasonCode, string message) var disconnectMessage = new DisconnectMessage(reasonCode, message); // send the disconnect message, but ignore the outcome - TrySendMessage(disconnectMessage); + _ = TrySendMessage(disconnectMessage); // mark disconnect message sent regardless of whether the send sctually succeeded _isDisconnectMessageSent = true; } - #region Handle received message events - /// /// Called when received. /// @@ -1268,15 +1305,11 @@ internal void OnDisconnectReceived(DisconnectMessage message) _isDisconnecting = true; _exception = new SshConnectionException(string.Format(CultureInfo.InvariantCulture, "The connection was closed by the server: {0} ({1}).", message.Description, message.ReasonCode), message.ReasonCode); - _exceptionWaitHandle.Set(); + _ = _exceptionWaitHandle.Set(); - var disconnectReceived = DisconnectReceived; - if (disconnectReceived != null) - disconnectReceived(this, new MessageEventArgs(message)); + DisconnectReceived?.Invoke(this, new MessageEventArgs(message)); - var disconnected = Disconnected; - if (disconnected != null) - disconnected(this, new EventArgs()); + Disconnected?.Invoke(this, EventArgs.Empty); // disconnect socket, and dispose it SocketDisconnectAndDispose(); @@ -1288,9 +1321,7 @@ internal void OnDisconnectReceived(DisconnectMessage message) /// message. internal void OnIgnoreReceived(IgnoreMessage message) { - var handlers = IgnoreReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + IgnoreReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1299,9 +1330,7 @@ internal void OnIgnoreReceived(IgnoreMessage message) /// message. internal void OnUnimplementedReceived(UnimplementedMessage message) { - var handlers = UnimplementedReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + UnimplementedReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1310,9 +1339,7 @@ internal void OnUnimplementedReceived(UnimplementedMessage message) /// message. internal void OnDebugReceived(DebugMessage message) { - var handlers = DebugReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + DebugReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1321,9 +1348,7 @@ internal void OnDebugReceived(DebugMessage message) /// message. internal void OnServiceRequestReceived(ServiceRequestMessage message) { - var handlers = ServiceRequestReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ServiceRequestReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1332,25 +1357,19 @@ internal void OnServiceRequestReceived(ServiceRequestMessage message) /// message. internal void OnServiceAcceptReceived(ServiceAcceptMessage message) { - var handlers = ServiceAcceptReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ServiceAcceptReceived?.Invoke(this, new MessageEventArgs(message)); - _serviceAccepted.Set(); + _ = _serviceAccepted.Set(); } internal void OnKeyExchangeDhGroupExchangeGroupReceived(KeyExchangeDhGroupExchangeGroup message) { - var handlers = KeyExchangeDhGroupExchangeGroupReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + KeyExchangeDhGroupExchangeGroupReceived?.Invoke(this, new MessageEventArgs(message)); } internal void OnKeyExchangeDhGroupExchangeReplyReceived(KeyExchangeDhGroupExchangeReply message) { - var handlers = KeyExchangeDhGroupExchangeReplyReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + KeyExchangeDhGroupExchangeReplyReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1361,7 +1380,7 @@ internal void OnKeyExchangeInitReceived(KeyExchangeInitMessage message) { _keyExchangeInProgress = true; - _keyExchangeCompletedWaitHandle.Reset(); + _ = _keyExchangeCompletedWaitHandle.Reset(); // Disable messages that are not key exchange related _sshMessageFactory.DisableNonKeyExchangeMessages(); @@ -1373,26 +1392,20 @@ internal void OnKeyExchangeInitReceived(KeyExchangeInitMessage message) _keyExchange.HostKeyReceived += KeyExchange_HostKeyReceived; - // Start the algorithm implementation + // Start the algorithm implementation _keyExchange.Start(this, message); - var keyExchangeInitReceived = KeyExchangeInitReceived; - if (keyExchangeInitReceived != null) - keyExchangeInitReceived(this, new MessageEventArgs(message)); + KeyExchangeInitReceived?.Invoke(this, new MessageEventArgs(message)); } internal void OnKeyExchangeDhReplyMessageReceived(KeyExchangeDhReplyMessage message) { - var handlers = KeyExchangeDhReplyMessageReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + KeyExchangeDhReplyMessageReceived?.Invoke(this, new MessageEventArgs(message)); } internal void OnKeyExchangeEcdhReplyMessageReceived(KeyExchangeEcdhReplyMessage message) { - var handlers = KeyExchangeEcdhReplyMessageReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + KeyExchangeEcdhReplyMessageReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1401,13 +1414,10 @@ internal void OnKeyExchangeEcdhReplyMessageReceived(KeyExchangeEcdhReplyMessage /// message. internal void OnNewKeysReceived(NewKeysMessage message) { - // Update sessionId - if (SessionId == null) - { - SessionId = _keyExchange.ExchangeHash; - } + // Update sessionId + SessionId ??= _keyExchange.ExchangeHash; - // Dispose of old ciphers and hash algorithms + // Dispose of old ciphers and hash algorithms if (_serverMac != null) { _serverMac.Dispose(); @@ -1420,7 +1430,7 @@ internal void OnNewKeysReceived(NewKeysMessage message) _clientMac = null; } - // Update negotiated algorithms + // Update negotiated algorithms _serverCipher = _keyExchange.CreateServerCipher(); _clientCipher = _keyExchange.CreateClientCipher(); _serverMac = _keyExchange.CreateServerHash(); @@ -1428,7 +1438,7 @@ internal void OnNewKeysReceived(NewKeysMessage message) _clientCompression = _keyExchange.CreateCompressor(); _serverDecompression = _keyExchange.CreateDecompressor(); - // Dispose of old KeyExchange object as it is no longer needed. + // Dispose of old KeyExchange object as it is no longer needed. if (_keyExchange != null) { _keyExchange.HostKeyReceived -= KeyExchange_HostKeyReceived; @@ -1439,12 +1449,10 @@ internal void OnNewKeysReceived(NewKeysMessage message) // Enable activated messages that are not key exchange related _sshMessageFactory.EnableActivatedMessages(); - var newKeysReceived = NewKeysReceived; - if (newKeysReceived != null) - newKeysReceived(this, new MessageEventArgs(message)); + NewKeysReceived?.Invoke(this, new MessageEventArgs(message)); - // Signal that key exchange completed - _keyExchangeCompletedWaitHandle.Set(); + // Signal that key exchange completed + _ = _keyExchangeCompletedWaitHandle.Set(); _keyExchangeInProgress = false; } @@ -1463,9 +1471,7 @@ void ISession.OnDisconnecting() /// message. internal void OnUserAuthenticationRequestReceived(RequestMessage message) { - var handlers = UserAuthenticationRequestReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + UserAuthenticationRequestReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1474,9 +1480,7 @@ internal void OnUserAuthenticationRequestReceived(RequestMessage message) /// message. internal void OnUserAuthenticationFailureReceived(FailureMessage message) { - var handlers = UserAuthenticationFailureReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + UserAuthenticationFailureReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1485,9 +1489,7 @@ internal void OnUserAuthenticationFailureReceived(FailureMessage message) /// message. internal void OnUserAuthenticationSuccessReceived(SuccessMessage message) { - var handlers = UserAuthenticationSuccessReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + UserAuthenticationSuccessReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1496,35 +1498,26 @@ internal void OnUserAuthenticationSuccessReceived(SuccessMessage message) /// message. internal void OnUserAuthenticationBannerReceived(BannerMessage message) { - var handlers = UserAuthenticationBannerReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + UserAuthenticationBannerReceived?.Invoke(this, new MessageEventArgs(message)); } - /// /// Called when message received. /// /// message. internal void OnUserAuthenticationInformationRequestReceived(InformationRequestMessage message) { - var handlers = UserAuthenticationInformationRequestReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + UserAuthenticationInformationRequestReceived?.Invoke(this, new MessageEventArgs(message)); } internal void OnUserAuthenticationPasswordChangeRequiredReceived(PasswordChangeRequiredMessage message) { - var handlers = UserAuthenticationPasswordChangeRequiredReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + UserAuthenticationPasswordChangeRequiredReceived?.Invoke(this, new MessageEventArgs(message)); } internal void OnUserAuthenticationPublicKeyReceived(PublicKeyMessage message) { - var handlers = UserAuthenticationPublicKeyReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + UserAuthenticationPublicKeyReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1533,9 +1526,7 @@ internal void OnUserAuthenticationPublicKeyReceived(PublicKeyMessage message) /// message. internal void OnGlobalRequestReceived(GlobalRequestMessage message) { - var handlers = GlobalRequestReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + GlobalRequestReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1544,9 +1535,7 @@ internal void OnGlobalRequestReceived(GlobalRequestMessage message) /// message. internal void OnRequestSuccessReceived(RequestSuccessMessage message) { - var handlers = RequestSuccessReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + RequestSuccessReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1555,9 +1544,7 @@ internal void OnRequestSuccessReceived(RequestSuccessMessage message) /// message. internal void OnRequestFailureReceived(RequestFailureMessage message) { - var handlers = RequestFailureReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + RequestFailureReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1566,9 +1553,7 @@ internal void OnRequestFailureReceived(RequestFailureMessage message) /// message. internal void OnChannelOpenReceived(ChannelOpenMessage message) { - var handlers = ChannelOpenReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ChannelOpenReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1577,9 +1562,7 @@ internal void OnChannelOpenReceived(ChannelOpenMessage message) /// message. internal void OnChannelOpenConfirmationReceived(ChannelOpenConfirmationMessage message) { - var handlers = ChannelOpenConfirmationReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ChannelOpenConfirmationReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1588,9 +1571,7 @@ internal void OnChannelOpenConfirmationReceived(ChannelOpenConfirmationMessage m /// message. internal void OnChannelOpenFailureReceived(ChannelOpenFailureMessage message) { - var handlers = ChannelOpenFailureReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ChannelOpenFailureReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1599,9 +1580,7 @@ internal void OnChannelOpenFailureReceived(ChannelOpenFailureMessage message) /// message. internal void OnChannelWindowAdjustReceived(ChannelWindowAdjustMessage message) { - var handlers = ChannelWindowAdjustReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ChannelWindowAdjustReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1610,9 +1589,7 @@ internal void OnChannelWindowAdjustReceived(ChannelWindowAdjustMessage message) /// message. internal void OnChannelDataReceived(ChannelDataMessage message) { - var handlers = ChannelDataReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ChannelDataReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1621,9 +1598,7 @@ internal void OnChannelDataReceived(ChannelDataMessage message) /// message. internal void OnChannelExtendedDataReceived(ChannelExtendedDataMessage message) { - var handlers = ChannelExtendedDataReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ChannelExtendedDataReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1632,9 +1607,7 @@ internal void OnChannelExtendedDataReceived(ChannelExtendedDataMessage message) /// message. internal void OnChannelEofReceived(ChannelEofMessage message) { - var handlers = ChannelEofReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ChannelEofReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1643,9 +1616,7 @@ internal void OnChannelEofReceived(ChannelEofMessage message) /// message. internal void OnChannelCloseReceived(ChannelCloseMessage message) { - var handlers = ChannelCloseReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ChannelCloseReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1654,9 +1625,7 @@ internal void OnChannelCloseReceived(ChannelCloseMessage message) /// message. internal void OnChannelRequestReceived(ChannelRequestMessage message) { - var handlers = ChannelRequestReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ChannelRequestReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1665,9 +1634,7 @@ internal void OnChannelRequestReceived(ChannelRequestMessage message) /// message. internal void OnChannelSuccessReceived(ChannelSuccessMessage message) { - var handlers = ChannelSuccessReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ChannelSuccessReceived?.Invoke(this, new MessageEventArgs(message)); } /// @@ -1676,22 +1643,14 @@ internal void OnChannelSuccessReceived(ChannelSuccessMessage message) /// message. internal void OnChannelFailureReceived(ChannelFailureMessage message) { - var handlers = ChannelFailureReceived; - if (handlers != null) - handlers(this, new MessageEventArgs(message)); + ChannelFailureReceived?.Invoke(this, new MessageEventArgs(message)); } - #endregion - private void KeyExchange_HostKeyReceived(object sender, HostKeyEventArgs e) { - var handlers = HostKeyReceived; - if (handlers != null) - handlers(this, e); + HostKeyReceived?.Invoke(this, e); } - #region Message loading functions - /// /// Registers SSH message with the session. /// @@ -1741,7 +1700,7 @@ private static string ToHex(byte[] bytes, int offset) for (var i = offset; i < byteCount; i++) { var b = bytes[i]; - builder.Append(b.ToString("X2")); + _ = builder.Append(b.ToString("X2")); } return builder.ToString(); @@ -1750,13 +1709,13 @@ private static string ToHex(byte[] bytes, int offset) internal static string ToHex(byte[] bytes) { if (bytes == null) + { return null; + } return ToHex(bytes, 0); } - #endregion - /// /// Gets a value indicating whether the socket is connected. /// @@ -1933,7 +1892,7 @@ private void MessageListener() finally { // signal that the message listener thread has stopped - _messageListenerCompleted.Set(); + _ = _messageListenerCompleted.Set(); } } @@ -1949,25 +1908,26 @@ private void RaiseError(Exception exp) if (_isDisconnecting) { - // a connection exception which is raised while isDisconnecting is normal and - // should be ignored + // a connection exception which is raised while isDisconnecting is normal and + // should be ignored if (connectionException != null) + { return; + } // any timeout while disconnecting can be caused by loss of connectivity // altogether and should be ignored - var socketException = exp as SocketException; - if (socketException != null && socketException.SocketErrorCode == SocketError.TimedOut) + if (exp is SocketException socketException && socketException.SocketErrorCode == SocketError.TimedOut) + { return; + } } // "save" exception and set exception wait handle to ensure any waits are interrupted _exception = exp; - _exceptionWaitHandle.Set(); + _ = _exceptionWaitHandle.Set(); - var errorOccured = ErrorOccured; - if (errorOccured != null) - errorOccured(this, new ExceptionEventArgs(exp)); + ErrorOccured?.Invoke(this, new ExceptionEventArgs(exp)); if (connectionException != null) { @@ -1982,12 +1942,9 @@ private void RaiseError(Exception exp) /// private void Reset() { - if (_exceptionWaitHandle != null) - _exceptionWaitHandle.Reset(); - if (_keyExchangeCompletedWaitHandle != null) - _keyExchangeCompletedWaitHandle.Reset(); - if (_messageListenerCompleted != null) - _messageListenerCompleted.Set(); + _ = _exceptionWaitHandle?.Reset(); + _ = _keyExchangeCompletedWaitHandle?.Reset(); + _ = _messageListenerCompleted?.Set(); SessionId = null; _isDisconnectMessageSent = false; @@ -2003,8 +1960,6 @@ private static SshConnectionException CreateConnectionAbortedByServerException() DisconnectReason.ConnectionLost); } -#region IDisposable implementation - private bool _disposed; /// @@ -2012,18 +1967,20 @@ private static SshConnectionException CreateConnectionAbortedByServerException() /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_disposed) + { return; + } if (disposing) { @@ -2086,20 +2043,15 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~Session() { - Dispose(false); + Dispose(disposing: false); } -#endregion IDisposable implementation - -#region ISession implementation - /// - /// Gets or sets the connection info. + /// Gets the connection info. /// /// The connection info. IConnectionInfo ISession.ConnectionInfo @@ -2181,8 +2133,6 @@ bool ISession.TrySendMessage(Message message) { return TrySendMessage(message); } - -#endregion ISession implementation } /// @@ -2210,4 +2160,4 @@ internal enum WaitResult /// Failed = 4 } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Sftp/ISftpFile.cs b/src/Renci.SshNet/Sftp/ISftpFile.cs index 60c4a7a52..fb0d8b224 100644 --- a/src/Renci.SshNet/Sftp/ISftpFile.cs +++ b/src/Renci.SshNet/Sftp/ISftpFile.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Sftp { /// - /// Represents SFTP file information + /// Represents SFTP file information. /// public interface ISftpFile { @@ -13,14 +13,23 @@ public interface ISftpFile SftpFileAttributes Attributes { get; } /// - /// Gets the full path of the directory or file. + /// Gets the full path of the file or directory. /// + /// + /// The full path of the file or directory. + /// string FullName { get; } /// - /// For files, gets the name of the file. For directories, gets the name of the last directory in the hierarchy if a hierarchy exists. - /// Otherwise, the Name property gets the name of the directory. + /// Gets the name of the file or directory. /// + /// + /// The name of the file or directory. + /// + /// + /// For directories, this is the name of the last directory in the hierarchy if a hierarchy exists; + /// otherwise, the name of the directory. + /// string Name { get; } /// @@ -56,7 +65,7 @@ public interface ISftpFile DateTime LastWriteTimeUtc { get; set; } /// - /// Gets or sets the size, in bytes, of the current file. + /// Gets the size, in bytes, of the current file. /// /// /// The size of the current file in bytes. @@ -83,7 +92,7 @@ public interface ISftpFile /// Gets a value indicating whether file represents a socket. /// /// - /// true if file represents a socket; otherwise, false. + /// true if file represents a socket; otherwise, false. /// bool IsSocket { get; } @@ -91,7 +100,7 @@ public interface ISftpFile /// Gets a value indicating whether file represents a symbolic link. /// /// - /// true if file represents a symbolic link; otherwise, false. + /// true if file represents a symbolic link; otherwise, false. /// bool IsSymbolicLink { get; } @@ -99,7 +108,7 @@ public interface ISftpFile /// Gets a value indicating whether file represents a regular file. /// /// - /// true if file represents a regular file; otherwise, false. + /// true if file represents a regular file; otherwise, false. /// bool IsRegularFile { get; } @@ -107,7 +116,7 @@ public interface ISftpFile /// Gets a value indicating whether file represents a block device. /// /// - /// true if file represents a block device; otherwise, false. + /// true if file represents a block device; otherwise, false. /// bool IsBlockDevice { get; } @@ -115,7 +124,7 @@ public interface ISftpFile /// Gets a value indicating whether file represents a directory. /// /// - /// true if file represents a directory; otherwise, false. + /// true if file represents a directory; otherwise, false. /// bool IsDirectory { get; } @@ -123,7 +132,7 @@ public interface ISftpFile /// Gets a value indicating whether file represents a character device. /// /// - /// true if file represents a character device; otherwise, false. + /// true if file represents a character device; otherwise, false. /// bool IsCharacterDevice { get; } @@ -131,7 +140,7 @@ public interface ISftpFile /// Gets a value indicating whether file represents a named pipe. /// /// - /// true if file represents a named pipe; otherwise, false. + /// true if file represents a named pipe; otherwise, false. /// bool IsNamedPipe { get; } @@ -139,7 +148,7 @@ public interface ISftpFile /// Gets or sets a value indicating whether the owner can read from this file. /// /// - /// true if owner can read from this file; otherwise, false. + /// true if owner can read from this file; otherwise, false. /// bool OwnerCanRead { get; set; } @@ -230,4 +239,4 @@ public interface ISftpFile /// void UpdateStatus(); } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Sftp/ISftpSession.cs b/src/Renci.SshNet/Sftp/ISftpSession.cs index 8971bd571..39b48e7f1 100644 --- a/src/Renci.SshNet/Sftp/ISftpSession.cs +++ b/src/Renci.SshNet/Sftp/ISftpSession.cs @@ -1,9 +1,10 @@ 锘縰sing System; using System.Collections.Generic; using System.Threading; -using Renci.SshNet.Sftp.Responses; using System.Threading.Tasks; +using Renci.SshNet.Sftp.Responses; + namespace Renci.SshNet.Sftp { internal interface ISftpSession : ISubsystemSession @@ -59,12 +60,12 @@ internal interface ISftpSession : ISubsystemSession /// The path. /// if set to true returns null instead of throwing an exception. /// - /// File attributes + /// File attributes. /// SftpFileAttributes RequestStat(string path, bool nullOnError = false); /// - /// Performs SSH_FXP_STAT request + /// Performs SSH_FXP_STAT request. /// /// The path. /// The delegate that is executed when completes. @@ -121,7 +122,7 @@ internal interface ISftpSession : ISubsystemSession void RequestMkDir(string path); /// - /// Performs SSH_FXP_OPEN request + /// Performs SSH_FXP_OPEN request. /// /// The path. /// The flags. @@ -132,7 +133,7 @@ internal interface ISftpSession : ISubsystemSession Task RequestOpenAsync(string path, Flags flags, CancellationToken cancellationToken); /// - /// Performs SSH_FXP_OPEN request + /// Performs SSH_FXP_OPEN request. /// /// The path. /// The flags. @@ -158,7 +159,7 @@ internal interface ISftpSession : ISubsystemSession byte[] EndOpen(SftpOpenAsyncResult asyncResult); /// - /// Performs SSH_FXP_OPENDIR request + /// Performs SSH_FXP_OPENDIR request. /// /// The path. /// if set to true returns null instead of throwing an exception. @@ -213,7 +214,7 @@ internal interface ISftpSession : ISubsystemSession Task RequestReadAsync(byte[] handle, ulong offset, uint length, CancellationToken cancellationToken); /// - /// Performs SSH_FXP_READDIR request + /// Performs SSH_FXP_READDIR request. /// /// The handle. /// diff --git a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/FStatVfsRequest.cs b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/FStatVfsRequest.cs index 5b5b02ecd..06eeef1e2 100644 --- a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/FStatVfsRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/FStatVfsRequest.cs @@ -42,8 +42,7 @@ protected override void SaveData() public override void Complete(SftpResponse response) { - var extendedReplyResponse = response as SftpExtendedReplyResponse; - if (extendedReplyResponse != null) + if (response is SftpExtendedReplyResponse extendedReplyResponse) { _extendedReplyAction(extendedReplyResponse); } diff --git a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/HardLinkRequest.cs b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/HardLinkRequest.cs index de7e06db4..963249d22 100644 --- a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/HardLinkRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/HardLinkRequest.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Sftp.Requests { - internal class HardLinkRequest : SftpExtendedRequest + internal sealed class HardLinkRequest : SftpExtendedRequest { private byte[] _oldPath; private byte[] _newPath; @@ -53,4 +53,4 @@ protected override void SaveData() WriteBinaryString(_newPath); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/PosixRenameRequest.cs b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/PosixRenameRequest.cs index d0b530f08..5d996723b 100644 --- a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/PosixRenameRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/PosixRenameRequest.cs @@ -1,10 +1,11 @@ 锘縰sing System; -using Renci.SshNet.Sftp.Responses; using System.Text; +using Renci.SshNet.Sftp.Responses; + namespace Renci.SshNet.Sftp.Requests { - internal class PosixRenameRequest : SftpExtendedRequest + internal sealed class PosixRenameRequest : SftpExtendedRequest { private byte[] _oldPath; private byte[] _newPath; @@ -21,7 +22,7 @@ public string NewPath private set { _newPath = Encoding.GetBytes(value); } } - public Encoding Encoding { get; private set; } + public Encoding Encoding { get; } /// /// Gets the size of the message in bytes. @@ -53,8 +54,9 @@ public PosixRenameRequest(uint protocolVersion, uint requestId, string oldPath, protected override void SaveData() { base.SaveData(); + WriteBinaryString(_oldPath); WriteBinaryString(_newPath); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/StatVfsRequest.cs b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/StatVfsRequest.cs index b1bda3c06..fe4373257 100644 --- a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/StatVfsRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/StatVfsRequest.cs @@ -1,13 +1,14 @@ 锘縰sing System; -using Renci.SshNet.Sftp.Responses; using System.Text; +using Renci.SshNet.Sftp.Responses; + namespace Renci.SshNet.Sftp.Requests { - internal class StatVfsRequest : SftpExtendedRequest + internal sealed class StatVfsRequest : SftpExtendedRequest { - private byte[] _path; private readonly Action _extendedReplyAction; + private byte[] _path; public string Path { @@ -51,8 +52,7 @@ protected override void SaveData() public override void Complete(SftpResponse response) { - var extendedReplyResponse = response as SftpExtendedReplyResponse; - if (extendedReplyResponse != null) + if (response is SftpExtendedReplyResponse extendedReplyResponse) { _extendedReplyAction(extendedReplyResponse); } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpBlockRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpBlockRequest.cs index 9414150c0..9c2ccd6ca 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpBlockRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpBlockRequest.cs @@ -1,9 +1,10 @@ 锘縰sing System; + using Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Sftp.Requests { - internal class SftpBlockRequest : SftpRequest + internal sealed class SftpBlockRequest : SftpRequest { public override SftpMessageTypes SftpMessageType { @@ -38,7 +39,7 @@ protected override int BufferCapacity } } - public SftpBlockRequest(uint protocolVersion, uint requestId, byte[] handle, UInt64 offset, UInt64 length, UInt32 lockMask, Action statusAction) + public SftpBlockRequest(uint protocolVersion, uint requestId, byte[] handle, ulong offset, ulong length, uint lockMask, Action statusAction) : base(protocolVersion, requestId, statusAction) { Handle = handle; @@ -50,6 +51,7 @@ public SftpBlockRequest(uint protocolVersion, uint requestId, byte[] handle, UIn protected override void LoadData() { base.LoadData(); + Handle = ReadBinary(); Offset = ReadUInt64(); Length = ReadUInt64(); @@ -59,6 +61,7 @@ protected override void LoadData() protected override void SaveData() { base.SaveData(); + WriteBinaryString(Handle); Write(Offset); Write(Length); diff --git a/src/Renci.SshNet/Sftp/Requests/SftpCloseRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpCloseRequest.cs index dd2dace1a..f17673f95 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpCloseRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpCloseRequest.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Sftp.Requests { - internal class SftpCloseRequest : SftpRequest + internal sealed class SftpCloseRequest : SftpRequest { public override SftpMessageTypes SftpMessageType { diff --git a/src/Renci.SshNet/Sftp/Requests/SftpFSetStatRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpFSetStatRequest.cs index 5de45c5ae..d24f757b8 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpFSetStatRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpFSetStatRequest.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Sftp.Requests { - internal class SftpFSetStatRequest : SftpRequest + internal sealed class SftpFSetStatRequest : SftpRequest { private byte[] _attributesBytes; @@ -20,10 +20,7 @@ private byte[] AttributesBytes { get { - if (_attributesBytes == null) - { - _attributesBytes = Attributes.GetBytes(); - } + _attributesBytes ??= Attributes.GetBytes(); return _attributesBytes; } } @@ -56,6 +53,7 @@ public SftpFSetStatRequest(uint protocolVersion, uint requestId, byte[] handle, protected override void LoadData() { base.LoadData(); + Handle = ReadBinary(); Attributes = ReadAttributes(); } @@ -63,6 +61,7 @@ protected override void LoadData() protected override void SaveData() { base.SaveData(); + WriteBinaryString(Handle); Write(AttributesBytes); } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpFStatRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpFStatRequest.cs index da71a62ea..6fa4576f6 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpFStatRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpFStatRequest.cs @@ -1,9 +1,10 @@ 锘縰sing System; + using Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Sftp.Requests { - internal class SftpFStatRequest : SftpRequest + internal sealed class SftpFStatRequest : SftpRequest { private readonly Action _attrsAction; @@ -52,8 +53,7 @@ protected override void SaveData() public override void Complete(SftpResponse response) { - var attrsResponse = response as SftpAttrsResponse; - if (attrsResponse != null) + if (response is SftpAttrsResponse attrsResponse) { _attrsAction(attrsResponse); } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpInitRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpInitRequest.cs index cb95c7c0e..25e21dabf 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpInitRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpInitRequest.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.Sftp.Requests { - internal class SftpInitRequest : SftpMessage + internal sealed class SftpInitRequest : SftpMessage { public override SftpMessageTypes SftpMessageType { diff --git a/src/Renci.SshNet/Sftp/Requests/SftpLStatRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpLStatRequest.cs index 1edb9c695..950ef8f43 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpLStatRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpLStatRequest.cs @@ -4,10 +4,10 @@ namespace Renci.SshNet.Sftp.Requests { - internal class SftpLStatRequest : SftpRequest + internal sealed class SftpLStatRequest : SftpRequest { - private byte[] _path; private readonly Action _attrsAction; + private byte[] _path; public override SftpMessageTypes SftpMessageType { @@ -61,8 +61,7 @@ protected override void SaveData() public override void Complete(SftpResponse response) { - var attrsResponse = response as SftpAttrsResponse; - if (attrsResponse != null) + if (response is SftpAttrsResponse attrsResponse) { _attrsAction(attrsResponse); } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpLinkRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpLinkRequest.cs index 04470b36f..063ad3b21 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpLinkRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpLinkRequest.cs @@ -1,9 +1,10 @@ -锘縰sing Renci.SshNet.Sftp.Responses; -using System; +锘縰sing System; + +using Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Sftp.Requests { - internal class SftpLinkRequest : SftpRequest + internal sealed class SftpLinkRequest : SftpRequest { private byte[] _newLinkPath; private byte[] _existingPath; @@ -67,6 +68,7 @@ public SftpLinkRequest(uint protocolVersion, uint requestId, string newLinkPath, protected override void LoadData() { base.LoadData(); + _newLinkPath = ReadBinary(); _existingPath = ReadBinary(); IsSymLink = ReadBoolean(); @@ -75,6 +77,7 @@ protected override void LoadData() protected override void SaveData() { base.SaveData(); + WriteBinaryString(_newLinkPath); WriteBinaryString(_existingPath); Write(IsSymLink); diff --git a/src/Renci.SshNet/Sftp/Requests/SftpMkDirRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpMkDirRequest.cs index 9dc60edc8..752e88c1d 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpMkDirRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpMkDirRequest.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Sftp.Requests { - internal class SftpMkDirRequest : SftpRequest + internal sealed class SftpMkDirRequest : SftpRequest { private byte[] _path; private byte[] _attributesBytes; @@ -32,6 +32,7 @@ private byte[] AttributesBytes { _attributesBytes = Attributes.GetBytes(); } + return _attributesBytes; } } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpOpenDirRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpOpenDirRequest.cs index 81a54b62d..cde5a7af3 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpOpenDirRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpOpenDirRequest.cs @@ -1,13 +1,14 @@ 锘縰sing System; using System.Text; + using Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Sftp.Requests { - internal class SftpOpenDirRequest : SftpRequest + internal sealed class SftpOpenDirRequest : SftpRequest { - private byte[] _path; private readonly Action _handleAction; + private byte[] _path; public override SftpMessageTypes SftpMessageType { @@ -64,8 +65,7 @@ protected override void SaveData() public override void Complete(SftpResponse response) { - var handleResponse = response as SftpHandleResponse; - if (handleResponse != null) + if (response is SftpHandleResponse handleResponse) { _handleAction(handleResponse); } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpOpenRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpOpenRequest.cs index da7a7a095..780552fbc 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpOpenRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpOpenRequest.cs @@ -4,11 +4,11 @@ namespace Renci.SshNet.Sftp.Requests { - internal class SftpOpenRequest : SftpRequest + internal sealed class SftpOpenRequest : SftpRequest { + private readonly Action _handleAction; private byte[] _fileName; private byte[] _attributes; - private readonly Action _handleAction; public override SftpMessageTypes SftpMessageType { @@ -21,7 +21,7 @@ public string Filename private set { _fileName = Encoding.GetBytes(value); } } - public Flags Flags { get; private set; } + public Flags Flags { get; } public SftpFileAttributes Attributes { @@ -29,7 +29,7 @@ public SftpFileAttributes Attributes private set { _attributes = value.GetBytes(); } } - public Encoding Encoding { get; private set; } + public Encoding Encoding { get; } /// /// Gets the size of the message in bytes. @@ -83,8 +83,7 @@ protected override void SaveData() public override void Complete(SftpResponse response) { - var handleResponse = response as SftpHandleResponse; - if (handleResponse != null) + if (response is SftpHandleResponse handleResponse) { _handleAction(handleResponse); } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpReadDirRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpReadDirRequest.cs index 9d46c69bd..9eae83253 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpReadDirRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpReadDirRequest.cs @@ -1,9 +1,10 @@ 锘縰sing System; + using Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Sftp.Requests { - internal class SftpReadDirRequest : SftpRequest + internal sealed class SftpReadDirRequest : SftpRequest { private readonly Action _nameAction; @@ -53,8 +54,7 @@ protected override void SaveData() public override void Complete(SftpResponse response) { - var nameResponse = response as SftpNameResponse; - if (nameResponse != null) + if (response is SftpNameResponse nameResponse) { _nameAction(nameResponse); } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpReadLinkRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpReadLinkRequest.cs index 90e36b69b..969eca564 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpReadLinkRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpReadLinkRequest.cs @@ -1,13 +1,14 @@ 锘縰sing System; using System.Text; + using Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Sftp.Requests { - internal class SftpReadLinkRequest : SftpRequest + internal sealed class SftpReadLinkRequest : SftpRequest { - private byte[] _path; private readonly Action _nameAction; + private byte[] _path; public override SftpMessageTypes SftpMessageType { @@ -20,7 +21,7 @@ public string Path private set { _path = Encoding.GetBytes(value); } } - public Encoding Encoding { get; private set; } + public Encoding Encoding { get; } /// /// Gets the size of the message in bytes. @@ -64,8 +65,7 @@ protected override void SaveData() public override void Complete(SftpResponse response) { - var nameResponse = response as SftpNameResponse; - if (nameResponse != null) + if (response is SftpNameResponse nameResponse) { _nameAction(nameResponse); } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpReadRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpReadRequest.cs index 72dc92877..b413b4a3a 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpReadRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpReadRequest.cs @@ -1,9 +1,10 @@ 锘縰sing System; + using Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Sftp.Requests { - internal class SftpReadRequest : SftpRequest + internal sealed class SftpReadRequest : SftpRequest { private readonly Action _dataAction; @@ -37,7 +38,7 @@ protected override int BufferCapacity } } - public SftpReadRequest(uint protocolVersion, uint requestId, byte[] handle, UInt64 offset, UInt32 length, Action dataAction, Action statusAction) + public SftpReadRequest(uint protocolVersion, uint requestId, byte[] handle, ulong offset, uint length, Action dataAction, Action statusAction) : base(protocolVersion, requestId, statusAction) { Handle = handle; @@ -49,6 +50,7 @@ public SftpReadRequest(uint protocolVersion, uint requestId, byte[] handle, UInt protected override void LoadData() { base.LoadData(); + Handle = ReadBinary(); Offset = ReadUInt64(); Length = ReadUInt32(); @@ -57,6 +59,7 @@ protected override void LoadData() protected override void SaveData() { base.SaveData(); + WriteBinaryString(Handle); Write(Offset); Write(Length); @@ -64,8 +67,7 @@ protected override void SaveData() public override void Complete(SftpResponse response) { - var dataResponse = response as SftpDataResponse; - if (dataResponse != null) + if (response is SftpDataResponse dataResponse) { _dataAction(dataResponse); } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpRealPathRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpRealPathRequest.cs index 44b11e90b..52e57bbe3 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpRealPathRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpRealPathRequest.cs @@ -1,13 +1,14 @@ 锘縰sing System; using System.Text; + using Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Sftp.Requests { - internal class SftpRealPathRequest : SftpRequest + internal sealed class SftpRealPathRequest : SftpRequest { - private byte[] _path; private readonly Action _nameAction; + private byte[] _path; public override SftpMessageTypes SftpMessageType { @@ -20,7 +21,7 @@ public string Path private set { _path = Encoding.GetBytes(value); } } - public Encoding Encoding { get; private set; } + public Encoding Encoding { get; } /// /// Gets the size of the message in bytes. @@ -43,11 +44,12 @@ public SftpRealPathRequest(uint protocolVersion, uint requestId, string path, En : base(protocolVersion, requestId, statusAction) { if (nameAction == null) - throw new ArgumentNullException("nameAction"); + { + throw new ArgumentNullException(nameof(nameAction)); + } Encoding = encoding; Path = path; - _nameAction = nameAction; } @@ -59,8 +61,7 @@ protected override void SaveData() public override void Complete(SftpResponse response) { - var nameResponse = response as SftpNameResponse; - if (nameResponse != null) + if (response is SftpNameResponse nameResponse) { _nameAction(nameResponse); } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpRemoveRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpRemoveRequest.cs index a527165c9..99d072f50 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpRemoveRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpRemoveRequest.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Sftp.Requests { - internal class SftpRemoveRequest : SftpRequest + internal sealed class SftpRemoveRequest : SftpRequest { private byte[] _fileName; diff --git a/src/Renci.SshNet/Sftp/Requests/SftpRenameRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpRenameRequest.cs index c6cf98f16..8d7fc91a2 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpRenameRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpRenameRequest.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Sftp.Requests { - internal class SftpRenameRequest : SftpRequest + internal sealed class SftpRenameRequest : SftpRequest { private byte[] _oldPath; private byte[] _newPath; diff --git a/src/Renci.SshNet/Sftp/Requests/SftpRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpRequest.cs index 88458e5fa..a3e4d0595 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpRequest.cs @@ -7,9 +7,9 @@ internal abstract class SftpRequest : SftpMessage { private readonly Action _statusAction; - public uint RequestId { get; private set; } - - public uint ProtocolVersion { get; private set; } + public uint RequestId { get; } + + public uint ProtocolVersion { get; } /// /// Gets the size of the message in bytes. @@ -36,8 +36,7 @@ protected SftpRequest(uint protocolVersion, uint requestId, Action _attrsAction; + private byte[] _path; public override SftpMessageTypes SftpMessageType { @@ -20,7 +20,7 @@ public string Path private set { _path = Encoding.GetBytes(value); } } - public Encoding Encoding { get; private set; } + public Encoding Encoding { get; } /// /// Gets the size of the message in bytes. @@ -50,19 +50,20 @@ public SftpStatRequest(uint protocolVersion, uint requestId, string path, Encodi protected override void LoadData() { base.LoadData(); + _path = ReadBinary(); } protected override void SaveData() { base.SaveData(); + WriteBinaryString(_path); } public override void Complete(SftpResponse response) { - var attrsResponse = response as SftpAttrsResponse; - if (attrsResponse != null) + if (response is SftpAttrsResponse attrsResponse) { _attrsAction(attrsResponse); } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpSymLinkRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpSymLinkRequest.cs index b338923ee..63127cdd5 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpSymLinkRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpSymLinkRequest.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Sftp.Requests { - internal class SftpSymLinkRequest : SftpRequest + internal sealed class SftpSymLinkRequest : SftpRequest { private byte[] _newLinkPath; private byte[] _existingPath; diff --git a/src/Renci.SshNet/Sftp/Requests/SftpUnblockRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpUnblockRequest.cs index 7f4a2147a..6dff38360 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpUnblockRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpUnblockRequest.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Sftp.Requests { - internal class SftpUnblockRequest : SftpRequest + internal sealed class SftpUnblockRequest : SftpRequest { public override SftpMessageTypes SftpMessageType { @@ -35,7 +35,7 @@ protected override int BufferCapacity } } - public SftpUnblockRequest(uint protocolVersion, uint requestId, byte[] handle, UInt64 offset, UInt64 length, Action statusAction) + public SftpUnblockRequest(uint protocolVersion, uint requestId, byte[] handle, ulong offset, ulong length, Action statusAction) : base(protocolVersion, requestId, statusAction) { Handle = handle; @@ -46,6 +46,7 @@ public SftpUnblockRequest(uint protocolVersion, uint requestId, byte[] handle, U protected override void LoadData() { base.LoadData(); + Handle = ReadBinary(); Offset = ReadUInt64(); Length = ReadUInt64(); @@ -54,6 +55,7 @@ protected override void LoadData() protected override void SaveData() { base.SaveData(); + WriteBinaryString(Handle); Write(Offset); Write(Length); diff --git a/src/Renci.SshNet/Sftp/Requests/SftpWriteRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpWriteRequest.cs index 6e8ca3166..be7f6da91 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpWriteRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpWriteRequest.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Sftp.Requests { - internal class SftpWriteRequest : SftpRequest + internal sealed class SftpWriteRequest : SftpRequest { public override SftpMessageTypes SftpMessageType { @@ -81,6 +81,7 @@ public SftpWriteRequest(uint protocolVersion, protected override void LoadData() { base.LoadData(); + Handle = ReadBinary(); ServerFileOffset = ReadUInt64(); Data = ReadBinary(); @@ -91,6 +92,7 @@ protected override void LoadData() protected override void SaveData() { base.SaveData(); + WriteBinaryString(Handle); Write(ServerFileOffset); WriteBinary(Data, Offset, Length); diff --git a/src/Renci.SshNet/Sftp/Responses/ExtendedReplies/StatVfsReplyInfo.cs b/src/Renci.SshNet/Sftp/Responses/ExtendedReplies/StatVfsReplyInfo.cs index 71c45dc15..768764419 100644 --- a/src/Renci.SshNet/Sftp/Responses/ExtendedReplies/StatVfsReplyInfo.cs +++ b/src/Renci.SshNet/Sftp/Responses/ExtendedReplies/StatVfsReplyInfo.cs @@ -2,7 +2,7 @@ namespace Renci.SshNet.Sftp.Responses { - internal class StatVfsReplyInfo : ExtendedReplyInfo + internal sealed class StatVfsReplyInfo : ExtendedReplyInfo { public SftpFileSytemInformation Information { get; private set; } @@ -22,4 +22,4 @@ public override void LoadData(SshDataStream stream) ); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Sftp/Responses/SftpAttrsResponse.cs b/src/Renci.SshNet/Sftp/Responses/SftpAttrsResponse.cs index fbf3250e9..f26aa5d33 100644 --- a/src/Renci.SshNet/Sftp/Responses/SftpAttrsResponse.cs +++ b/src/Renci.SshNet/Sftp/Responses/SftpAttrsResponse.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.Sftp.Responses { - internal class SftpAttrsResponse : SftpResponse + internal sealed class SftpAttrsResponse : SftpResponse { public override SftpMessageTypes SftpMessageType { @@ -17,6 +17,7 @@ public SftpAttrsResponse(uint protocolVersion) protected override void LoadData() { base.LoadData(); + Attributes = ReadAttributes(); } } diff --git a/src/Renci.SshNet/Sftp/Responses/SftpDataResponse.cs b/src/Renci.SshNet/Sftp/Responses/SftpDataResponse.cs index f15a8dcc0..ce0d414c5 100644 --- a/src/Renci.SshNet/Sftp/Responses/SftpDataResponse.cs +++ b/src/Renci.SshNet/Sftp/Responses/SftpDataResponse.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.Sftp.Responses { - internal class SftpDataResponse : SftpResponse + internal sealed class SftpDataResponse : SftpResponse { public override SftpMessageTypes SftpMessageType { diff --git a/src/Renci.SshNet/Sftp/Responses/SftpHandleResponse.cs b/src/Renci.SshNet/Sftp/Responses/SftpHandleResponse.cs index 233e3e371..31da2e937 100644 --- a/src/Renci.SshNet/Sftp/Responses/SftpHandleResponse.cs +++ b/src/Renci.SshNet/Sftp/Responses/SftpHandleResponse.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.Sftp.Responses { - internal class SftpHandleResponse : SftpResponse + internal sealed class SftpHandleResponse : SftpResponse { public override SftpMessageTypes SftpMessageType { diff --git a/src/Renci.SshNet/Sftp/Responses/SftpNameResponse.cs b/src/Renci.SshNet/Sftp/Responses/SftpNameResponse.cs index 3750119d4..059831052 100644 --- a/src/Renci.SshNet/Sftp/Responses/SftpNameResponse.cs +++ b/src/Renci.SshNet/Sftp/Responses/SftpNameResponse.cs @@ -1,10 +1,11 @@ -锘縰sing Renci.SshNet.Common; -using System.Collections.Generic; +锘縰sing System.Collections.Generic; using System.Text; +using Renci.SshNet.Common; + namespace Renci.SshNet.Sftp.Responses { - internal class SftpNameResponse : SftpResponse + internal sealed class SftpNameResponse : SftpResponse { public override SftpMessageTypes SftpMessageType { @@ -27,7 +28,7 @@ public SftpNameResponse(uint protocolVersion, Encoding encoding) protected override void LoadData() { base.LoadData(); - + Count = ReadUInt32(); Files = new KeyValuePair[Count]; @@ -36,8 +37,9 @@ protected override void LoadData() var fileName = ReadString(Encoding); if (SupportsLongName(ProtocolVersion)) { - ReadString(Encoding); // skip longname + _ = ReadString(Encoding); // skip longname } + Files[i] = new KeyValuePair(fileName, ReadAttributes()); } } diff --git a/src/Renci.SshNet/Sftp/Responses/SftpStatusResponse.cs b/src/Renci.SshNet/Sftp/Responses/SftpStatusResponse.cs index f41692f04..2f43cdc37 100644 --- a/src/Renci.SshNet/Sftp/Responses/SftpStatusResponse.cs +++ b/src/Renci.SshNet/Sftp/Responses/SftpStatusResponse.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.Sftp.Responses { - internal class SftpStatusResponse : SftpResponse + internal sealed class SftpStatusResponse : SftpResponse { public override SftpMessageTypes SftpMessageType { diff --git a/src/Renci.SshNet/Sftp/Responses/SftpVersionResponse.cs b/src/Renci.SshNet/Sftp/Responses/SftpVersionResponse.cs index 87c9f13f3..1ae8e6d6a 100644 --- a/src/Renci.SshNet/Sftp/Responses/SftpVersionResponse.cs +++ b/src/Renci.SshNet/Sftp/Responses/SftpVersionResponse.cs @@ -2,7 +2,7 @@ namespace Renci.SshNet.Sftp.Responses { - internal class SftpVersionResponse : SftpMessage + internal sealed class SftpVersionResponse : SftpMessage { public override SftpMessageTypes SftpMessageType { @@ -16,6 +16,7 @@ public override SftpMessageTypes SftpMessageType protected override void LoadData() { base.LoadData(); + Version = ReadUInt32(); Extentions = ReadExtensionPair(); } @@ -25,8 +26,11 @@ protected override void SaveData() base.SaveData(); Write(Version); + if (Extentions != null) + { Write(Extentions); + } } } } diff --git a/src/Renci.SshNet/Sftp/SFtpStatAsyncResult.cs b/src/Renci.SshNet/Sftp/SFtpStatAsyncResult.cs index d3776ce21..41d915499 100644 --- a/src/Renci.SshNet/Sftp/SFtpStatAsyncResult.cs +++ b/src/Renci.SshNet/Sftp/SFtpStatAsyncResult.cs @@ -1,11 +1,13 @@ -锘縰sing Renci.SshNet.Common; -using System; +锘縰sing System; + +using Renci.SshNet.Common; namespace Renci.SshNet.Sftp { - internal class SFtpStatAsyncResult : AsyncResult + internal sealed class SFtpStatAsyncResult : AsyncResult { - public SFtpStatAsyncResult(AsyncCallback asyncCallback, object state) : base(asyncCallback, state) + public SFtpStatAsyncResult(AsyncCallback asyncCallback, object state) + : base(asyncCallback, state) { } } diff --git a/src/Renci.SshNet/Sftp/SftpCloseAsyncResult.cs b/src/Renci.SshNet/Sftp/SftpCloseAsyncResult.cs index 6349371f0..d4148e5c7 100644 --- a/src/Renci.SshNet/Sftp/SftpCloseAsyncResult.cs +++ b/src/Renci.SshNet/Sftp/SftpCloseAsyncResult.cs @@ -1,11 +1,13 @@ -锘縰sing Renci.SshNet.Common; -using System; +锘縰sing System; + +using Renci.SshNet.Common; namespace Renci.SshNet.Sftp { - internal class SftpCloseAsyncResult : AsyncResult + internal sealed class SftpCloseAsyncResult : AsyncResult { - public SftpCloseAsyncResult(AsyncCallback asyncCallback, object state) : base(asyncCallback, state) + public SftpCloseAsyncResult(AsyncCallback asyncCallback, object state) + : base(asyncCallback, state) { } } diff --git a/src/Renci.SshNet/Sftp/SftpFile.cs b/src/Renci.SshNet/Sftp/SftpFile.cs index 6356d26ce..07d1039e1 100644 --- a/src/Renci.SshNet/Sftp/SftpFile.cs +++ b/src/Renci.SshNet/Sftp/SftpFile.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Sftp { /// - /// Represents SFTP file information + /// Represents SFTP file information. /// public sealed class SftpFile : ISftpFile { @@ -26,31 +26,44 @@ public sealed class SftpFile : ISftpFile internal SftpFile(ISftpSession sftpSession, string fullName, SftpFileAttributes attributes) { if (sftpSession == null) + { throw new SshConnectionException("Client not connected."); + } if (attributes == null) - throw new ArgumentNullException("attributes"); + { + throw new ArgumentNullException(nameof(attributes)); + } if (fullName == null) - throw new ArgumentNullException("fullName"); + { + throw new ArgumentNullException(nameof(fullName)); + } _sftpSession = sftpSession; Attributes = attributes; - Name = fullName.Substring(fullName.LastIndexOf('/') + 1); - FullName = fullName; } /// - /// Gets the full path of the directory or file. + /// Gets the full path of the file or directory. /// + /// + /// The full path of the file or directory. + /// public string FullName { get; private set; } /// - /// For files, gets the name of the file. For directories, gets the name of the last directory in the hierarchy if a hierarchy exists. - /// Otherwise, the Name property gets the name of the directory. + /// Gets the name of the file or directory. /// + /// + /// The name of the file or directory. + /// + /// + /// For directories, this is the name of the last directory in the hierarchy if a hierarchy exists; + /// otherwise, the name of the directory. + /// public string Name { get; private set; } /// @@ -126,7 +139,7 @@ public DateTime LastWriteTimeUtc } /// - /// Gets or sets the size, in bytes, of the current file. + /// Gets the size, in bytes, of the current file. /// /// /// The size of the current file in bytes. @@ -179,7 +192,7 @@ public int GroupId /// Gets a value indicating whether file represents a socket. /// /// - /// true if file represents a socket; otherwise, false. + /// true if file represents a socket; otherwise, false. /// public bool IsSocket { @@ -193,7 +206,7 @@ public bool IsSocket /// Gets a value indicating whether file represents a symbolic link. /// /// - /// true if file represents a symbolic link; otherwise, false. + /// true if file represents a symbolic link; otherwise, false. /// public bool IsSymbolicLink { @@ -207,7 +220,7 @@ public bool IsSymbolicLink /// Gets a value indicating whether file represents a regular file. /// /// - /// true if file represents a regular file; otherwise, false. + /// true if file represents a regular file; otherwise, false. /// public bool IsRegularFile { @@ -221,7 +234,7 @@ public bool IsRegularFile /// Gets a value indicating whether file represents a block device. /// /// - /// true if file represents a block device; otherwise, false. + /// true if file represents a block device; otherwise, false. /// public bool IsBlockDevice { @@ -235,7 +248,7 @@ public bool IsBlockDevice /// Gets a value indicating whether file represents a directory. /// /// - /// true if file represents a directory; otherwise, false. + /// true if file represents a directory; otherwise, false. /// public bool IsDirectory { @@ -249,7 +262,7 @@ public bool IsDirectory /// Gets a value indicating whether file represents a character device. /// /// - /// true if file represents a character device; otherwise, false. + /// true if file represents a character device; otherwise, false. /// public bool IsCharacterDevice { @@ -263,7 +276,7 @@ public bool IsCharacterDevice /// Gets a value indicating whether file represents a named pipe. /// /// - /// true if file represents a named pipe; otherwise, false. + /// true if file represents a named pipe; otherwise, false. /// public bool IsNamedPipe { @@ -277,7 +290,7 @@ public bool IsNamedPipe /// Gets or sets a value indicating whether the owner can read from this file. /// /// - /// true if owner can read from this file; otherwise, false. + /// true if owner can read from this file; otherwise, false. /// public bool OwnerCanRead { @@ -295,7 +308,7 @@ public bool OwnerCanRead /// Gets or sets a value indicating whether the owner can write into this file. /// /// - /// true if owner can write into this file; otherwise, false. + /// true if owner can write into this file; otherwise, false. /// public bool OwnerCanWrite { @@ -313,7 +326,7 @@ public bool OwnerCanWrite /// Gets or sets a value indicating whether the owner can execute this file. /// /// - /// true if owner can execute this file; otherwise, false. + /// true if owner can execute this file; otherwise, false. /// public bool OwnerCanExecute { @@ -331,7 +344,7 @@ public bool OwnerCanExecute /// Gets or sets a value indicating whether the group members can read from this file. /// /// - /// true if group members can read from this file; otherwise, false. + /// true if group members can read from this file; otherwise, false. /// public bool GroupCanRead { @@ -349,7 +362,7 @@ public bool GroupCanRead /// Gets or sets a value indicating whether the group members can write into this file. /// /// - /// true if group members can write into this file; otherwise, false. + /// true if group members can write into this file; otherwise, false. /// public bool GroupCanWrite { @@ -367,7 +380,7 @@ public bool GroupCanWrite /// Gets or sets a value indicating whether the group members can execute this file. /// /// - /// true if group members can execute this file; otherwise, false. + /// true if group members can execute this file; otherwise, false. /// public bool GroupCanExecute { @@ -385,7 +398,7 @@ public bool GroupCanExecute /// Gets or sets a value indicating whether the others can read from this file. /// /// - /// true if others can read from this file; otherwise, false. + /// true if others can read from this file; otherwise, false. /// public bool OthersCanRead { @@ -403,7 +416,7 @@ public bool OthersCanRead /// Gets or sets a value indicating whether the others can write into this file. /// /// - /// true if others can write into this file; otherwise, false. + /// true if others can write into this file; otherwise, false. /// public bool OthersCanWrite { @@ -421,7 +434,7 @@ public bool OthersCanWrite /// Gets or sets a value indicating whether the others can execute this file. /// /// - /// true if others can execute this file; otherwise, false. + /// true if others can execute this file; otherwise, false. /// public bool OthersCanExecute { @@ -436,7 +449,7 @@ public bool OthersCanExecute } /// - /// Sets file permissions. + /// Sets file permissions. /// /// The mode. public void SetPermissions(short mode) @@ -469,7 +482,10 @@ public void Delete() public void MoveTo(string destFileName) { if (destFileName == null) - throw new ArgumentNullException("destFileName"); + { + throw new ArgumentNullException(nameof(destFileName)); + } + _sftpSession.RequestRename(FullName, destFileName); var fullPath = _sftpSession.GetCanonicalPath(destFileName); @@ -488,14 +504,21 @@ public void UpdateStatus() } /// - /// Returns a that represents this instance. + /// Returns a that represents this instance. /// /// - /// A that represents this instance. + /// A that represents this instance. /// public override string ToString() { - return string.Format(CultureInfo.CurrentCulture, "Name {0}, Length {1}, User ID {2}, Group ID {3}, Accessed {4}, Modified {5}", Name, Length, UserId, GroupId, LastAccessTime, LastWriteTime); + return string.Format(CultureInfo.CurrentCulture, + "Name {0}, Length {1}, User ID {2}, Group ID {3}, Accessed {4}, Modified {5}", + Name, + Length, + UserId, + GroupId, + LastAccessTime, + LastWriteTime); } } } diff --git a/src/Renci.SshNet/Sftp/SftpFileAttributes.cs b/src/Renci.SshNet/Sftp/SftpFileAttributes.cs index 573deb92a..901d6ee5a 100644 --- a/src/Renci.SshNet/Sftp/SftpFileAttributes.cs +++ b/src/Renci.SshNet/Sftp/SftpFileAttributes.cs @@ -1,9 +1,9 @@ 锘縰sing System; using System.Collections.Generic; -using System.Linq; using System.Globalization; +using System.Linq; + using Renci.SshNet.Common; -using System.Diagnostics; namespace Renci.SshNet.Sftp { @@ -12,54 +12,45 @@ namespace Renci.SshNet.Sftp /// public class SftpFileAttributes { - #region Bitmask constants - - private const uint S_IFMT = 0xF000; // bitmask for the file type bitfields + private const uint S_IFMT = 0xF000; // bitmask for the file type bitfields - private const uint S_IFSOCK = 0xC000; // socket + private const uint S_IFSOCK = 0xC000; // socket - private const uint S_IFLNK = 0xA000; // symbolic link + private const uint S_IFLNK = 0xA000; // symbolic link - private const uint S_IFREG = 0x8000; // regular file + private const uint S_IFREG = 0x8000; // regular file - private const uint S_IFBLK = 0x6000; // block device + private const uint S_IFBLK = 0x6000; // block device - private const uint S_IFDIR = 0x4000; // directory + private const uint S_IFDIR = 0x4000; // directory - private const uint S_IFCHR = 0x2000; // character device + private const uint S_IFCHR = 0x2000; // character device - private const uint S_IFIFO = 0x1000; // FIFO + private const uint S_IFIFO = 0x1000; // FIFO - private const uint S_ISUID = 0x0800; // set UID bit + private const uint S_ISUID = 0x0800; // set UID bit - private const uint S_ISGID = 0x0400; // set-group-ID bit (see below) + private const uint S_ISGID = 0x0400; // set-group-ID bit (see below) - private const uint S_ISVTX = 0x0200; // sticky bit (see below) + private const uint S_ISVTX = 0x0200; // sticky bit (see below) - private const uint S_IRUSR = 0x0100; // owner has read permission + private const uint S_IRUSR = 0x0100; // owner has read permission - private const uint S_IWUSR = 0x0080; // owner has write permission + private const uint S_IWUSR = 0x0080; // owner has write permission - private const uint S_IXUSR = 0x0040; // owner has execute permission + private const uint S_IXUSR = 0x0040; // owner has execute permission - private const uint S_IRGRP = 0x0020; // group has read permission + private const uint S_IRGRP = 0x0020; // group has read permission - private const uint S_IWGRP = 0x0010; // group has write permission + private const uint S_IWGRP = 0x0010; // group has write permission - private const uint S_IXGRP = 0x0008; // group has execute permission + private const uint S_IXGRP = 0x0008; // group has execute permission - private const uint S_IROTH = 0x0004; // others have read permission + private const uint S_IROTH = 0x0004; // others have read permission - private const uint S_IWOTH = 0x0002; // others have write permission + private const uint S_IWOTH = 0x0002; // others have write permission - private const uint S_IXOTH = 0x0001; // others have execute permission - - #endregion - - private bool _isBitFiledsBitSet; - private bool _isUIDBitSet; - private bool _isGroupIDBitSet; - private bool _isStickyBitSet; + private const uint S_IXOTH = 0x0001; // others have execute permission private readonly DateTime _originalLastAccessTimeUtc; private readonly DateTime _originalLastWriteTimeUtc; @@ -69,6 +60,11 @@ public class SftpFileAttributes private readonly uint _originalPermissions; private readonly IDictionary _originalExtensions; + private bool _isBitFiledsBitSet; + private bool _isUIDBitSet; + private bool _isGroupIDBitSet; + private bool _isStickyBitSet; + internal bool IsLastAccessTimeChanged { get { return _originalLastAccessTimeUtc != LastAccessTimeUtc; } @@ -114,12 +110,12 @@ public DateTime LastAccessTime { get { - return ToLocalTime(this.LastAccessTimeUtc); + return ToLocalTime(LastAccessTimeUtc); } set { - this.LastAccessTimeUtc = ToUniversalTime(value); + LastAccessTimeUtc = ToUniversalTime(value); } } @@ -133,12 +129,12 @@ public DateTime LastWriteTime { get { - return ToLocalTime(this.LastWriteTimeUtc); + return ToLocalTime(LastWriteTimeUtc); } set { - this.LastWriteTimeUtc = ToUniversalTime(value); + LastWriteTimeUtc = ToUniversalTime(value); } } @@ -194,7 +190,7 @@ public DateTime LastWriteTime /// Gets a value indicating whether file represents a symbolic link. /// /// - /// true if file represents a symbolic link; otherwise, false. + /// true if file represents a symbolic link; otherwise, false. /// public bool IsSymbolicLink { get; private set; } @@ -202,7 +198,7 @@ public DateTime LastWriteTime /// Gets a value indicating whether file represents a regular file. /// /// - /// true if file represents a regular file; otherwise, false. + /// true if file represents a regular file; otherwise, false. /// public bool IsRegularFile { get; private set; } @@ -210,7 +206,7 @@ public DateTime LastWriteTime /// Gets a value indicating whether file represents a block device. /// /// - /// true if file represents a block device; otherwise, false. + /// true if file represents a block device; otherwise, false. /// public bool IsBlockDevice { get; private set; } @@ -218,7 +214,7 @@ public DateTime LastWriteTime /// Gets a value indicating whether file represents a directory. /// /// - /// true if file represents a directory; otherwise, false. + /// true if file represents a directory; otherwise, false. /// public bool IsDirectory { get; private set; } @@ -226,7 +222,7 @@ public DateTime LastWriteTime /// Gets a value indicating whether file represents a character device. /// /// - /// true if file represents a character device; otherwise, false. + /// true if file represents a character device; otherwise, false. /// public bool IsCharacterDevice { get; private set; } @@ -234,84 +230,84 @@ public DateTime LastWriteTime /// Gets a value indicating whether file represents a named pipe. /// /// - /// true if file represents a named pipe; otherwise, false. + /// true if file represents a named pipe; otherwise, false. /// public bool IsNamedPipe { get; private set; } /// - /// Gets a value indicating whether the owner can read from this file. + /// Gets or sets a value indicating whether the owner can read from this file. /// /// - /// true if owner can read from this file; otherwise, false. + /// true if owner can read from this file; otherwise, false. /// public bool OwnerCanRead { get; set; } /// - /// Gets a value indicating whether the owner can write into this file. + /// Gets or sets a value indicating whether the owner can write into this file. /// /// - /// true if owner can write into this file; otherwise, false. + /// true if owner can write into this file; otherwise, false. /// public bool OwnerCanWrite { get; set; } /// - /// Gets a value indicating whether the owner can execute this file. + /// Gets or sets a value indicating whether the owner can execute this file. /// /// - /// true if owner can execute this file; otherwise, false. + /// true if owner can execute this file; otherwise, false. /// public bool OwnerCanExecute { get; set; } /// - /// Gets a value indicating whether the group members can read from this file. + /// Gets or sets a value indicating whether the group members can read from this file. /// /// - /// true if group members can read from this file; otherwise, false. + /// true if group members can read from this file; otherwise, false. /// public bool GroupCanRead { get; set; } /// - /// Gets a value indicating whether the group members can write into this file. + /// Gets or sets a value indicating whether the group members can write into this file. /// /// - /// true if group members can write into this file; otherwise, false. + /// true if group members can write into this file; otherwise, false. /// public bool GroupCanWrite { get; set; } /// - /// Gets a value indicating whether the group members can execute this file. + /// Gets or sets a value indicating whether the group members can execute this file. /// /// - /// true if group members can execute this file; otherwise, false. + /// true if group members can execute this file; otherwise, false. /// public bool GroupCanExecute { get; set; } /// - /// Gets a value indicating whether the others can read from this file. + /// Gets or sets a value indicating whether the others can read from this file. /// /// - /// true if others can read from this file; otherwise, false. + /// true if others can read from this file; otherwise, false. /// public bool OthersCanRead { get; set; } /// - /// Gets a value indicating whether the others can write into this file. + /// Gets or sets a value indicating whether the others can write into this file. /// /// - /// true if others can write into this file; otherwise, false. + /// true if others can write into this file; otherwise, false. /// public bool OthersCanWrite { get; set; } /// - /// Gets a value indicating whether the others can execute this file. + /// Gets or sets a value indicating whether the others can execute this file. /// /// - /// true if others can execute this file; otherwise, false. + /// true if others can execute this file; otherwise, false. /// public bool OthersCanExecute { get; set; } /// - /// Gets or sets the extensions. + /// Gets the extensions. /// /// /// The extensions. @@ -325,108 +321,148 @@ internal uint Permissions uint permission = 0; if (_isBitFiledsBitSet) - permission = permission | S_IFMT; + { + permission |= S_IFMT; + } if (IsSocket) - permission = permission | S_IFSOCK; + { + permission |= S_IFSOCK; + } if (IsSymbolicLink) - permission = permission | S_IFLNK; + { + permission |= S_IFLNK; + } if (IsRegularFile) - permission = permission | S_IFREG; + { + permission |= S_IFREG; + } if (IsBlockDevice) - permission = permission | S_IFBLK; + { + permission |= S_IFBLK; + } if (IsDirectory) - permission = permission | S_IFDIR; + { + permission |= S_IFDIR; + } if (IsCharacterDevice) - permission = permission | S_IFCHR; + { + permission |= S_IFCHR; + } if (IsNamedPipe) - permission = permission | S_IFIFO; + { + permission |= S_IFIFO; + } if (_isUIDBitSet) - permission = permission | S_ISUID; + { + permission |= S_ISUID; + } if (_isGroupIDBitSet) - permission = permission | S_ISGID; + { + permission |= S_ISGID; + } if (_isStickyBitSet) - permission = permission | S_ISVTX; + { + permission |= S_ISVTX; + } if (OwnerCanRead) - permission = permission | S_IRUSR; + { + permission |= S_IRUSR; + } if (OwnerCanWrite) - permission = permission | S_IWUSR; + { + permission |= S_IWUSR; + } if (OwnerCanExecute) - permission = permission | S_IXUSR; + { + permission |= S_IXUSR; + } if (GroupCanRead) - permission = permission | S_IRGRP; + { + permission |= S_IRGRP; + } if (GroupCanWrite) - permission = permission | S_IWGRP; + { + permission |= S_IWGRP; + } if (GroupCanExecute) - permission = permission | S_IXGRP; + { + permission |= S_IXGRP; + } if (OthersCanRead) - permission = permission | S_IROTH; + { + permission |= S_IROTH; + } if (OthersCanWrite) - permission = permission | S_IWOTH; + { + permission |= S_IWOTH; + } if (OthersCanExecute) - permission = permission | S_IXOTH; + { + permission |= S_IXOTH; + } return permission; } private set { - _isBitFiledsBitSet = ((value & S_IFMT) == S_IFMT); + _isBitFiledsBitSet = (value & S_IFMT) == S_IFMT; - IsSocket = ((value & S_IFSOCK) == S_IFSOCK); + IsSocket = (value & S_IFSOCK) == S_IFSOCK; - IsSymbolicLink = ((value & S_IFLNK) == S_IFLNK); + IsSymbolicLink = (value & S_IFLNK) == S_IFLNK; - IsRegularFile = ((value & S_IFREG) == S_IFREG); + IsRegularFile = (value & S_IFREG) == S_IFREG; - IsBlockDevice = ((value & S_IFBLK) == S_IFBLK); + IsBlockDevice = (value & S_IFBLK) == S_IFBLK; - IsDirectory = ((value & S_IFDIR) == S_IFDIR); + IsDirectory = (value & S_IFDIR) == S_IFDIR; - IsCharacterDevice = ((value & S_IFCHR) == S_IFCHR); + IsCharacterDevice = (value & S_IFCHR) == S_IFCHR; - IsNamedPipe = ((value & S_IFIFO) == S_IFIFO); + IsNamedPipe = (value & S_IFIFO) == S_IFIFO; - _isUIDBitSet = ((value & S_ISUID) == S_ISUID); + _isUIDBitSet = (value & S_ISUID) == S_ISUID; - _isGroupIDBitSet = ((value & S_ISGID) == S_ISGID); + _isGroupIDBitSet = (value & S_ISGID) == S_ISGID; - _isStickyBitSet = ((value & S_ISVTX) == S_ISVTX); + _isStickyBitSet = (value & S_ISVTX) == S_ISVTX; - OwnerCanRead = ((value & S_IRUSR) == S_IRUSR); + OwnerCanRead = (value & S_IRUSR) == S_IRUSR; - OwnerCanWrite = ((value & S_IWUSR) == S_IWUSR); + OwnerCanWrite = (value & S_IWUSR) == S_IWUSR; - OwnerCanExecute = ((value & S_IXUSR) == S_IXUSR); + OwnerCanExecute = (value & S_IXUSR) == S_IXUSR; - GroupCanRead = ((value & S_IRGRP) == S_IRGRP); + GroupCanRead = (value & S_IRGRP) == S_IRGRP; - GroupCanWrite = ((value & S_IWGRP) == S_IWGRP); + GroupCanWrite = (value & S_IWGRP) == S_IWGRP; - GroupCanExecute = ((value & S_IXGRP) == S_IXGRP); + GroupCanExecute = (value & S_IXGRP) == S_IXGRP; - OthersCanRead = ((value & S_IROTH) == S_IROTH); + OthersCanRead = (value & S_IROTH) == S_IROTH; - OthersCanWrite = ((value & S_IWOTH) == S_IWOTH); + OthersCanWrite = (value & S_IWOTH) == S_IWOTH; - OthersCanExecute = ((value & S_IXOTH) == S_IXOTH); + OthersCanExecute = (value & S_IXOTH) == S_IXOTH; } } @@ -451,9 +487,9 @@ internal SftpFileAttributes(DateTime lastAccessTimeUtc, DateTime lastWriteTimeUt /// The mode. public void SetPermissions(short mode) { - if (mode < 0 || mode > 999) + if (mode is < 0 or > 999) { - throw new ArgumentOutOfRangeException("mode"); + throw new ArgumentOutOfRangeException(nameof(mode)); } var modeBytes = mode.ToString(CultureInfo.InvariantCulture).PadLeft(3, '0').ToCharArray(); @@ -562,26 +598,26 @@ internal static SftpFileAttributes FromBytes(SshDataStream stream) uint permissions = 0; DateTime accessTime; DateTime modifyTime; - IDictionary extensions = null; + Dictionary extensions = null; - if ((flag & 0x00000001) == 0x00000001) // SSH_FILEXFER_ATTR_SIZE + if ((flag & 0x00000001) == 0x00000001) // SSH_FILEXFER_ATTR_SIZE { size = (long) stream.ReadUInt64(); } - if ((flag & 0x00000002) == 0x00000002) // SSH_FILEXFER_ATTR_UIDGID + if ((flag & 0x00000002) == 0x00000002) // SSH_FILEXFER_ATTR_UIDGID { userId = (int) stream.ReadUInt32(); groupId = (int) stream.ReadUInt32(); } - if ((flag & 0x00000004) == 0x00000004) // SSH_FILEXFER_ATTR_PERMISSIONS + if ((flag & 0x00000004) == 0x00000004) // SSH_FILEXFER_ATTR_PERMISSIONS { permissions = stream.ReadUInt32(); } - if ((flag & 0x00000008) == 0x00000008) // SSH_FILEXFER_ATTR_ACMODTIME + if ((flag & 0x00000008) == 0x00000008) // SSH_FILEXFER_ATTR_ACMODTIME { // The incoming times are "Unix times", so they're already in UTC. We need to preserve that // to avoid losing information in a local time conversion during the "fall back" hour in DST. @@ -596,7 +632,7 @@ internal static SftpFileAttributes FromBytes(SshDataStream stream) modifyTime = DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc); } - if ((flag & 0x80000000) == 0x80000000) // SSH_FILEXFER_ATTR_EXTENDED + if ((flag & 0x80000000) == 0x80000000) // SSH_FILEXFER_ATTR_EXTENDED { var extendedCount = (int) stream.ReadUInt32(); extensions = new Dictionary(extendedCount); diff --git a/src/Renci.SshNet/Sftp/SftpFileReader.cs b/src/Renci.SshNet/Sftp/SftpFileReader.cs index a881e9c03..a6a1f0898 100644 --- a/src/Renci.SshNet/Sftp/SftpFileReader.cs +++ b/src/Renci.SshNet/Sftp/SftpFileReader.cs @@ -1,10 +1,11 @@ -锘縰sing Renci.SshNet.Abstractions; -using Renci.SshNet.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Globalization; using System.Threading; +using Renci.SshNet.Abstractions; +using Renci.SshNet.Common; + namespace Renci.SshNet.Sftp { internal class SftpFileReader : ISftpFileReader @@ -14,42 +15,43 @@ internal class SftpFileReader : ISftpFileReader private readonly byte[] _handle; private readonly ISftpSession _sftpSession; private readonly uint _chunkSize; - private ulong _offset; + private readonly SemaphoreLight _semaphore; + private readonly object _readLock; + private readonly ManualResetEvent _disposingWaitHandle; + private readonly ManualResetEvent _readAheadCompleted; + private readonly Dictionary _queue; + private readonly WaitHandle[] _waitHandles; /// /// Holds the size of the file, when available. /// private readonly long? _fileSize; - private readonly Dictionary _queue; - private readonly WaitHandle[] _waitHandles; + private ulong _offset; private int _readAheadChunkIndex; private ulong _readAheadOffset; - private readonly ManualResetEvent _readAheadCompleted; private int _nextChunkIndex; /// /// Holds a value indicating whether EOF has already been signaled by the SSH server. /// private bool _endOfFileReceived; + /// /// Holds a value indicating whether the client has read up to the end of the file. /// private bool _isEndOfFileRead; - private readonly SemaphoreLight _semaphore; - private readonly object _readLock; - private readonly ManualResetEvent _disposingWaitHandle; private bool _disposingOrDisposed; private Exception _exception; /// - /// Initializes a new instance with the specified handle, + /// Initializes a new instance of the class with the specified handle, /// and the maximum number of pending reads. /// - /// - /// + /// The file handle. + /// The SFT session. /// The size of a individual read-ahead chunk. /// The maximum number of pending reads. /// The size of the file, if known; otherwise, null. @@ -72,11 +74,19 @@ public SftpFileReader(byte[] handle, ISftpSession sftpSession, uint chunkSize, i public byte[] Read() { if (_disposingOrDisposed) + { throw new ObjectDisposedException(GetType().FullName); + } + if (_exception != null) + { throw _exception; + } + if (_isEndOfFileRead) + { throw new SshException("Attempting to read beyond the end of the file."); + } BufferedRead nextChunk; @@ -86,12 +96,14 @@ public byte[] Read() // instance is already disposed while (!_queue.TryGetValue(_nextChunkIndex, out nextChunk) && _exception == null) { - Monitor.Wait(_readLock); + _ =Monitor.Wait(_readLock); } // throw when exception occured in read-ahead, or the current instance is already disposed if (_exception != null) + { throw _exception; + } var data = nextChunk.Data; @@ -101,20 +113,22 @@ public byte[] Read() if (data.Length == 0) { // PERF: we do not bother updating all of the internal state when we've reached EOF - _isEndOfFileRead = true; } else { // remove processed chunk - _queue.Remove(_nextChunkIndex); + _ = _queue.Remove(_nextChunkIndex); + // update offset _offset += (ulong) data.Length; + // move to next chunk _nextChunkIndex++; } + // unblock wait in read-ahead - _semaphore.Release(); + _ = _semaphore.Release(); return data; } @@ -126,26 +140,30 @@ public byte[] Read() { // avoid future reads _isEndOfFileRead = true; + // unblock wait in read-ahead - _semaphore.Release(); + _ = _semaphore.Release(); + // signal EOF to caller return nextChunk.Data; } } - // When the server returned less bytes than requested (for the previous chunk) - // we'll synchronously request the remaining data. - // - // Due to the optimization above, we'll only get here in one of the following cases: - // - an EOF situation for files for which we were unable to obtain the file size - // - fewer bytes that requested were returned - // - // According to the SSH specification, this last case should never happen for normal - // disk files (but can happen for device files). In practice, OpenSSH - for example - - // returns less bytes than requested when requesting more than 64 KB. - // - // Important: - // To avoid a deadlock, this read must be done outside of the read lock + /* + * When the server returned less bytes than requested (for the previous chunk) + * we'll synchronously request the remaining data. + * + * Due to the optimization above, we'll only get here in one of the following cases: + * - an EOF situation for files for which we were unable to obtain the file size + * - fewer bytes that requested were returned + * + * According to the SSH specification, this last case should never happen for normal + * disk files (but can happen for device files). In practice, OpenSSH - for example - + * returns less bytes than requested when requesting more than 64 KB. + * + * Important: + * To avoid a deadlock, this read must be done outside of the read lock. + */ var bytesToCatchUp = nextChunk.Offset - _offset; @@ -162,24 +180,28 @@ public byte[] Read() if (nextChunk.Data.Length == 0) { _isEndOfFileRead = true; + // ensure we've not yet disposed the current instance if (!_disposingOrDisposed) { // unblock wait in read-ahead - _semaphore.Release(); + _ = _semaphore.Release(); } + // signal EOF to caller return read; } // move reader to error state _exception = new SshException("Unexpectedly reached end of file."); + // ensure we've not yet disposed the current instance if (!_disposingOrDisposed) { // unblock wait in read-ahead - _semaphore.Release(); + _ = _semaphore.Release(); } + // notify caller of error throw _exception; } @@ -202,13 +224,15 @@ public void Dispose() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected void Dispose(bool disposing) { if (_disposingOrDisposed) + { return; + } // transition to disposing state _disposingOrDisposed = true; @@ -219,10 +243,10 @@ protected void Dispose(bool disposing) _exception = new ObjectDisposedException(GetType().FullName); // signal that we're disposing to interrupt wait in read-ahead - _disposingWaitHandle.Set(); + _ = _disposingWaitHandle.Set(); // wait until the read-ahead thread has completed - _readAheadCompleted.WaitOne(); + _ = _readAheadCompleted.WaitOne(); // unblock the Read() lock (_readLock) @@ -230,6 +254,7 @@ protected void Dispose(bool disposing) // dispose semaphore in read lock to ensure we don't run into an ObjectDisposedException // in Read() _semaphore.Dispose(); + // awake Read Monitor.PulseAll(_readLock); } @@ -269,6 +294,7 @@ private void StartReadAhead() { Monitor.PulseAll(_readLock); } + // break the read-ahead loop break; } @@ -285,7 +311,9 @@ private void StartReadAhead() // don't bother reading any more chunks if we received EOF, an exception has occurred // or the current instance is disposed if (_endOfFileReceived || _exception != null) + { break; + } // start reading next chunk var bufferedRead = new BufferedRead(_readAheadChunkIndex, _readAheadOffset); @@ -301,14 +329,13 @@ private void StartReadAhead() // mode to avoid having multiple read-aheads that read beyond EOF if (_fileSize != null && (long) _readAheadOffset > _fileSize.Value) { - var asyncResult = _sftpSession.BeginRead(_handle, _readAheadOffset, _chunkSize, null, - bufferedRead); + var asyncResult = _sftpSession.BeginRead(_handle, _readAheadOffset, _chunkSize, null, bufferedRead); var data = _sftpSession.EndRead(asyncResult); ReadCompletedCore(bufferedRead, data); } else { - _sftpSession.BeginRead(_handle, _readAheadOffset, _chunkSize, ReadCompleted, bufferedRead); + _ = _sftpSession.BeginRead(_handle, _readAheadOffset, _chunkSize, ReadCompleted, bufferedRead); } } catch (Exception ex) @@ -319,11 +346,12 @@ private void StartReadAhead() // advance read-ahead offset _readAheadOffset += _chunkSize; + // increment index of read-ahead chunk _readAheadChunkIndex++; } - _readAheadCompleted.Set(); + _ = _readAheadCompleted.Set(); }); } @@ -350,7 +378,7 @@ private bool ContinueReadAhead() } catch (Exception ex) { - Interlocked.CompareExchange(ref _exception, ex, null); + _ = Interlocked.CompareExchange(ref _exception, ex, comparand: null); return false; } } @@ -392,6 +420,7 @@ private void ReadCompletedCore(BufferedRead bufferedRead, byte[] data) { // add item to queue _queue.Add(bufferedRead.ChunkIndex, bufferedRead); + // signal that a chunk has been read or EOF has been reached; // in both cases, Read() will eventually also unblock the "read-ahead" thread Monitor.PulseAll(_readLock); @@ -407,10 +436,10 @@ private void ReadCompletedCore(BufferedRead bufferedRead, byte[] data) private void HandleFailure(Exception cause) { - Interlocked.CompareExchange(ref _exception, cause, null); + _ = Interlocked.CompareExchange(ref _exception, cause, comparand: null); // unblock read-ahead - _semaphore.Release(); + _ = _semaphore.Release(); // unblock Read() lock (_readLock) @@ -419,13 +448,13 @@ private void HandleFailure(Exception cause) } } - internal class BufferedRead + internal sealed class BufferedRead { - public int ChunkIndex { get; private set; } + public int ChunkIndex { get; } public byte[] Data { get; private set; } - public ulong Offset { get; private set; } + public ulong Offset { get; } public BufferedRead(int chunkIndex, ulong offset) { diff --git a/src/Renci.SshNet/Sftp/SftpFileStream.cs b/src/Renci.SshNet/Sftp/SftpFileStream.cs index a266b35b8..e42cad978 100644 --- a/src/Renci.SshNet/Sftp/SftpFileStream.cs +++ b/src/Renci.SshNet/Sftp/SftpFileStream.cs @@ -1,10 +1,11 @@ 锘縰sing System; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Threading; -using System.Diagnostics.CodeAnalysis; -using Renci.SshNet.Common; using System.Threading.Tasks; +using Renci.SshNet.Common; + namespace Renci.SshNet.Sftp { /// @@ -13,15 +14,16 @@ namespace Renci.SshNet.Sftp /// public class SftpFileStream : Stream { - // TODO: Add security method to set userid, groupid and other permission settings + private readonly object _lock = new object(); + private readonly int _readBufferSize; + private readonly int _writeBufferSize; + // Internal state. private byte[] _handle; private ISftpSession _session; // Buffer information. - private readonly int _readBufferSize; private byte[] _readBuffer; - private readonly int _writeBufferSize; private byte[] _writeBuffer; private int _bufferPosition; private int _bufferLen; @@ -31,8 +33,6 @@ public class SftpFileStream : Stream private bool _canSeek; private bool _canWrite; - private readonly object _lock = new object(); - /// /// Gets a value indicating whether the current stream supports reading. /// @@ -67,7 +67,7 @@ public override bool CanWrite } /// - /// Indicates whether timeout properties are usable for . + /// Gets a value indicating whether timeout properties are usable for . /// /// /// true in all cases. @@ -95,7 +95,9 @@ public override long Length CheckSessionIsOpen(); if (!CanSeek) + { throw new NotSupportedException("Seek operation is not supported."); + } // Flush the write buffer, because it may // affect the length of the stream. @@ -105,11 +107,12 @@ public override long Length } // obtain file attributes - var attributes = _session.RequestFStat(_handle, true); + var attributes = _session.RequestFStat(_handle, nullOnError: true); if (attributes != null) { return attributes.Size; } + throw new IOException("Seek operation failed."); } } @@ -127,13 +130,17 @@ public override long Position get { CheckSessionIsOpen(); + if (!CanSeek) + { throw new NotSupportedException("Seek operation not supported."); + } + return _position; } set { - Seek(value, SeekOrigin.Begin); + _ = Seek(value, SeekOrigin.Begin); } } @@ -180,12 +187,14 @@ private SftpFileStream(ISftpSession session, string path, FileAccess access, int _handle = handle; - // instead of using the specified buffer size as is, we use it to calculate a buffer size - // that ensures we always receive or send the max. number of bytes in a single SSH_FXP_READ - // or SSH_FXP_WRITE message + /* + * Instead of using the specified buffer size as is, we use it to calculate a buffer size + * that ensures we always receive or send the max. number of bytes in a single SSH_FXP_READ + * or SSH_FXP_WRITE message. + */ - _readBufferSize = (int)session.CalculateOptimalReadLength((uint)bufferSize); - _writeBufferSize = (int)session.CalculateOptimalWriteLength((uint)bufferSize, _handle); + _readBufferSize = (int) session.CalculateOptimalReadLength((uint)bufferSize); + _writeBufferSize = (int) session.CalculateOptimalWriteLength((uint)bufferSize, _handle); _position = position; } @@ -193,11 +202,19 @@ private SftpFileStream(ISftpSession session, string path, FileAccess access, int internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAccess access, int bufferSize) { if (session == null) + { throw new SshConnectionException("Client not connected."); + } + if (path == null) - throw new ArgumentNullException("path"); + { + throw new ArgumentNullException(nameof(path)); + } + if (bufferSize <= 0) - throw new ArgumentOutOfRangeException("bufferSize", "Cannot be less than or equal to zero."); + { + throw new ArgumentOutOfRangeException(nameof(bufferSize), "Cannot be less than or equal to zero."); + } Timeout = TimeSpan.FromSeconds(30); Name = path; @@ -223,7 +240,7 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc flags |= Flags.Write; break; default: - throw new ArgumentOutOfRangeException("access"); + throw new ArgumentOutOfRangeException(nameof(access)); } if ((access & FileAccess.Read) != 0 && mode == FileMode.Append) @@ -233,13 +250,13 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc if ((access & FileAccess.Write) == 0) { - if (mode == FileMode.Create || mode == FileMode.CreateNew || mode == FileMode.Truncate || mode == FileMode.Append) + if (mode is FileMode.Create or FileMode.CreateNew or FileMode.Truncate or FileMode.Append) { throw new ArgumentException(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", - typeof(FileMode).Name, - mode, - typeof(FileAccess).Name, - access)); + nameof(FileMode), + mode, + nameof(FileAccess), + access)); } } @@ -249,7 +266,7 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc flags |= Flags.Append | Flags.CreateNewOrOpen; break; case FileMode.Create: - _handle = _session.RequestOpen(path, flags | Flags.Truncate, true); + _handle = _session.RequestOpen(path, flags | Flags.Truncate, nullOnError: true); if (_handle == null) { flags |= Flags.CreateNew; @@ -258,6 +275,7 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc { flags |= Flags.Truncate; } + break; case FileMode.CreateNew: flags |= Flags.CreateNew; @@ -271,22 +289,23 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc flags |= Flags.Truncate; break; default: - throw new ArgumentOutOfRangeException("mode"); + throw new ArgumentOutOfRangeException(nameof(mode)); } - if (_handle == null) - _handle = _session.RequestOpen(path, flags); + _handle ??= _session.RequestOpen(path, flags); - // instead of using the specified buffer size as is, we use it to calculate a buffer size - // that ensures we always receive or send the max. number of bytes in a single SSH_FXP_READ - // or SSH_FXP_WRITE message + /* + * Instead of using the specified buffer size as is, we use it to calculate a buffer size + * that ensures we always receive or send the max. number of bytes in a single SSH_FXP_READ + * or SSH_FXP_WRITE message. + */ _readBufferSize = (int) session.CalculateOptimalReadLength((uint) bufferSize); _writeBufferSize = (int) session.CalculateOptimalWriteLength((uint) bufferSize, _handle); if (mode == FileMode.Append) { - var attributes = _session.RequestFStat(_handle, false); + var attributes = _session.RequestFStat(_handle, nullOnError: false); _position = attributes.Size; } } @@ -294,11 +313,19 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc internal static async Task OpenAsync(ISftpSession session, string path, FileMode mode, FileAccess access, int bufferSize, CancellationToken cancellationToken) { if (session == null) + { throw new SshConnectionException("Client not connected."); + } + if (path == null) - throw new ArgumentNullException("path"); + { + throw new ArgumentNullException(nameof(path)); + } + if (bufferSize <= 0) - throw new ArgumentOutOfRangeException("bufferSize", "Cannot be less than or equal to zero."); + { + throw new ArgumentOutOfRangeException(nameof(bufferSize), "Cannot be less than or equal to zero."); + } var flags = Flags.None; @@ -315,7 +342,7 @@ internal static async Task OpenAsync(ISftpSession session, strin flags |= Flags.Write; break; default: - throw new ArgumentOutOfRangeException("access"); + throw new ArgumentOutOfRangeException(nameof(access)); } if ((access & FileAccess.Read) != 0 && mode == FileMode.Append) @@ -325,18 +352,16 @@ internal static async Task OpenAsync(ISftpSession session, strin if ((access & FileAccess.Write) == 0) { - if (mode == FileMode.Create || mode == FileMode.CreateNew || mode == FileMode.Truncate || mode == FileMode.Append) + if (mode is FileMode.Create or FileMode.CreateNew or FileMode.Truncate or FileMode.Append) { throw new ArgumentException(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", - typeof(FileMode).Name, - mode, - typeof(FileAccess).Name, - access)); + nameof(FileMode), + mode, + nameof(FileAccess), + access)); } } - byte[] handle = null; - switch (mode) { case FileMode.Append: @@ -357,11 +382,10 @@ internal static async Task OpenAsync(ISftpSession session, strin flags |= Flags.Truncate; break; default: - throw new ArgumentOutOfRangeException("mode"); + throw new ArgumentOutOfRangeException(nameof(mode)); } - if (handle == null) - handle = await session.RequestOpenAsync(path, flags, cancellationToken).ConfigureAwait(false); + var handle = await session.RequestOpenAsync(path, flags, cancellationToken).ConfigureAwait(false); long position = 0; if (mode == FileMode.Append) @@ -378,9 +402,10 @@ internal static async Task OpenAsync(ISftpSession session, strin await session.RequestCloseAsync(handle, cancellationToken).ConfigureAwait(false); } catch - { + { // The original exception is presumably more informative, so we just ignore this one. } + throw; } } @@ -389,12 +414,11 @@ internal static async Task OpenAsync(ISftpSession session, strin } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~SftpFileStream() { - Dispose(false); + Dispose(disposing: false); } /// @@ -434,10 +458,8 @@ public override Task FlushAsync(CancellationToken cancellationToken) { return FlushWriteBufferAsync(cancellationToken); } - else - { - FlushReadBuffer(); - } + + FlushReadBuffer(); return Task.CompletedTask; } @@ -480,13 +502,24 @@ public override int Read(byte[] buffer, int offset, int count) var readLen = 0; if (buffer == null) - throw new ArgumentNullException("buffer"); + { + throw new ArgumentNullException(nameof(buffer)); + } + if (offset < 0) - throw new ArgumentOutOfRangeException("offset"); + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if (count < 0) - throw new ArgumentOutOfRangeException("count"); + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + if ((buffer.Length - offset) < count) + { throw new ArgumentException("Invalid array range."); + } // Lock down the file stream while we do this. lock (_lock) @@ -518,6 +551,7 @@ public override int Read(byte[] buffer, int offset, int count) { // write all data read to caller-provided buffer bytesToWriteToCallerBuffer = data.Length; + // reset buffer since we will skip buffering _bufferPosition = 0; _bufferLen = 0; @@ -526,18 +560,23 @@ public override int Read(byte[] buffer, int offset, int count) { // determine number of bytes that we should write into read buffer var bytesToWriteToReadBuffer = data.Length - bytesToWriteToCallerBuffer; + // write remaining bytes to read buffer Buffer.BlockCopy(data, count, GetOrCreateReadBuffer(), 0, bytesToWriteToReadBuffer); + // update position in read buffer _bufferPosition = 0; + // update number of bytes in read buffer _bufferLen = bytesToWriteToReadBuffer; } // write bytes to caller-provided buffer Buffer.BlockCopy(data, 0, buffer, offset, bytesToWriteToCallerBuffer); + // update stream position _position += bytesToWriteToCallerBuffer; + // record total number of bytes read into caller-provided buffer readLen += bytesToWriteToCallerBuffer; @@ -553,6 +592,7 @@ public override int Read(byte[] buffer, int offset, int count) // advance offset to start writing bytes into caller-provided buffer offset += bytesToWriteToCallerBuffer; + // update number of bytes left to read into caller-provided buffer count -= bytesToWriteToCallerBuffer; } @@ -560,18 +600,25 @@ public override int Read(byte[] buffer, int offset, int count) { // limit the number of bytes to use from read buffer to the caller-request number of bytes if (bytesAvailableInBuffer > count) + { bytesAvailableInBuffer = count; + } // copy data from read buffer to the caller-provided buffer Buffer.BlockCopy(GetOrCreateReadBuffer(), _bufferPosition, buffer, offset, bytesAvailableInBuffer); + // update position in read buffer _bufferPosition += bytesAvailableInBuffer; + // update stream position _position += bytesAvailableInBuffer; + // record total number of bytes read into caller-provided buffer readLen += bytesAvailableInBuffer; + // advance offset to start writing bytes into caller-provided buffer offset += bytesAvailableInBuffer; + // update number of bytes left to read count -= bytesAvailableInBuffer; } @@ -596,13 +643,24 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, var readLen = 0; if (buffer == null) - throw new ArgumentNullException("buffer"); + { + throw new ArgumentNullException(nameof(buffer)); + } + if (offset < 0) - throw new ArgumentOutOfRangeException("offset"); + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if (count < 0) - throw new ArgumentOutOfRangeException("count"); + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + if ((buffer.Length - offset) < count) + { throw new ArgumentException("Invalid array range."); + } CheckSessionIsOpen(); @@ -631,6 +689,7 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, { // write all data read to caller-provided buffer bytesToWriteToCallerBuffer = data.Length; + // reset buffer since we will skip buffering _bufferPosition = 0; _bufferLen = 0; @@ -639,18 +698,23 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, { // determine number of bytes that we should write into read buffer var bytesToWriteToReadBuffer = data.Length - bytesToWriteToCallerBuffer; + // write remaining bytes to read buffer Buffer.BlockCopy(data, count, GetOrCreateReadBuffer(), 0, bytesToWriteToReadBuffer); + // update position in read buffer _bufferPosition = 0; + // update number of bytes in read buffer _bufferLen = bytesToWriteToReadBuffer; } // write bytes to caller-provided buffer Buffer.BlockCopy(data, 0, buffer, offset, bytesToWriteToCallerBuffer); + // update stream position _position += bytesToWriteToCallerBuffer; + // record total number of bytes read into caller-provided buffer readLen += bytesToWriteToCallerBuffer; @@ -666,6 +730,7 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, // advance offset to start writing bytes into caller-provided buffer offset += bytesToWriteToCallerBuffer; + // update number of bytes left to read into caller-provided buffer count -= bytesToWriteToCallerBuffer; } @@ -673,18 +738,25 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, { // limit the number of bytes to use from read buffer to the caller-request number of bytes if (bytesAvailableInBuffer > count) + { bytesAvailableInBuffer = count; + } // copy data from read buffer to the caller-provided buffer Buffer.BlockCopy(GetOrCreateReadBuffer(), _bufferPosition, buffer, offset, bytesAvailableInBuffer); + // update position in read buffer _bufferPosition += bytesAvailableInBuffer; + // update stream position _position += bytesAvailableInBuffer; + // record total number of bytes read into caller-provided buffer readLen += bytesAvailableInBuffer; + // advance offset to start writing bytes into caller-provided buffer offset += bytesAvailableInBuffer; + // update number of bytes left to read count -= bytesAvailableInBuffer; } @@ -738,6 +810,7 @@ public override int ReadByte() // Extract the next byte from the buffer. ++_position; + return readBuffer[_bufferPosition++]; } } @@ -755,7 +828,7 @@ public override int ReadByte() /// Methods were called after the stream was closed. public override long Seek(long offset, SeekOrigin origin) { - long newPosn = -1; + long newPosn; // Lock down the file stream while we do this. lock (_lock) @@ -763,13 +836,16 @@ public override long Seek(long offset, SeekOrigin origin) CheckSessionIsOpen(); if (!CanSeek) + { throw new NotSupportedException("Seek is not supported."); + } // Don't do anything if the position won't be moving. if (origin == SeekOrigin.Begin && offset == _position) { return offset; } + if (origin == SeekOrigin.Current && offset == 0) { return _position; @@ -822,11 +898,11 @@ public override long Seek(long offset, SeekOrigin origin) newPosn = _position + offset; break; case SeekOrigin.End: - var attributes = _session.RequestFStat(_handle, false); + var attributes = _session.RequestFStat(_handle, nullOnError: false); newPosn = attributes.Size + offset; break; default: - throw new ArgumentException(message: "Invalid seek origin.", paramName: "origin"); + throw new ArgumentException("Invalid seek origin.", nameof(origin)); } if (newPosn < 0) @@ -863,7 +939,9 @@ public override long Seek(long offset, SeekOrigin origin) public override void SetLength(long value) { if (value < 0) - throw new ArgumentOutOfRangeException("value"); + { + throw new ArgumentOutOfRangeException(nameof(value)); + } // Lock down the file stream while we do this. lock (_lock) @@ -871,7 +949,9 @@ public override void SetLength(long value) CheckSessionIsOpen(); if (!CanSeek) + { throw new NotSupportedException("Seek is not supported."); + } if (_bufferOwnedByWrite) { @@ -882,7 +962,7 @@ public override void SetLength(long value) SetupWrite(); } - var attributes = _session.RequestFStat(_handle, false); + var attributes = _session.RequestFStat(_handle, nullOnError: false); attributes.Size = value; _session.RequestFSetStat(_handle, attributes); @@ -908,13 +988,24 @@ public override void SetLength(long value) public override void Write(byte[] buffer, int offset, int count) { if (buffer == null) - throw new ArgumentNullException("buffer"); + { + throw new ArgumentNullException(nameof(buffer)); + } + if (offset < 0) - throw new ArgumentOutOfRangeException("offset"); + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if (count < 0) - throw new ArgumentOutOfRangeException("count"); + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + if ((buffer.Length - offset) < count) + { throw new ArgumentException("Invalid array range."); + } // Lock down the file stream while we do this. lock (_lock) @@ -933,6 +1024,7 @@ public override void Write(byte[] buffer, int offset, int count) { // flush write buffer, and mark it empty FlushWriteBuffer(); + // we can now write or buffer the full buffer size tempLen = _writeBufferSize; } @@ -946,7 +1038,7 @@ public override void Write(byte[] buffer, int offset, int count) // Can we short-cut the internal buffer? if (_bufferPosition == 0 && tempLen == _writeBufferSize) { - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { _session.RequestWrite(_handle, (ulong) _position, buffer, offset, tempLen, wait); } @@ -968,7 +1060,7 @@ public override void Write(byte[] buffer, int offset, int count) // rather than waiting for the next call to this method. if (_bufferPosition >= _writeBufferSize) { - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { _session.RequestWrite(_handle, (ulong) (_position - _bufferPosition), GetOrCreateWriteBuffer(), 0, _bufferPosition, wait); } @@ -978,7 +1070,6 @@ public override void Write(byte[] buffer, int offset, int count) } } - /// /// Asynchronously writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. /// @@ -996,13 +1087,24 @@ public override void Write(byte[] buffer, int offset, int count) public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (buffer == null) - throw new ArgumentNullException("buffer"); + { + throw new ArgumentNullException(nameof(buffer)); + } + if (offset < 0) - throw new ArgumentOutOfRangeException("offset"); + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + if (count < 0) - throw new ArgumentOutOfRangeException("count"); + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + if ((buffer.Length - offset) < count) + { throw new ArgumentException("Invalid array range."); + } CheckSessionIsOpen(); @@ -1018,6 +1120,7 @@ public override async Task WriteAsync(byte[] buffer, int offset, int count, Canc { // flush write buffer, and mark it empty await FlushWriteBufferAsync(cancellationToken).ConfigureAwait(false); + // we can now write or buffer the full buffer size tempLen = _writeBufferSize; } @@ -1077,7 +1180,7 @@ public override void WriteByte(byte value) // Flush the current buffer if it is full. if (_bufferPosition >= _writeBufferSize) { - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { _session.RequestWrite(_handle, (ulong) (_position - _bufferPosition), writeBuffer, 0, _bufferPosition, wait); } @@ -1135,15 +1238,13 @@ protected override void Dispose(bool disposing) private byte[] GetOrCreateReadBuffer() { - if (_readBuffer == null) - _readBuffer = new byte[_readBufferSize]; + _readBuffer ??= new byte[_readBufferSize]; return _readBuffer; } private byte[] GetOrCreateWriteBuffer() { - if (_writeBuffer == null) - _writeBuffer = new byte[_writeBufferSize]; + _writeBuffer ??= new byte[_writeBufferSize]; return _writeBuffer; } @@ -1163,7 +1264,7 @@ private void FlushWriteBuffer() { if (_bufferPosition > 0) { - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { _session.RequestWrite(_handle, (ulong) (_position - _bufferPosition), _writeBuffer, 0, _bufferPosition, wait); } @@ -1176,7 +1277,7 @@ private async Task FlushWriteBufferAsync(CancellationToken cancellationToken) { if (_bufferPosition > 0) { - await _session.RequestWriteAsync(_handle, (ulong)(_position - _bufferPosition), _writeBuffer, 0, _bufferPosition, cancellationToken); + await _session.RequestWriteAsync(_handle, (ulong)(_position - _bufferPosition), _writeBuffer, 0, _bufferPosition, cancellationToken).ConfigureAwait(false); _bufferPosition = 0; } } @@ -1187,7 +1288,9 @@ private async Task FlushWriteBufferAsync(CancellationToken cancellationToken) private void SetupRead() { if (!CanRead) + { throw new NotSupportedException("Read not supported."); + } if (_bufferOwnedByWrite) { @@ -1201,8 +1304,10 @@ private void SetupRead() /// private void SetupWrite() { - if ((!CanWrite)) + if (!CanWrite) + { throw new NotSupportedException("Write not supported."); + } if (!_bufferOwnedByWrite) { @@ -1214,9 +1319,14 @@ private void SetupWrite() private void CheckSessionIsOpen() { if (_session == null) + { throw new ObjectDisposedException(GetType().FullName); + } + if (!_session.IsOpen) + { throw new ObjectDisposedException(GetType().FullName, "Cannot access a closed SFTP session."); + } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Sftp/SftpListDirectoryAsyncResult.cs b/src/Renci.SshNet/Sftp/SftpListDirectoryAsyncResult.cs index 2b791e54c..b69c05b27 100644 --- a/src/Renci.SshNet/Sftp/SftpListDirectoryAsyncResult.cs +++ b/src/Renci.SshNet/Sftp/SftpListDirectoryAsyncResult.cs @@ -1,5 +1,6 @@ 锘縰sing System; using System.Collections.Generic; + using Renci.SshNet.Common; namespace Renci.SshNet.Sftp @@ -13,16 +14,15 @@ public class SftpListDirectoryAsyncResult : AsyncResult> /// Gets the number of files read so far. /// public int FilesRead { get; private set; } - + /// /// Initializes a new instance of the class. /// /// The async callback. /// The state. - public SftpListDirectoryAsyncResult(AsyncCallback asyncCallback, Object state) + public SftpListDirectoryAsyncResult(AsyncCallback asyncCallback, object state) : base(asyncCallback, state) { - } /// diff --git a/src/Renci.SshNet/Sftp/SftpMessage.cs b/src/Renci.SshNet/Sftp/SftpMessage.cs index 8f131fa79..5ecb69bc8 100644 --- a/src/Renci.SshNet/Sftp/SftpMessage.cs +++ b/src/Renci.SshNet/Sftp/SftpMessage.cs @@ -1,6 +1,7 @@ -锘縰sing System.IO; +锘縰sing System.Globalization; +using System.IO; + using Renci.SshNet.Common; -using System.Globalization; namespace Renci.SshNet.Sftp { @@ -44,7 +45,7 @@ protected override void WriteBytes(SshDataStream stream) var startPosition = stream.Position; // skip 4 bytes for the length of the SFTP message data - stream.Seek(sizeOfDataLengthBytes, SeekOrigin.Current); + _ = stream.Seek(sizeOfDataLengthBytes, SeekOrigin.Current); // write the SFTP message data to the stream base.WriteBytes(stream); diff --git a/src/Renci.SshNet/Sftp/SftpMessageTypes.cs b/src/Renci.SshNet/Sftp/SftpMessageTypes.cs index d74fc6ccd..25ea00eac 100644 --- a/src/Renci.SshNet/Sftp/SftpMessageTypes.cs +++ b/src/Renci.SshNet/Sftp/SftpMessageTypes.cs @@ -1,130 +1,155 @@ -锘 -namespace Renci.SshNet.Sftp +锘縩amespace Renci.SshNet.Sftp { internal enum SftpMessageTypes : byte { /// - /// SSH_FXP_INIT + /// SSH_FXP_INIT. /// Init = 1, + /// - /// SSH_FXP_VERSION + /// SSH_FXP_VERSION. /// Version = 2, + /// - /// SSH_FXP_OPEN + /// SSH_FXP_OPEN. /// Open = 3, + /// - /// SSH_FXP_CLOSE + /// SSH_FXP_CLOSE. /// Close = 4, + /// - /// SSH_FXP_READ + /// SSH_FXP_READ. /// Read = 5, + /// - /// SSH_FXP_WRITE + /// SSH_FXP_WRITE. /// Write = 6, + /// - /// SSH_FXP_LSTAT + /// SSH_FXP_LSTAT. /// LStat = 7, + /// - /// SSH_FXP_FSTAT + /// SSH_FXP_FSTAT. /// FStat = 8, + /// - /// SSH_FXP_SETSTAT + /// SSH_FXP_SETSTAT. /// SetStat = 9, + /// - /// SSH_FXP_FSETSTAT + /// SSH_FXP_FSETSTAT. /// FSetStat = 10, + /// - /// SSH_FXP_OPENDIR + /// SSH_FXP_OPENDIR. /// OpenDir = 11, + /// - /// SSH_FXP_READDIR + /// SSH_FXP_READDIR. /// ReadDir = 12, + /// - /// SSH_FXP_REMOVE + /// SSH_FXP_REMOVE. /// Remove = 13, + /// - /// SSH_FXP_MKDIR + /// SSH_FXP_MKDIR. /// MkDir = 14, + /// - /// SSH_FXP_RMDIR + /// SSH_FXP_RMDIR. /// RmDir = 15, + /// - /// SSH_FXP_REALPATH + /// SSH_FXP_REALPATH. /// RealPath = 16, + /// - /// SSH_FXP_STAT + /// SSH_FXP_STAT. /// Stat = 17, + /// - /// SSH_FXP_RENAME + /// SSH_FXP_RENAME. /// Rename = 18, + /// - /// SSH_FXP_READLINK + /// SSH_FXP_READLINK. /// ReadLink = 19, + /// - /// SSH_FXP_SYMLINK + /// SSH_FXP_SYMLINK. /// SymLink = 20, + /// - /// SSH_FXP_LINK + /// SSH_FXP_LINK. /// Link = 21, + /// - /// SSH_FXP_BLOCK + /// SSH_FXP_BLOCK. /// Block = 22, + /// - /// SSH_FXP_UNBLOCK + /// SSH_FXP_UNBLOCK. /// Unblock = 23, /// - /// SSH_FXP_STATUS + /// SSH_FXP_STATUS. /// Status = 101, + /// - /// SSH_FXP_HANDLE + /// SSH_FXP_HANDLE. /// Handle = 102, + /// - /// SSH_FXP_DATA + /// SSH_FXP_DATA. /// Data = 103, + /// - /// SSH_FXP_NAME + /// SSH_FXP_NAME. /// Name = 104, + /// - /// SSH_FXP_ATTRS + /// SSH_FXP_ATTRS. /// Attrs = 105, /// - /// SSH_FXP_EXTENDED + /// SSH_FXP_EXTENDED. /// Extended = 200, + /// - /// SSH_FXP_EXTENDED_REPLY + /// SSH_FXP_EXTENDED_REPLY. /// ExtendedReply = 201 - } } diff --git a/src/Renci.SshNet/Sftp/SftpOpenAsyncResult.cs b/src/Renci.SshNet/Sftp/SftpOpenAsyncResult.cs index b19de7e79..a239172e4 100644 --- a/src/Renci.SshNet/Sftp/SftpOpenAsyncResult.cs +++ b/src/Renci.SshNet/Sftp/SftpOpenAsyncResult.cs @@ -1,11 +1,13 @@ -锘縰sing Renci.SshNet.Common; -using System; +锘縰sing System; + +using Renci.SshNet.Common; namespace Renci.SshNet.Sftp { - internal class SftpOpenAsyncResult : AsyncResult + internal sealed class SftpOpenAsyncResult : AsyncResult { - public SftpOpenAsyncResult(AsyncCallback asyncCallback, object state) : base(asyncCallback, state) + public SftpOpenAsyncResult(AsyncCallback asyncCallback, object state) + : base(asyncCallback, state) { } } diff --git a/src/Renci.SshNet/Sftp/SftpReadAsyncResult.cs b/src/Renci.SshNet/Sftp/SftpReadAsyncResult.cs index 65911d222..9814f0e8f 100644 --- a/src/Renci.SshNet/Sftp/SftpReadAsyncResult.cs +++ b/src/Renci.SshNet/Sftp/SftpReadAsyncResult.cs @@ -1,11 +1,13 @@ -锘縰sing Renci.SshNet.Common; -using System; +锘縰sing System; + +using Renci.SshNet.Common; namespace Renci.SshNet.Sftp { - internal class SftpReadAsyncResult : AsyncResult + internal sealed class SftpReadAsyncResult : AsyncResult { - public SftpReadAsyncResult(AsyncCallback asyncCallback, object state) : base(asyncCallback, state) + public SftpReadAsyncResult(AsyncCallback asyncCallback, object state) + : base(asyncCallback, state) { } } diff --git a/src/Renci.SshNet/Sftp/SftpRealPathAsyncResult.cs b/src/Renci.SshNet/Sftp/SftpRealPathAsyncResult.cs index e1f1fbf95..ab8600320 100644 --- a/src/Renci.SshNet/Sftp/SftpRealPathAsyncResult.cs +++ b/src/Renci.SshNet/Sftp/SftpRealPathAsyncResult.cs @@ -1,11 +1,13 @@ -锘縰sing Renci.SshNet.Common; -using System; +锘縰sing System; + +using Renci.SshNet.Common; namespace Renci.SshNet.Sftp { - internal class SftpRealPathAsyncResult : AsyncResult + internal sealed class SftpRealPathAsyncResult : AsyncResult { - public SftpRealPathAsyncResult(AsyncCallback asyncCallback, object state) : base(asyncCallback, state) + public SftpRealPathAsyncResult(AsyncCallback asyncCallback, object state) + : base(asyncCallback, state) { } } diff --git a/src/Renci.SshNet/Sftp/SftpResponseFactory.cs b/src/Renci.SshNet/Sftp/SftpResponseFactory.cs index ad6b22913..0edcfcf7c 100644 --- a/src/Renci.SshNet/Sftp/SftpResponseFactory.cs +++ b/src/Renci.SshNet/Sftp/SftpResponseFactory.cs @@ -1,7 +1,8 @@ 锘縰sing System; +using System.Globalization; using System.Text; + using Renci.SshNet.Sftp.Responses; -using System.Globalization; namespace Renci.SshNet.Sftp { diff --git a/src/Renci.SshNet/Sftp/SftpSession.cs b/src/Renci.SshNet/Sftp/SftpSession.cs index dd38bd36e..7bba929ed 100644 --- a/src/Renci.SshNet/Sftp/SftpSession.cs +++ b/src/Renci.SshNet/Sftp/SftpSession.cs @@ -1,12 +1,13 @@ 锘縰sing System; +using System.Collections.Generic; +using System.Globalization; using System.Text; using System.Threading; +using System.Threading.Tasks; + using Renci.SshNet.Common; -using System.Collections.Generic; -using System.Globalization; -using Renci.SshNet.Sftp.Responses; using Renci.SshNet.Sftp.Requests; -using System.Threading.Tasks; +using Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Sftp { @@ -17,9 +18,8 @@ internal class SftpSession : SubsystemSession, ISftpSession private readonly Dictionary _requests = new Dictionary(); private readonly ISftpResponseFactory _sftpResponseFactory; - //FIXME: obtain from SftpClient! private readonly List _data = new List(32 * 1024); - private EventWaitHandle _sftpVersionConfirmed = new AutoResetEvent(false); + private EventWaitHandle _sftpVersionConfirmed = new AutoResetEvent(initialState: false); private IDictionary _supportedExtensions; /// @@ -56,6 +56,13 @@ public uint NextRequestId } } + /// + /// Initializes a new instance of the class. + /// + /// The SSH session. + /// The operation timeout. + /// The character encoding to use. + /// The factory to create SFTP responses. public SftpSession(ISession session, int operationTimeout, Encoding encoding, ISftpResponseFactory sftpResponseFactory) : base(session, "sftp", operationTimeout) { @@ -95,7 +102,7 @@ public string GetCanonicalPath(string path) var canonizedPath = string.Empty; - var realPathFiles = RequestRealPath(fullPath, true); + var realPathFiles = RequestRealPath(fullPath, nullOnError: true); if (realPathFiles != null) { @@ -103,23 +110,29 @@ public string GetCanonicalPath(string path) } if (!string.IsNullOrEmpty(canonizedPath)) + { return canonizedPath; + } - // Check for special cases + // Check for special cases if (fullPath.EndsWith("/.", StringComparison.OrdinalIgnoreCase) || fullPath.EndsWith("/..", StringComparison.OrdinalIgnoreCase) || fullPath.Equals("/", StringComparison.OrdinalIgnoreCase) || fullPath.IndexOf('/') < 0) + { return fullPath; + } var pathParts = fullPath.Split('/'); var partialFullPath = string.Join("/", pathParts, 0, pathParts.Length - 1); if (string.IsNullOrEmpty(partialFullPath)) + { partialFullPath = "/"; + } - realPathFiles = RequestRealPath(partialFullPath, true); + realPathFiles = RequestRealPath(partialFullPath, nullOnError: true); if (realPathFiles != null) { @@ -133,7 +146,10 @@ public string GetCanonicalPath(string path) var slash = string.Empty; if (canonizedPath[canonizedPath.Length - 1] != '/') + { slash = "/"; + } + return string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", canonizedPath, slash, pathParts[pathParts.Length - 1]); } @@ -142,30 +158,36 @@ public async Task GetCanonicalPathAsync(string path, CancellationToken c var fullPath = GetFullRemotePath(path); var canonizedPath = string.Empty; - var realPathFiles = await RequestRealPathAsync(fullPath, true, cancellationToken).ConfigureAwait(false); + var realPathFiles = await RequestRealPathAsync(fullPath, nullOnError: true, cancellationToken).ConfigureAwait(false); if (realPathFiles != null) { canonizedPath = realPathFiles[0].Key; } if (!string.IsNullOrEmpty(canonizedPath)) + { return canonizedPath; + } - // Check for special cases + // Check for special cases if (fullPath.EndsWith("/.", StringComparison.Ordinal) || fullPath.EndsWith("/..", StringComparison.Ordinal) || fullPath.Equals("/", StringComparison.Ordinal) || fullPath.IndexOf('/') < 0) + { return fullPath; + } var pathParts = fullPath.Split('/'); var partialFullPath = string.Join("/", pathParts, 0, pathParts.Length - 1); if (string.IsNullOrEmpty(partialFullPath)) + { partialFullPath = "/"; + } - realPathFiles = await RequestRealPathAsync(partialFullPath, true, cancellationToken).ConfigureAwait(false); + realPathFiles = await RequestRealPathAsync(partialFullPath, nullOnError: true, cancellationToken).ConfigureAwait(false); if (realPathFiles != null) { @@ -179,7 +201,10 @@ public async Task GetCanonicalPathAsync(string path, CancellationToken c var slash = string.Empty; if (canonizedPath[canonizedPath.Length - 1] != '/') + { slash = "/"; + } + return canonizedPath + slash + pathParts[pathParts.Length - 1]; } @@ -212,12 +237,12 @@ protected override void OnChannelOpen() WaitOnHandle(_sftpVersionConfirmed, OperationTimeout); - if (ProtocolVersion > MaximumSupportedVersion || ProtocolVersion < MinimumSupportedVersion) + if (ProtocolVersion is > MaximumSupportedVersion or < MinimumSupportedVersion) { throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Server SFTP version {0} is not supported.", ProtocolVersion)); } - // Resolve current directory + // Resolve current directory WorkingDirectory = RequestRealPath(".")[0].Key; } @@ -339,18 +364,18 @@ private bool TryLoadSftpMessage(byte[] packetData, int offset, int count) { // Create SFTP message var response = _sftpResponseFactory.Create(ProtocolVersion, packetData[offset], Encoding); + // Load message data into it response.Load(packetData, offset + 1, count - 1); try { - var versionResponse = response as SftpVersionResponse; - if (versionResponse != null) + if (response is SftpVersionResponse versionResponse) { ProtocolVersion = versionResponse.Version; _supportedExtensions = versionResponse.Extentions; - _sftpVersionConfirmed.Set(); + _ = _sftpVersionConfirmed.Set(); } else { @@ -391,10 +416,8 @@ private void SendRequest(SftpRequest request) SendMessage(request); } - #region SFTP API functions - /// - /// Performs SSH_FXP_OPEN request + /// Performs SSH_FXP_OPEN request. /// /// The path. /// The flags. @@ -405,19 +428,23 @@ public byte[] RequestOpen(string path, Flags flags, bool nullOnError = false) byte[] handle = null; SshException exception = null; - using (var wait = new AutoResetEvent(false)) - { - var request = new SftpOpenRequest(ProtocolVersion, NextRequestId, path, Encoding, flags, - response => - { - handle = response.Handle; - wait.Set(); - }, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + using (var wait = new AutoResetEvent(initialState: false)) + { + var request = new SftpOpenRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + flags, + response => + { + handle = response.Handle; + _ = wait.Set(); + }, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -436,20 +463,24 @@ public async Task RequestOpenAsync(string path, Flags flags, Cancellatio { cancellationToken.ThrowIfCancellationRequested(); - TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource)s).TrySetCanceled(), tcs, false)) + using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) { - SendRequest(new SftpOpenRequest(ProtocolVersion, NextRequestId, path, Encoding, flags, - response => tcs.TrySetResult(response.Handle), - response => tcs.TrySetException(GetSftpException(response)))); + SendRequest(new SftpOpenRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + flags, + response => tcs.TrySetResult(response.Handle), + response => tcs.TrySetException(GetSftpException(response)))); return await tcs.Task.ConfigureAwait(false); } } /// - /// Performs SSH_FXP_OPEN request + /// Performs SSH_FXP_OPEN request. /// /// The path. /// The flags. @@ -462,15 +493,19 @@ public SftpOpenAsyncResult BeginOpen(string path, Flags flags, AsyncCallback cal { var asyncResult = new SftpOpenAsyncResult(callback, state); - var request = new SftpOpenRequest(ProtocolVersion, NextRequestId, path, Encoding, flags, - response => - { - asyncResult.SetAsCompleted(response.Handle, false); - }, - response => - { - asyncResult.SetAsCompleted(GetSftpException(response), false); - }); + var request = new SftpOpenRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + flags, + response => + { + asyncResult.SetAsCompleted(response.Handle, completedSynchronously: false); + }, + response => + { + asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false); + }); SendRequest(request); @@ -492,13 +527,19 @@ public SftpOpenAsyncResult BeginOpen(string path, Flags flags, AsyncCallback cal public byte[] EndOpen(SftpOpenAsyncResult asyncResult) { if (asyncResult == null) - throw new ArgumentNullException("asyncResult"); + { + throw new ArgumentNullException(nameof(asyncResult)); + } if (asyncResult.EndInvokeCalled) + { throw new InvalidOperationException("EndOpen has already been called."); + } if (asyncResult.IsCompleted) + { return asyncResult.EndInvoke(); + } using (var waitHandle = asyncResult.AsyncWaitHandle) { @@ -515,14 +556,16 @@ public void RequestClose(byte[] handle) { SshException exception = null; - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { - var request = new SftpCloseRequest(ProtocolVersion, NextRequestId, handle, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + var request = new SftpCloseRequest(ProtocolVersion, + NextRequestId, + handle, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -537,26 +580,29 @@ public void RequestClose(byte[] handle) public async Task RequestCloseAsync(byte[] handle, CancellationToken cancellationToken) { - TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - - SendRequest(new SftpCloseRequest(ProtocolVersion, NextRequestId, handle, - response => - { - if (response.StatusCode == StatusCodes.Ok) - { - tcs.TrySetResult(true); - } - else - { - tcs.TrySetException(GetSftpException(response)); - } - })); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + SendRequest(new SftpCloseRequest(ProtocolVersion, + NextRequestId, + handle, + response => + { + if (response.StatusCode == StatusCodes.Ok) + { + _ = tcs.TrySetResult(true); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } + })); // Only check for cancellation after the SftpCloseRequest was sent cancellationToken.ThrowIfCancellationRequested(); - using (cancellationToken.Register((s) => ((TaskCompletionSource)s).TrySetCanceled(), tcs, false)) + + using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) { - await tcs.Task.ConfigureAwait(false); + _ = await tcs.Task.ConfigureAwait(false); } } @@ -573,11 +619,13 @@ public SftpCloseAsyncResult BeginClose(byte[] handle, AsyncCallback callback, ob { var asyncResult = new SftpCloseAsyncResult(callback, state); - var request = new SftpCloseRequest(ProtocolVersion, NextRequestId, handle, - response => - { - asyncResult.SetAsCompleted(GetSftpException(response), false); - }); + var request = new SftpCloseRequest(ProtocolVersion, + NextRequestId, + handle, + response => + { + asyncResult.SetAsCompleted(GetSftpException(response), false); + }); SendRequest(request); return asyncResult; @@ -591,10 +639,14 @@ public SftpCloseAsyncResult BeginClose(byte[] handle, AsyncCallback callback, ob public void EndClose(SftpCloseAsyncResult asyncResult) { if (asyncResult == null) - throw new ArgumentNullException("asyncResult"); + { + throw new ArgumentNullException(nameof(asyncResult)); + } if (asyncResult.EndInvokeCalled) + { throw new InvalidOperationException("EndClose has already been called."); + } if (asyncResult.IsCompleted) { @@ -625,22 +677,26 @@ public SftpReadAsyncResult BeginRead(byte[] handle, ulong offset, uint length, A { var asyncResult = new SftpReadAsyncResult(callback, state); - var request = new SftpReadRequest(ProtocolVersion, NextRequestId, handle, offset, length, - response => - { - asyncResult.SetAsCompleted(response.Data, false); - }, - response => - { - if (response.StatusCode != StatusCodes.Eof) - { - asyncResult.SetAsCompleted(GetSftpException(response), false); - } - else - { - asyncResult.SetAsCompleted(Array.Empty, false); - } - }); + var request = new SftpReadRequest(ProtocolVersion, + NextRequestId, + handle, + offset, + length, + response => + { + asyncResult.SetAsCompleted(response.Data, completedSynchronously: false); + }, + response => + { + if (response.StatusCode != StatusCodes.Eof) + { + asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false); + } + else + { + asyncResult.SetAsCompleted(Array.Empty, completedSynchronously: false); + } + }); SendRequest(request); return asyncResult; @@ -661,13 +717,19 @@ public SftpReadAsyncResult BeginRead(byte[] handle, ulong offset, uint length, A public byte[] EndRead(SftpReadAsyncResult asyncResult) { if (asyncResult == null) - throw new ArgumentNullException("asyncResult"); + { + throw new ArgumentNullException(nameof(asyncResult)); + } if (asyncResult.EndInvokeCalled) + { throw new InvalidOperationException("EndRead has already been called."); + } if (asyncResult.IsCompleted) + { return asyncResult.EndInvoke(); + } using (var waitHandle = asyncResult.AsyncWaitHandle) { @@ -689,26 +751,31 @@ public byte[] RequestRead(byte[] handle, ulong offset, uint length) byte[] data = null; - using (var wait = new AutoResetEvent(false)) - { - var request = new SftpReadRequest(ProtocolVersion, NextRequestId, handle, offset, length, - response => - { - data = response.Data; - wait.Set(); - }, - response => - { - if (response.StatusCode != StatusCodes.Eof) - { - exception = GetSftpException(response); - } - else - { - data = Array.Empty; - } - wait.Set(); - }); + using (var wait = new AutoResetEvent(initialState: false)) + { + var request = new SftpReadRequest(ProtocolVersion, + NextRequestId, + handle, + offset, + length, + response => + { + data = response.Data; + _ = wait.Set(); + }, + response => + { + if (response.StatusCode != StatusCodes.Eof) + { + exception = GetSftpException(response); + } + else + { + data = Array.Empty; + } + + _ = wait.Set(); + }); SendRequest(request); @@ -727,23 +794,27 @@ public async Task RequestReadAsync(byte[] handle, ulong offset, uint len { cancellationToken.ThrowIfCancellationRequested(); - TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - - using (cancellationToken.Register((s) => ((TaskCompletionSource)s).TrySetCanceled(), tcs, false)) - { - SendRequest(new SftpReadRequest(ProtocolVersion, NextRequestId, handle, offset, length, - response => tcs.TrySetResult(response.Data), - response => - { - if (response.StatusCode == StatusCodes.Eof) - { - tcs.TrySetResult(Array.Empty); - } - else - { - tcs.TrySetException(GetSftpException(response)); - } - })); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) + { + SendRequest(new SftpReadRequest(ProtocolVersion, + NextRequestId, + handle, + offset, + length, + response => tcs.TrySetResult(response.Data), + response => + { + if (response.StatusCode == StatusCodes.Eof) + { + _ = tcs.TrySetResult(Array.Empty); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } + })); return await tcs.Task.ConfigureAwait(false); } @@ -769,23 +840,30 @@ public void RequestWrite(byte[] handle, { SshException exception = null; - var request = new SftpWriteRequest(ProtocolVersion, NextRequestId, handle, serverOffset, data, offset, - length, response => - { - if (writeCompleted != null) - { - writeCompleted(response); - } - - exception = GetSftpException(response); - if (wait != null) - wait.Set(); - }); + var request = new SftpWriteRequest(ProtocolVersion, + NextRequestId, + handle, + serverOffset, + data, + offset, + length, + response => + { + writeCompleted?.Invoke(response); + + exception = GetSftpException(response); + if (wait != null) + { + _ = wait.Set(); + } + }); SendRequest(request); if (wait != null) + { WaitOnHandle(wait, OperationTimeout); + } if (exception != null) { @@ -797,24 +875,30 @@ public async Task RequestWriteAsync(byte[] handle, ulong serverOffset, byte[] da { cancellationToken.ThrowIfCancellationRequested(); - TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - - using (cancellationToken.Register((s) => ((TaskCompletionSource)s).TrySetCanceled(), tcs, false)) - { - SendRequest(new SftpWriteRequest(ProtocolVersion, NextRequestId, handle, serverOffset, data, offset, length, - response => - { - if (response.StatusCode == StatusCodes.Ok) - { - tcs.TrySetResult(true); - } - else - { - tcs.TrySetException(GetSftpException(response)); - } - })); - - await tcs.Task.ConfigureAwait(false); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) + { + SendRequest(new SftpWriteRequest(ProtocolVersion, + NextRequestId, + handle, + serverOffset, + data, + offset, + length, + response => + { + if (response.StatusCode == StatusCodes.Ok) + { + _ = tcs.TrySetResult(true); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } + })); + + _ = await tcs.Task.ConfigureAwait(false); } } @@ -823,26 +907,29 @@ public async Task RequestWriteAsync(byte[] handle, ulong serverOffset, byte[] da /// /// The path. /// - /// File attributes + /// File attributes. /// public SftpFileAttributes RequestLStat(string path) { SshException exception = null; SftpFileAttributes attributes = null; - using (var wait = new AutoResetEvent(false)) - { - var request = new SftpLStatRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - attributes = response.Attributes; - wait.Set(); - }, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + using (var wait = new AutoResetEvent(initialState: false)) + { + var request = new SftpLStatRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => + { + attributes = response.Attributes; + _ = wait.Set(); + }, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -870,15 +957,18 @@ public SFtpStatAsyncResult BeginLStat(string path, AsyncCallback callback, objec { var asyncResult = new SFtpStatAsyncResult(callback, state); - var request = new SftpLStatRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - asyncResult.SetAsCompleted(response.Attributes, false); - }, - response => - { - asyncResult.SetAsCompleted(GetSftpException(response), false); - }); + var request = new SftpLStatRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => + { + asyncResult.SetAsCompleted(response.Attributes, completedSynchronously: false); + }, + response => + { + asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false); + }); SendRequest(request); return asyncResult; @@ -895,13 +985,19 @@ public SFtpStatAsyncResult BeginLStat(string path, AsyncCallback callback, objec public SftpFileAttributes EndLStat(SFtpStatAsyncResult asyncResult) { if (asyncResult == null) - throw new ArgumentNullException("asyncResult"); + { + throw new ArgumentNullException(nameof(asyncResult)); + } if (asyncResult.EndInvokeCalled) + { throw new InvalidOperationException("EndLStat has already been called."); + } if (asyncResult.IsCompleted) + { return asyncResult.EndInvoke(); + } using (var waitHandle = asyncResult.AsyncWaitHandle) { @@ -916,26 +1012,28 @@ public SftpFileAttributes EndLStat(SFtpStatAsyncResult asyncResult) /// The handle. /// if set to true returns null instead of throwing an exception. /// - /// File attributes + /// File attributes. /// public SftpFileAttributes RequestFStat(byte[] handle, bool nullOnError) { SshException exception = null; SftpFileAttributes attributes = null; - using (var wait = new AutoResetEvent(false)) - { - var request = new SftpFStatRequest(ProtocolVersion, NextRequestId, handle, - response => - { - attributes = response.Attributes; - wait.Set(); - }, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + using (var wait = new AutoResetEvent(initialState: false)) + { + var request = new SftpFStatRequest(ProtocolVersion, + NextRequestId, + handle, + response => + { + attributes = response.Attributes; + _ = wait.Set(); + }, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -954,13 +1052,15 @@ public async Task RequestFStatAsync(byte[] handle, Cancellat { cancellationToken.ThrowIfCancellationRequested(); - TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource)s).TrySetCanceled(), tcs, false)) + using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) { - SendRequest(new SftpFStatRequest(ProtocolVersion, NextRequestId, handle, - response => tcs.TrySetResult(response.Attributes), - response => tcs.TrySetException(GetSftpException(response)))); + SendRequest(new SftpFStatRequest(ProtocolVersion, + NextRequestId, + handle, + response => tcs.TrySetResult(response.Attributes), + response => tcs.TrySetException(GetSftpException(response)))); return await tcs.Task.ConfigureAwait(false); } @@ -975,14 +1075,18 @@ public void RequestSetStat(string path, SftpFileAttributes attributes) { SshException exception = null; - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { - var request = new SftpSetStatRequest(ProtocolVersion, NextRequestId, path, Encoding, attributes, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + var request = new SftpSetStatRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + attributes, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -1004,14 +1108,17 @@ public void RequestFSetStat(byte[] handle, SftpFileAttributes attributes) { SshException exception = null; - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { - var request = new SftpFSetStatRequest(ProtocolVersion, NextRequestId, handle, attributes, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + var request = new SftpFSetStatRequest(ProtocolVersion, + NextRequestId, + handle, + attributes, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -1025,7 +1132,7 @@ public void RequestFSetStat(byte[] handle, SftpFileAttributes attributes) } /// - /// Performs SSH_FXP_OPENDIR request + /// Performs SSH_FXP_OPENDIR request. /// /// The path. /// if set to true returns null instead of throwing an exception. @@ -1036,19 +1143,22 @@ public byte[] RequestOpenDir(string path, bool nullOnError = false) byte[] handle = null; - using (var wait = new AutoResetEvent(false)) - { - var request = new SftpOpenDirRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - handle = response.Handle; - wait.Set(); - }, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + using (var wait = new AutoResetEvent(initialState: false)) + { + var request = new SftpOpenDirRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => + { + handle = response.Handle; + _ = wait.Set(); + }, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -1067,20 +1177,23 @@ public async Task RequestOpenDirAsync(string path, CancellationToken can { cancellationToken.ThrowIfCancellationRequested(); - TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource)s).TrySetCanceled(), tcs, false)) + using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) { - SendRequest(new SftpOpenDirRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => tcs.TrySetResult(response.Handle), - response => tcs.TrySetException(GetSftpException(response)))); + SendRequest(new SftpOpenDirRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => tcs.TrySetResult(response.Handle), + response => tcs.TrySetException(GetSftpException(response)))); return await tcs.Task.ConfigureAwait(false); } } /// - /// Performs SSH_FXP_READDIR request + /// Performs SSH_FXP_READDIR request. /// /// The handle. /// @@ -1090,22 +1203,25 @@ public KeyValuePair[] RequestReadDir(byte[] handle) KeyValuePair[] result = null; - using (var wait = new AutoResetEvent(false)) - { - var request = new SftpReadDirRequest(ProtocolVersion, NextRequestId, handle, - response => - { - result = response.Files; - wait.Set(); - }, - response => - { - if (response.StatusCode != StatusCodes.Eof) - { - exception = GetSftpException(response); - } - wait.Set(); - }); + using (var wait = new AutoResetEvent(initialState: false)) + { + var request = new SftpReadDirRequest(ProtocolVersion, + NextRequestId, + handle, + response => + { + result = response.Files; + _ = wait.Set(); + }, + response => + { + if (response.StatusCode != StatusCodes.Eof) + { + exception = GetSftpException(response); + } + + _ = wait.Set(); + }); SendRequest(request); @@ -1124,23 +1240,25 @@ public async Task[]> RequestReadDirAsyn { cancellationToken.ThrowIfCancellationRequested(); - TaskCompletionSource[]> tcs = new TaskCompletionSource[]>(TaskCreationOptions.RunContinuationsAsynchronously); - - using (cancellationToken.Register((s) => ((TaskCompletionSource[]>)s).TrySetCanceled(), tcs, false)) - { - SendRequest(new SftpReadDirRequest(ProtocolVersion, NextRequestId, handle, - response => tcs.TrySetResult(response.Files), - response => - { - if (response.StatusCode == StatusCodes.Eof) - { - tcs.TrySetResult(null); - } - else - { - tcs.TrySetException(GetSftpException(response)); - } - })); + var tcs = new TaskCompletionSource[]>(TaskCreationOptions.RunContinuationsAsynchronously); + + using (cancellationToken.Register((s) => ((TaskCompletionSource[]>) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) + { + SendRequest(new SftpReadDirRequest(ProtocolVersion, + NextRequestId, + handle, + response => tcs.TrySetResult(response.Files), + response => + { + if (response.StatusCode == StatusCodes.Eof) + { + _ = tcs.TrySetResult(null); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } + })); return await tcs.Task.ConfigureAwait(false); } @@ -1154,14 +1272,17 @@ public void RequestRemove(string path) { SshException exception = null; - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { - var request = new SftpRemoveRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + var request = new SftpRemoveRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -1178,24 +1299,27 @@ public async Task RequestRemoveAsync(string path, CancellationToken cancellation { cancellationToken.ThrowIfCancellationRequested(); - TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource)s).TrySetCanceled(), tcs, false)) + using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) { - SendRequest(new SftpRemoveRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - if (response.StatusCode == StatusCodes.Ok) - { - tcs.TrySetResult(true); - } - else - { - tcs.TrySetException(GetSftpException(response)); - } - })); + SendRequest(new SftpRemoveRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => + { + if (response.StatusCode == StatusCodes.Ok) + { + _ = tcs.TrySetResult(true); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } + })); - await tcs.Task.ConfigureAwait(false); + _ = await tcs.Task.ConfigureAwait(false); } } @@ -1207,14 +1331,17 @@ public void RequestMkDir(string path) { SshException exception = null; - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { - var request = new SftpMkDirRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + var request = new SftpMkDirRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -1235,14 +1362,17 @@ public void RequestRmDir(string path) { SshException exception = null; - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { - var request = new SftpRmDirRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + var request = new SftpRmDirRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -1256,7 +1386,7 @@ public void RequestRmDir(string path) } /// - /// Performs SSH_FXP_REALPATH request + /// Performs SSH_FXP_REALPATH request. /// /// The path. /// if set to true returns null instead of throwing an exception. @@ -1269,19 +1399,22 @@ internal KeyValuePair[] RequestRealPath(string path, KeyValuePair[] result = null; - using (var wait = new AutoResetEvent(false)) - { - var request = new SftpRealPathRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - result = response.Files; - wait.Set(); - }, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + using (var wait = new AutoResetEvent(initialState: false)) + { + var request = new SftpRealPathRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => + { + result = response.Files; + _ = wait.Set(); + }, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -1300,23 +1433,26 @@ internal async Task[]> RequestRealPathA { cancellationToken.ThrowIfCancellationRequested(); - TaskCompletionSource[]> tcs = new TaskCompletionSource[]>(TaskCreationOptions.RunContinuationsAsynchronously); - - using (cancellationToken.Register((s) => ((TaskCompletionSource[]>)s).TrySetCanceled(), tcs, false)) - { - SendRequest(new SftpRealPathRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => tcs.TrySetResult(response.Files), - response => - { - if (nullOnError) - { - tcs.TrySetResult(null); - } - else - { - tcs.TrySetException(GetSftpException(response)); - } - })); + var tcs = new TaskCompletionSource[]>(TaskCreationOptions.RunContinuationsAsynchronously); + + using (cancellationToken.Register((s) => ((TaskCompletionSource[]>) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) + { + SendRequest(new SftpRealPathRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => tcs.TrySetResult(response.Files), + response => + { + if (nullOnError) + { + _ = tcs.TrySetResult(null); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } + })); return await tcs.Task.ConfigureAwait(false); } @@ -1335,15 +1471,12 @@ public SftpRealPathAsyncResult BeginRealPath(string path, AsyncCallback callback { var asyncResult = new SftpRealPathAsyncResult(callback, state); - var request = new SftpRealPathRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - asyncResult.SetAsCompleted(response.Files[0].Key, false); - }, - response => - { - asyncResult.SetAsCompleted(GetSftpException(response), false); - }); + var request = new SftpRealPathRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => asyncResult.SetAsCompleted(response.Files[0].Key, completedSynchronously: false), + response => asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false)); SendRequest(request); return asyncResult; @@ -1360,13 +1493,19 @@ public SftpRealPathAsyncResult BeginRealPath(string path, AsyncCallback callback public string EndRealPath(SftpRealPathAsyncResult asyncResult) { if (asyncResult == null) - throw new ArgumentNullException("asyncResult"); + { + throw new ArgumentNullException(nameof(asyncResult)); + } if (asyncResult.EndInvokeCalled) + { throw new InvalidOperationException("EndRealPath has already been called."); + } if (asyncResult.IsCompleted) + { return asyncResult.EndInvoke(); + } using (var waitHandle = asyncResult.AsyncWaitHandle) { @@ -1381,7 +1520,7 @@ public string EndRealPath(SftpRealPathAsyncResult asyncResult) /// The path. /// if set to true returns null instead of throwing an exception. /// - /// File attributes + /// File attributes. /// public SftpFileAttributes RequestStat(string path, bool nullOnError = false) { @@ -1389,19 +1528,22 @@ public SftpFileAttributes RequestStat(string path, bool nullOnError = false) SftpFileAttributes attributes = null; - using (var wait = new AutoResetEvent(false)) - { - var request = new SftpStatRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - attributes = response.Attributes; - wait.Set(); - }, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + using (var wait = new AutoResetEvent(initialState: false)) + { + var request = new SftpStatRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => + { + attributes = response.Attributes; + _ = wait.Set(); + }, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -1417,7 +1559,7 @@ public SftpFileAttributes RequestStat(string path, bool nullOnError = false) } /// - /// Performs SSH_FXP_STAT request + /// Performs SSH_FXP_STAT request. /// /// The path. /// The delegate that is executed when completes. @@ -1429,15 +1571,12 @@ public SFtpStatAsyncResult BeginStat(string path, AsyncCallback callback, object { var asyncResult = new SFtpStatAsyncResult(callback, state); - var request = new SftpStatRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - asyncResult.SetAsCompleted(response.Attributes, false); - }, - response => - { - asyncResult.SetAsCompleted(GetSftpException(response), false); - }); + var request = new SftpStatRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => asyncResult.SetAsCompleted(response.Attributes, completedSynchronously: false), + response => asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false)); SendRequest(request); return asyncResult; @@ -1454,13 +1593,19 @@ public SFtpStatAsyncResult BeginStat(string path, AsyncCallback callback, object public SftpFileAttributes EndStat(SFtpStatAsyncResult asyncResult) { if (asyncResult == null) - throw new ArgumentNullException("asyncResult"); + { + throw new ArgumentNullException(nameof(asyncResult)); + } if (asyncResult.EndInvokeCalled) + { throw new InvalidOperationException("EndStat has already been called."); + } if (asyncResult.IsCompleted) + { return asyncResult.EndInvoke(); + } using (var waitHandle = asyncResult.AsyncWaitHandle) { @@ -1483,14 +1628,18 @@ public void RequestRename(string oldPath, string newPath) SshException exception = null; - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { - var request = new SftpRenameRequest(ProtocolVersion, NextRequestId, oldPath, newPath, Encoding, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + var request = new SftpRenameRequest(ProtocolVersion, + NextRequestId, + oldPath, + newPath, + Encoding, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -1507,24 +1656,28 @@ public async Task RequestRenameAsync(string oldPath, string newPath, Cancellatio { cancellationToken.ThrowIfCancellationRequested(); - TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - - using (cancellationToken.Register((s) => ((TaskCompletionSource)s).TrySetCanceled(), tcs, false)) - { - SendRequest(new SftpRenameRequest(ProtocolVersion, NextRequestId, oldPath, newPath, Encoding, - response => - { - if (response.StatusCode == StatusCodes.Ok) - { - tcs.TrySetResult(true); - } - else - { - tcs.TrySetException(GetSftpException(response)); - } - })); - - await tcs.Task.ConfigureAwait(false); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + + using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) + { + SendRequest(new SftpRenameRequest(ProtocolVersion, + NextRequestId, + oldPath, + newPath, + Encoding, + response => + { + if (response.StatusCode == StatusCodes.Ok) + { + _ = tcs.TrySetResult(true); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } + })); + + _ = await tcs.Task.ConfigureAwait(false); } } @@ -1545,19 +1698,22 @@ internal KeyValuePair[] RequestReadLink(string path, KeyValuePair[] result = null; - using (var wait = new AutoResetEvent(false)) - { - var request = new SftpReadLinkRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - result = response.Files; - wait.Set(); - }, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + using (var wait = new AutoResetEvent(initialState: false)) + { + var request = new SftpReadLinkRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => + { + result = response.Files; + _ = wait.Set(); + }, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -1586,14 +1742,18 @@ public void RequestSymLink(string linkpath, string targetpath) SshException exception = null; - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { - var request = new SftpSymLinkRequest(ProtocolVersion, NextRequestId, linkpath, targetpath, Encoding, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + var request = new SftpSymLinkRequest(ProtocolVersion, + NextRequestId, + linkpath, + targetpath, + Encoding, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); @@ -1606,10 +1766,6 @@ public void RequestSymLink(string linkpath, string targetpath) } } - #endregion - - #region SFTP Extended API functions - /// /// Performs posix-rename@openssh.com extended request. /// @@ -1624,17 +1780,23 @@ public void RequestPosixRename(string oldPath, string newPath) SshException exception = null; - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { - var request = new PosixRenameRequest(ProtocolVersion, NextRequestId, oldPath, newPath, Encoding, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + var request = new PosixRenameRequest(ProtocolVersion, + NextRequestId, + oldPath, + newPath, + Encoding, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); if (!_supportedExtensions.ContainsKey(request.Name)) + { throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Extension method {0} currently not supported by the server.", request.Name)); + } SendRequest(request); @@ -1652,7 +1814,9 @@ public void RequestPosixRename(string oldPath, string newPath) /// /// The path. /// if set to true [null on error]. - /// + /// + /// A for the specified path. + /// public SftpFileSytemInformation RequestStatVfs(string path, bool nullOnError = false) { if (ProtocolVersion < 3) @@ -1664,22 +1828,27 @@ public SftpFileSytemInformation RequestStatVfs(string path, bool nullOnError = f SftpFileSytemInformation information = null; - using (var wait = new AutoResetEvent(false)) - { - var request = new StatVfsRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => - { - information = response.GetReply().Information; - wait.Set(); - }, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + using (var wait = new AutoResetEvent(initialState: false)) + { + var request = new StatVfsRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => + { + information = response.GetReply().Information; + _ = wait.Set(); + }, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); if (!_supportedExtensions.ContainsKey(request.Name)) + { throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Extension method {0} currently not supported by the server.", request.Name)); + } SendRequest(request); @@ -1703,13 +1872,16 @@ public async Task RequestStatVfsAsync(string path, Can cancellationToken.ThrowIfCancellationRequested(); - TaskCompletionSource tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource)s).TrySetCanceled(), tcs, false)) + using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) { - SendRequest(new StatVfsRequest(ProtocolVersion, NextRequestId, path, Encoding, - response => tcs.TrySetResult(response.GetReply().Information), - response => tcs.TrySetException(GetSftpException(response)))); + SendRequest(new StatVfsRequest(ProtocolVersion, + NextRequestId, + path, + Encoding, + response => tcs.TrySetResult(response.GetReply().Information), + response => tcs.TrySetException(GetSftpException(response)))); return await tcs.Task.ConfigureAwait(false); } @@ -1720,8 +1892,10 @@ public async Task RequestStatVfsAsync(string path, Can /// /// The file handle. /// if set to true [null on error]. - /// - /// + /// + /// A for the specified path. + /// + /// This operation is not supported for the current SFTP protocol version. internal SftpFileSytemInformation RequestFStatVfs(byte[] handle, bool nullOnError = false) { if (ProtocolVersion < 3) @@ -1733,22 +1907,26 @@ internal SftpFileSytemInformation RequestFStatVfs(byte[] handle, bool nullOnErro SftpFileSytemInformation information = null; - using (var wait = new AutoResetEvent(false)) - { - var request = new FStatVfsRequest(ProtocolVersion, NextRequestId, handle, - response => - { - information = response.GetReply().Information; - wait.Set(); - }, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + using (var wait = new AutoResetEvent(initialState: false)) + { + var request = new FStatVfsRequest(ProtocolVersion, + NextRequestId, + handle, + response => + { + information = response.GetReply().Information; + _ = wait.Set(); + }, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); if (!_supportedExtensions.ContainsKey(request.Name)) + { throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Extension method {0} currently not supported by the server.", request.Name)); + } SendRequest(request); @@ -1777,17 +1955,22 @@ internal void HardLink(string oldPath, string newPath) SshException exception = null; - using (var wait = new AutoResetEvent(false)) + using (var wait = new AutoResetEvent(initialState: false)) { - var request = new HardLinkRequest(ProtocolVersion, NextRequestId, oldPath, newPath, - response => - { - exception = GetSftpException(response); - wait.Set(); - }); + var request = new HardLinkRequest(ProtocolVersion, + NextRequestId, + oldPath, + newPath, + response => + { + exception = GetSftpException(response); + _ = wait.Set(); + }); if (!_supportedExtensions.ContainsKey(request.Name)) + { throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Extension method {0} currently not supported by the server.", request.Name)); + } SendRequest(request); @@ -1800,8 +1983,6 @@ internal void HardLink(string oldPath, string newPath) } } - #endregion - /// /// Calculates the optimal size of the buffer to read data from the channel. /// @@ -1815,7 +1996,7 @@ public uint CalculateOptimalReadLength(uint bufferSize) // bytes 1 to 4: packet length // byte 5: message type // bytes 6 to 9: response id - // bytes 10 to 13: length of payload鈥 + // bytes 10 to 13: length of payload // // WinSCP uses a payload length of 32755 bytes // @@ -1851,8 +2032,10 @@ public uint CalculateOptimalWriteLength(uint bufferSize, byte[] handle) // 14-21: offset // 22-25: data length - // Putty uses data length of 4096 bytes - // WinSCP uses data length of 32739 bytes (total 32768 bytes; 32739 + 25 + 4 bytes for handle) + /* + * Putty uses data length of 4096 bytes + * WinSCP uses data length of 32739 bytes (total 32768 bytes; 32739 + 25 + 4 bytes for handle) + */ var lengthOfNonDataProtocolFields = 25u + (uint)handle.Length; var maximumPacketSize = Channel.RemotePacketSize; @@ -1879,15 +2062,17 @@ private void HandleResponse(SftpResponse response) SftpRequest request; lock (_requests) { - _requests.TryGetValue(response.ResponseId, out request); + _ = _requests.TryGetValue(response.ResponseId, out request); if (request != null) { - _requests.Remove(response.ResponseId); + _ = _requests.Remove(response.ResponseId); } } if (request == null) + { throw new InvalidOperationException("Invalid response."); + } request.Complete(response); } diff --git a/src/Renci.SshNet/Sftp/SftpSynchronizeDirectoriesAsyncResult.cs b/src/Renci.SshNet/Sftp/SftpSynchronizeDirectoriesAsyncResult.cs index 0d2644de5..35aacd200 100644 --- a/src/Renci.SshNet/Sftp/SftpSynchronizeDirectoriesAsyncResult.cs +++ b/src/Renci.SshNet/Sftp/SftpSynchronizeDirectoriesAsyncResult.cs @@ -1,8 +1,9 @@ 锘縰sing System; using System.Collections.Generic; -using Renci.SshNet.Common; using System.IO; +using Renci.SshNet.Common; + namespace Renci.SshNet.Sftp { /// @@ -16,11 +17,11 @@ public class SftpSynchronizeDirectoriesAsyncResult : AsyncResult - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The async callback. /// The state. - public SftpSynchronizeDirectoriesAsyncResult(AsyncCallback asyncCallback, Object state) + public SftpSynchronizeDirectoriesAsyncResult(AsyncCallback asyncCallback, object state) : base(asyncCallback, state) { } diff --git a/src/Renci.SshNet/Sftp/SftpUploadAsyncResult.cs b/src/Renci.SshNet/Sftp/SftpUploadAsyncResult.cs index 5f586daf5..10069b259 100644 --- a/src/Renci.SshNet/Sftp/SftpUploadAsyncResult.cs +++ b/src/Renci.SshNet/Sftp/SftpUploadAsyncResult.cs @@ -1,4 +1,5 @@ 锘縰sing System; + using Renci.SshNet.Common; namespace Renci.SshNet.Sftp @@ -9,7 +10,7 @@ namespace Renci.SshNet.Sftp public class SftpUploadAsyncResult : AsyncResult { /// - /// Gets or sets a value indicating whether to cancel asynchronous upload operation + /// Gets or sets a value indicating whether to cancel asynchronous upload operation. /// /// /// true if upload operation to be canceled; otherwise, false. @@ -29,7 +30,7 @@ public class SftpUploadAsyncResult : AsyncResult /// /// The async callback. /// The state. - public SftpUploadAsyncResult(AsyncCallback asyncCallback, Object state) + public SftpUploadAsyncResult(AsyncCallback asyncCallback, object state) : base(asyncCallback, state) { } diff --git a/src/Renci.SshNet/Shell.cs b/src/Renci.SshNet/Shell.cs index 3e68e6b12..63ebcf7e7 100644 --- a/src/Renci.SshNet/Shell.cs +++ b/src/Renci.SshNet/Shell.cs @@ -1,32 +1,33 @@ 锘縰sing System; +using System.Collections.Generic; using System.IO; using System.Threading; + +using Renci.SshNet.Abstractions; using Renci.SshNet.Channels; using Renci.SshNet.Common; -using System.Collections.Generic; -using Renci.SshNet.Abstractions; namespace Renci.SshNet { /// - /// Represents instance of the SSH shell object + /// Represents instance of the SSH shell object. /// public class Shell : IDisposable { private readonly ISession _session; - private IChannelSession _channel; - private EventWaitHandle _channelClosedWaitHandle; - private Stream _input; private readonly string _terminalName; private readonly uint _columns; private readonly uint _rows; private readonly uint _width; private readonly uint _height; private readonly IDictionary _terminalModes; - private EventWaitHandle _dataReaderTaskCompleted; private readonly Stream _outputStream; private readonly Stream _extendedOutputStream; private readonly int _bufferSize; + private EventWaitHandle _dataReaderTaskCompleted; + private IChannelSession _channel; + private EventWaitHandle _channelClosedWaitHandle; + private Stream _input; /// /// Gets a value indicating whether this shell is started. @@ -101,10 +102,7 @@ public void Start() throw new SshException("Shell is started."); } - if (Starting != null) - { - Starting(this, new EventArgs()); - } + Starting?.Invoke(this, new EventArgs()); _channel = _session.CreateChannelSession(); _channel.DataReceived += Channel_DataReceived; @@ -114,13 +112,13 @@ public void Start() _session.ErrorOccured += Session_ErrorOccured; _channel.Open(); - _channel.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModes); - _channel.SendShellRequest(); + _ = _channel.SendPseudoTerminalRequest(_terminalName, _columns, _rows, _width, _height, _terminalModes); + _ = _channel.SendShellRequest(); - _channelClosedWaitHandle = new AutoResetEvent(false); + _channelClosedWaitHandle = new AutoResetEvent(initialState: false); - // Start input stream listener - _dataReaderTaskCompleted = new ManualResetEvent(false); + // Start input stream listener + _dataReaderTaskCompleted = new ManualResetEvent(initialState: false); ThreadAbstraction.ExecuteThread(() => { try @@ -148,16 +146,13 @@ public void Start() } finally { - _dataReaderTaskCompleted.Set(); + _ = _dataReaderTaskCompleted.Set(); } }); IsStarted = true; - if (Started != null) - { - Started(this, new EventArgs()); - } + Started?.Invoke(this, EventArgs.Empty); } /// @@ -171,10 +166,7 @@ public void Stop() throw new SshException("Shell is not started."); } - if (_channel != null) - { - _channel.Dispose(); - } + _channel?.Dispose(); } private void Session_ErrorOccured(object sender, ExceptionEventArgs e) @@ -184,11 +176,7 @@ private void Session_ErrorOccured(object sender, ExceptionEventArgs e) private void RaiseError(ExceptionEventArgs e) { - var handler = ErrorOccurred; - if (handler != null) - { - handler(this, e); - } + ErrorOccurred?.Invoke(this, e); } private void Session_Disconnected(object sender, EventArgs e) @@ -198,35 +186,29 @@ private void Session_Disconnected(object sender, EventArgs e) private void Channel_ExtendedDataReceived(object sender, ChannelExtendedDataEventArgs e) { - if (_extendedOutputStream != null) - { - _extendedOutputStream.Write(e.Data, 0, e.Data.Length); - } + _extendedOutputStream?.Write(e.Data, 0, e.Data.Length); } private void Channel_DataReceived(object sender, ChannelDataEventArgs e) { - if (_outputStream != null) - { - _outputStream.Write(e.Data, 0, e.Data.Length); - } + _outputStream?.Write(e.Data, 0, e.Data.Length); } private void Channel_Closed(object sender, ChannelEventArgs e) { if (Stopping != null) { - // Handle event on different thread - ThreadAbstraction.ExecuteThread(() => Stopping(this, new EventArgs())); + // Handle event on different thread + ThreadAbstraction.ExecuteThread(() => Stopping(this, EventArgs.Empty)); } _channel.Dispose(); - _channelClosedWaitHandle.Set(); + _ = _channelClosedWaitHandle.Set(); _input.Dispose(); _input = null; - _dataReaderTaskCompleted.WaitOne(_session.ConnectionInfo.Timeout); + _ = _dataReaderTaskCompleted.WaitOne(_session.ConnectionInfo.Timeout); _dataReaderTaskCompleted.Dispose(); _dataReaderTaskCompleted = null; @@ -238,8 +220,8 @@ private void Channel_Closed(object sender, ChannelEventArgs e) if (Stopped != null) { - // Handle event on different thread - ThreadAbstraction.ExecuteThread(() => Stopped(this, new EventArgs())); + // Handle event on different thread + ThreadAbstraction.ExecuteThread(() => Stopped(this, EventArgs.Empty)); } _channel = null; @@ -255,14 +237,14 @@ private void Channel_Closed(object sender, ChannelEventArgs e) private void UnsubscribeFromSessionEvents(ISession session) { if (session == null) + { return; + } session.Disconnected -= Session_Disconnected; session.ErrorOccured -= Session_ErrorOccured; } - #region IDisposable Members - private bool _disposed; /// @@ -270,18 +252,20 @@ private void UnsubscribeFromSessionEvents(ISession session) /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_disposed) + { return; + } if (disposing) { @@ -313,15 +297,11 @@ protected virtual void Dispose(bool disposing) } /// - /// Releases unmanaged resources and performs other cleanup operations before the - /// is reclaimed by garbage collection. + /// Finalizes an instance of the class. /// ~Shell() { - Dispose(false); + Dispose(disposing: false); } - - #endregion - } } diff --git a/src/Renci.SshNet/ShellStream.cs b/src/Renci.SshNet/ShellStream.cs index 3274fe19c..004b962a3 100644 --- a/src/Renci.SshNet/ShellStream.cs +++ b/src/Renci.SshNet/ShellStream.cs @@ -1,12 +1,13 @@ 锘縰sing System; using System.Collections.Generic; -using System.Text; using System.IO; -using Renci.SshNet.Channels; -using Renci.SshNet.Common; -using System.Threading; +using System.Text; using System.Text.RegularExpressions; +using System.Threading; + using Renci.SshNet.Abstractions; +using Renci.SshNet.Channels; +using Renci.SshNet.Common; namespace Renci.SshNet { @@ -23,7 +24,7 @@ public class ShellStream : Stream private readonly Queue _incoming; private readonly Queue _outgoing; private IChannelSession _channel; - private AutoResetEvent _dataReceived = new AutoResetEvent(false); + private AutoResetEvent _dataReceived = new AutoResetEvent(initialState: false); private bool _isDisposed; /// @@ -37,7 +38,7 @@ public class ShellStream : Stream public event EventHandler ErrorOccurred; /// - /// Gets a value that indicates whether data is available on the to be read. + /// Gets a value indicating whether data is available on the to be read. /// /// /// true if data is available to be read; otherwise, false. @@ -65,13 +66,13 @@ internal int BufferSize } /// - /// Initializes a new instance. + /// Initializes a new instance of the class. /// /// The SSH session. /// The TERM environment variable. /// The terminal width in columns. /// The terminal width in rows. - /// The terminal height in pixels. + /// The terminal width in pixels. /// The terminal height in pixels. /// The terminal mode values. /// The size of the buffer. @@ -95,10 +96,12 @@ internal ShellStream(ISession session, string terminalName, uint columns, uint r try { _channel.Open(); + if (!_channel.SendPseudoTerminalRequest(terminalName, columns, rows, width, height, terminalModeValues)) { throw new SshException("The pseudo-terminal request was not accepted by the server. Consult the server log for more information."); } + if (!_channel.SendShellRequest()) { throw new SshException("The request to start a shell was not accepted by the server. Consult the server log for more information."); @@ -112,8 +115,6 @@ internal ShellStream(ISession session, string terminalName, uint columns, uint r } } - #region Stream overide methods - /// /// Gets a value indicating whether the current stream supports reading. /// @@ -150,7 +151,7 @@ public override bool CanWrite /// /// Clears all buffers for this stream and causes any buffered data to be written to the underlying device. /// - /// An I/O error occurs. + /// An I/O error occurs. /// Methods were called after the stream was closed. public override void Flush() { @@ -189,9 +190,9 @@ public override long Length /// /// 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. + /// An I/O error occurs. + /// The stream does not support seeking. + /// Methods were called after the stream was closed. public override long Position { get { return 0; } @@ -207,12 +208,12 @@ public override long Position /// /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. /// - /// The sum of and is larger than the buffer length. - /// is null. - /// or is negative. - /// An I/O error occurs. - /// The stream does not support reading. - /// Methods were called after the stream was closed. + /// The sum of and is larger than the buffer length. + /// is null. + /// or is negative. + /// An I/O error occurs. + /// The stream does not support reading. + /// Methods were called after the stream was closed. public override int Read(byte[] buffer, int offset, int count) { var i = 0; @@ -232,13 +233,13 @@ public override int Read(byte[] buffer, int offset, int count) /// This method is not supported. /// /// A byte offset relative to the parameter. - /// A value of type indicating the reference point used to obtain the new position. + /// A value of type indicating the reference point used to obtain the new position. /// /// The new position within the current stream. /// - /// An I/O error occurs. - /// The stream does not support seeking, such as if the stream is constructed from a pipe or console output. - /// Methods were called after the stream was closed. + /// An I/O error occurs. + /// The stream does not support seeking, such as if the stream is constructed from a pipe or console output. + /// Methods were called after the stream was closed. public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); @@ -248,9 +249,9 @@ public override long Seek(long offset, SeekOrigin origin) /// This method is not supported. /// /// The desired length of the current stream in bytes. - /// An I/O error occurs. - /// The stream does not support both writing and seeking, such as if the stream is constructed from a pipe or console output. - /// Methods were called after the stream was closed. + /// An I/O error occurs. + /// The stream does not support both writing and seeking, such as if the stream is constructed from a pipe or console output. + /// Methods were called after the stream was closed. public override void SetLength(long value) { throw new NotSupportedException(); @@ -262,12 +263,12 @@ public override void SetLength(long value) /// An array of bytes. This method copies bytes from to the current stream. /// The zero-based byte offset in at which to begin copying bytes to the current stream. /// The number of bytes to be written to the current stream. - /// The sum of and is greater than the buffer length. - /// is null. - /// or is negative. - /// An I/O error occurs. - /// The stream does not support writing. - /// Methods were called after the stream was closed. + /// The sum of and is greater than the buffer length. + /// is null. + /// or is negative. + /// An I/O error occurs. + /// The stream does not support writing. + /// Methods were called after the stream was closed. public override void Write(byte[] buffer, int offset, int count) { foreach (var b in buffer.Take(offset, count)) @@ -281,8 +282,6 @@ public override void Write(byte[] buffer, int offset, int count) } } - #endregion - /// /// Expects the specified expression and performs action when one is found. /// @@ -323,8 +322,8 @@ public void Expect(TimeSpan timeout, params ExpectAction[] expectActions) for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++) { - // Remove processed items from the queue - _incoming.Dequeue(); + // Remove processed items from the queue + _ = _incoming.Dequeue(); } expectAction.Action(result); @@ -345,7 +344,7 @@ public void Expect(TimeSpan timeout, params ExpectAction[] expectActions) } else { - _dataReceived.WaitOne(); + _ = _dataReceived.WaitOne(); } } } @@ -361,7 +360,7 @@ public void Expect(TimeSpan timeout, params ExpectAction[] expectActions) /// public IAsyncResult BeginExpect(params ExpectAction[] expectActions) { - return BeginExpect(TimeSpan.Zero, null, null, expectActions); + return BeginExpect(TimeSpan.Zero, callback: null, state: null, expectActions); } /// @@ -374,7 +373,7 @@ public IAsyncResult BeginExpect(params ExpectAction[] expectActions) /// public IAsyncResult BeginExpect(AsyncCallback callback, params ExpectAction[] expectActions) { - return BeginExpect(TimeSpan.Zero, callback, null, expectActions); + return BeginExpect(TimeSpan.Zero, callback, state: null, expectActions); } /// @@ -405,21 +404,19 @@ public IAsyncResult BeginExpect(TimeSpan timeout, AsyncCallback callback, object { var text = string.Empty; - // Create new AsyncResult object + // Create new AsyncResult object var asyncResult = new ExpectAsyncResult(callback, state); - // Execute callback on different thread + // Execute callback on different thread ThreadAbstraction.ExecuteThread(() => { string expectActionResult = null; try { - do { lock (_incoming) { - if (_incoming.Count > 0) { text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count); @@ -437,16 +434,12 @@ public IAsyncResult BeginExpect(TimeSpan timeout, AsyncCallback callback, object for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++) { - // Remove processed items from the queue - _incoming.Dequeue(); + // Remove processed items from the queue + _ = _incoming.Dequeue(); } expectAction.Action(result); - - if (callback != null) - { - callback(asyncResult); - } + callback?.Invoke(asyncResult); expectActionResult = result; } } @@ -454,30 +447,30 @@ public IAsyncResult BeginExpect(TimeSpan timeout, AsyncCallback callback, object } if (expectActionResult != null) + { break; + } if (timeout.Ticks > 0) { if (!_dataReceived.WaitOne(timeout)) { - if (callback != null) - { - callback(asyncResult); - } + callback?.Invoke(asyncResult); break; } } else { - _dataReceived.WaitOne(); + _ = _dataReceived.WaitOne(); } - } while (true); + } + while (true); - asyncResult.SetAsCompleted(expectActionResult, true); + asyncResult.SetAsCompleted(expectActionResult, completedSynchronously: true); } catch (Exception exp) { - asyncResult.SetAsCompleted(exp, true); + asyncResult.SetAsCompleted(exp, completedSynchronously: true); } }); @@ -491,10 +484,10 @@ public IAsyncResult BeginExpect(TimeSpan timeout, AsyncCallback callback, object /// 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. public string EndExpect(IAsyncResult asyncResult) { - var ar = asyncResult as ExpectAsyncResult; - - if (ar == null || ar.EndInvokeCalled) + if (asyncResult is not ExpectAsyncResult ar || ar.EndInvokeCalled) + { throw new ArgumentException("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."); + } // Wait for operation to complete, then return result or throw exception return ar.EndInvoke(); @@ -563,11 +556,12 @@ public string Expect(Regex regex, TimeSpan timeout) if (match.Success) { - // Remove processed items from the queue + // Remove processed items from the queue for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++) { - _incoming.Dequeue(); + _ = _incoming.Dequeue(); } + break; } } @@ -581,9 +575,8 @@ public string Expect(Regex regex, TimeSpan timeout) } else { - _dataReceived.WaitOne(); + _ = _dataReceived.WaitOne(); } - } return text; @@ -631,7 +624,9 @@ public string ReadLine(TimeSpan timeout) // remove processed bytes from the queue for (var i = 0; i < bytesProcessed; i++) - _incoming.Dequeue(); + { + _ = _incoming.Dequeue(); + } break; } @@ -646,9 +641,8 @@ public string ReadLine(TimeSpan timeout) } else { - _dataReceived.WaitOne(); + _ = _dataReceived.WaitOne(); } - } return text; @@ -683,7 +677,9 @@ public string Read() public void Write(string text) { if (text == null) + { return; + } if (_channel == null) { @@ -715,7 +711,9 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); if (_isDisposed) + { return; + } if (disposing) { @@ -753,7 +751,9 @@ protected override void Dispose(bool disposing) private void UnsubscribeFromSessionEvents(ISession session) { if (session == null) + { return; + } session.Disconnected -= Session_Disconnected; session.ErrorOccured -= Session_ErrorOccured; @@ -767,12 +767,14 @@ private void Session_ErrorOccured(object sender, ExceptionEventArgs e) private void Session_Disconnected(object sender, EventArgs e) { if (_channel != null) + { _channel.Dispose(); + } } private void Channel_Closed(object sender, ChannelEventArgs e) { - // TODO: Do we need to call dispose here ?? + // TODO: Do we need to call dispose here ?? Dispose(); } @@ -781,31 +783,27 @@ private void Channel_DataReceived(object sender, ChannelDataEventArgs e) lock (_incoming) { foreach (var b in e.Data) + { _incoming.Enqueue(b); + } } if (_dataReceived != null) - _dataReceived.Set(); + { + _ = _dataReceived.Set(); + } OnDataReceived(e.Data); } private void OnRaiseError(ExceptionEventArgs e) { - var handler = ErrorOccurred; - if (handler != null) - { - handler(this, e); - } + ErrorOccurred?.Invoke(this, e); } private void OnDataReceived(byte[] data) { - var handler = DataReceived; - if (handler != null) - { - handler(this, new ShellDataEventArgs(data)); - } + DataReceived?.Invoke(this, new ShellDataEventArgs(data)); } } } diff --git a/src/Renci.SshNet/SshClient.cs b/src/Renci.SshNet/SshClient.cs index 881a173d4..26a3cb1b4 100644 --- a/src/Renci.SshNet/SshClient.cs +++ b/src/Renci.SshNet/SshClient.cs @@ -1,9 +1,10 @@ 锘縰sing System; using System.Collections.Generic; -using System.IO; -using System.Text; using System.Diagnostics.CodeAnalysis; +using System.IO; using System.Net; +using System.Text; + using Renci.SshNet.Common; namespace Renci.SshNet @@ -14,7 +15,7 @@ namespace Renci.SshNet public class SshClient : BaseClient { /// - /// Holds the list of forwarded ports + /// Holds the list of forwarded ports. /// private readonly List _forwardedPorts; @@ -39,8 +40,6 @@ public IEnumerable ForwardedPorts } } - #region Constructors - /// /// Initializes a new instance of the class. /// @@ -53,7 +52,7 @@ public IEnumerable ForwardedPorts /// /// is null. public SshClient(ConnectionInfo connectionInfo) - : this(connectionInfo, false) + : this(connectionInfo, ownsConnectionInfo: false) { } @@ -69,7 +68,7 @@ public SshClient(ConnectionInfo connectionInfo) /// is not within and . [SuppressMessage("Microsoft.Reliability", "C2A000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] public SshClient(string host, int port, string username, string password) - : this(new PasswordConnectionInfo(host, port, username, password), true) + : this(new PasswordConnectionInfo(host, port, username, password), ownsConnectionInfo: true) { } @@ -105,7 +104,7 @@ public SshClient(string host, string username, string password) /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] public SshClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) - : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) + : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -159,8 +158,6 @@ internal SshClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServ _forwardedPorts = new List(); } - #endregion - /// /// Called when client is disconnecting from the server. /// @@ -188,7 +185,10 @@ protected override void OnDisconnecting() public void AddForwardedPort(ForwardedPort port) { if (port == null) - throw new ArgumentNullException("port"); + { + throw new ArgumentNullException(nameof(port)); + } + EnsureSessionIsOpen(); AttachForwardedPort(port); @@ -203,19 +203,23 @@ public void AddForwardedPort(ForwardedPort port) public void RemoveForwardedPort(ForwardedPort port) { if (port == null) - throw new ArgumentNullException("port"); + { + throw new ArgumentNullException(nameof(port)); + } - // Stop port forwarding before removing it + // Stop port forwarding before removing it port.Stop(); DetachForwardedPort(port); - _forwardedPorts.Remove(port); + _ = _forwardedPorts.Remove(port); } private void AttachForwardedPort(ForwardedPort port) { if (port.Session != null && port.Session != Session) + { throw new InvalidOperationException("Forwarded port is already added to a different client."); + } port.Session = Session; } @@ -264,14 +268,14 @@ public SshCommand CreateCommand(string commandText, Encoding encoding) /// /// /// CommandText property is empty. - /// Invalid Operation - An existing channel was used to execute this command. + /// Invalid Operation - An existing channel was used to execute this command. /// Asynchronous operation is already in progress. /// Client is not connected. /// is null. public SshCommand RunCommand(string commandText) { var cmd = CreateCommand(commandText); - cmd.Execute(); + _ = cmd.Execute(); return cmd; } @@ -361,7 +365,7 @@ public Shell CreateShell(Encoding encoding, string input, Stream output, Stream var writer = new StreamWriter(_inputStream, encoding); writer.Write(input); writer.Flush(); - _inputStream.Seek(0, SeekOrigin.Begin); + _ = _inputStream.Seek(0, SeekOrigin.Begin); return CreateShell(_inputStream, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize); } @@ -410,7 +414,7 @@ public Shell CreateShell(Encoding encoding, string input, Stream output, Stream /// The TERM environment variable. /// The terminal width in columns. /// The terminal width in rows. - /// The terminal height in pixels. + /// The terminal width in pixels. /// The terminal height in pixels. /// The size of the buffer. /// @@ -438,7 +442,7 @@ public ShellStream CreateShellStream(string terminalName, uint columns, uint row /// The TERM environment variable. /// The terminal width in columns. /// The terminal width in rows. - /// The terminal height in pixels. + /// The terminal width in pixels. /// The terminal height in pixels. /// The size of the buffer. /// The terminal mode values. @@ -479,7 +483,7 @@ protected override void OnDisconnected() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool disposing) @@ -487,7 +491,9 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); if (_isDisposed) + { return; + } if (disposing) { @@ -504,7 +510,9 @@ protected override void Dispose(bool disposing) private void EnsureSessionIsOpen() { if (Session == null) + { throw new SshConnectionException("Client not connected."); + } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/SshCommand.cs b/src/Renci.SshNet/SshCommand.cs index 37e91da08..2fa78d4a5 100644 --- a/src/Renci.SshNet/SshCommand.cs +++ b/src/Renci.SshNet/SshCommand.cs @@ -1,13 +1,14 @@ 锘縰sing System; +using System.Globalization; using System.IO; using System.Text; using System.Threading; + +using Renci.SshNet.Abstractions; using Renci.SshNet.Channels; using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; using Renci.SshNet.Messages.Transport; -using System.Globalization; -using Renci.SshNet.Abstractions; namespace Renci.SshNet { @@ -16,15 +17,19 @@ namespace Renci.SshNet /// public class SshCommand : IDisposable { - private ISession _session; private readonly Encoding _encoding; + private readonly object _endExecuteLock = new object(); + + private ISession _session; private IChannelSession _channel; private CommandAsyncResult _asyncResult; private AsyncCallback _callback; private EventWaitHandle _sessionErrorOccuredWaitHandle; private Exception _exception; + private StringBuilder _result; + private StringBuilder _error; private bool _hasError; - private readonly object _endExecuteLock = new object(); + private bool _isDisposed; /// /// Gets the command text. @@ -66,7 +71,6 @@ public class SshCommand : IDisposable /// public Stream ExtendedOutputStream { get; private set; } - private StringBuilder _result; /// /// Gets the command execution result. /// @@ -77,23 +81,19 @@ public string Result { get { - if (_result == null) - { - _result = new StringBuilder(); - } + _result ??= new StringBuilder(); if (OutputStream != null && OutputStream.Length > 0) { // do not dispose the StreamReader, as it would also dispose the stream var sr = new StreamReader(OutputStream, _encoding); - _result.Append(sr.ReadToEnd()); + _ = _result.Append(sr.ReadToEnd()); } return _result.ToString(); } } - private StringBuilder _error; /// /// Gets the command execution error. /// @@ -106,20 +106,18 @@ public string Error { if (_hasError) { - if (_error == null) - { - _error = new StringBuilder(); - } + _error ??= new StringBuilder(); if (ExtendedOutputStream != null && ExtendedOutputStream.Length > 0) { // do not dispose the StreamReader, as it would also dispose the stream var sr = new StreamReader(ExtendedOutputStream, _encoding); - _error.Append(sr.ReadToEnd()); + _ = _error.Append(sr.ReadToEnd()); } return _error.ToString(); } + return string.Empty; } } @@ -134,11 +132,19 @@ public string Error internal SshCommand(ISession session, string commandText, Encoding encoding) { if (session == null) - throw new ArgumentNullException("session"); + { + throw new ArgumentNullException(nameof(session)); + } + if (commandText == null) - throw new ArgumentNullException("commandText"); + { + throw new ArgumentNullException(nameof(commandText)); + } + if (encoding == null) - throw new ArgumentNullException("encoding"); + { + throw new ArgumentNullException(nameof(encoding)); + } _session = session; CommandText = commandText; @@ -154,7 +160,7 @@ internal SshCommand(ISession session, string commandText, Encoding encoding) /// Begins an asynchronous command execution. /// /// - /// An that represents the asynchronous command execution, which could still be pending. + /// An that represents the asynchronous command execution, which could still be pending. /// /// /// @@ -164,8 +170,6 @@ internal SshCommand(ISession session, string commandText, Encoding encoding) /// CommandText property is empty. /// Client is not connected. /// Operation has timed out. - /// Asynchronous operation is already in progress. - /// CommandText property is empty. public IAsyncResult BeginExecute() { return BeginExecute(null, null); @@ -176,15 +180,13 @@ public IAsyncResult BeginExecute() /// /// An optional asynchronous callback, to be called when the command execution is complete. /// - /// An that represents the asynchronous command execution, which could still be pending. + /// An that represents the asynchronous command execution, which could still be pending. /// /// Asynchronous operation is already in progress. /// Invalid operation. /// CommandText property is empty. /// Client is not connected. /// Operation has timed out. - /// Asynchronous operation is already in progress. - /// CommandText property is empty. public IAsyncResult BeginExecute(AsyncCallback callback) { return BeginExecute(callback, null); @@ -203,17 +205,15 @@ public IAsyncResult BeginExecute(AsyncCallback callback) /// CommandText property is empty. /// Client is not connected. /// Operation has timed out. - /// Asynchronous operation is already in progress. - /// CommandText property is empty. public IAsyncResult BeginExecute(AsyncCallback callback, object state) { - // Prevent from executing BeginExecute before calling EndExecute + // Prevent from executing BeginExecute before calling EndExecute if (_asyncResult != null && !_asyncResult.EndCalled) { throw new InvalidOperationException("Asynchronous operation is already in progress."); } - // Create new AsyncResult object + // Create new AsyncResult object _asyncResult = new CommandAsyncResult { AsyncWaitHandle = new ManualResetEvent(false), @@ -221,14 +221,16 @@ public IAsyncResult BeginExecute(AsyncCallback callback, object state) AsyncState = state, }; - // When command re-executed again, create a new channel + // When command re-executed again, create a new channel if (_channel != null) { throw new SshException("Invalid operation."); } if (string.IsNullOrEmpty(CommandText)) + { throw new ArgumentException("CommandText property is empty."); + } var outputStream = OutputStream; if (outputStream != null) @@ -244,7 +246,7 @@ public IAsyncResult BeginExecute(AsyncCallback callback, object state) ExtendedOutputStream = null; } - // Initialize output streams + // Initialize output streams OutputStream = new PipeStream(); ExtendedOutputStream = new PipeStream(); @@ -254,7 +256,7 @@ public IAsyncResult BeginExecute(AsyncCallback callback, object state) _channel = CreateChannel(); _channel.Open(); - _channel.SendExecRequest(CommandText); + _ = _channel.SendExecRequest(CommandText); return _asyncResult; } @@ -266,10 +268,10 @@ public IAsyncResult BeginExecute(AsyncCallback callback, object state) /// An optional asynchronous callback, to be called when the command execution is complete. /// A user-provided object that distinguishes this particular asynchronous read request from other requests. /// - /// An that represents the asynchronous command execution, which could still be pending. + /// An that represents the asynchronous command execution, which could still be pending. /// - /// Client is not connected. - /// Operation has timed out. + /// Client is not connected. + /// Operation has timed out. public IAsyncResult BeginExecute(string commandText, AsyncCallback callback, object state) { CommandText = commandText; @@ -291,13 +293,12 @@ public string EndExecute(IAsyncResult asyncResult) { if (asyncResult == null) { - throw new ArgumentNullException("asyncResult"); + throw new ArgumentNullException(nameof(asyncResult)); } - var commandAsyncResult = asyncResult as CommandAsyncResult; - if (commandAsyncResult == null || _asyncResult != commandAsyncResult) + if (asyncResult is not CommandAsyncResult commandAsyncResult || _asyncResult != commandAsyncResult) { - throw new ArgumentException(string.Format("The {0} object was not returned from the corresponding asynchronous method on this class.", typeof(IAsyncResult).Name)); + throw new ArgumentException(string.Format("The {0} object was not returned from the corresponding asynchronous method on this class.", nameof(IAsyncResult))); } lock (_endExecuteLock) @@ -307,7 +308,7 @@ public string EndExecute(IAsyncResult asyncResult) throw new ArgumentException("EndExecute can only be called once for each asynchronous operation."); } - // wait for operation to complete (or time out) + // wait for operation to complete (or time out) WaitOnHandle(_asyncResult.AsyncWaitHandle); UnsubscribeFromEventsAndDisposeChannel(_channel); @@ -328,15 +329,15 @@ public string EndExecute(IAsyncResult asyncResult) /// /// /// - /// Client is not connected. - /// Operation has timed out. + /// Client is not connected. + /// Operation has timed out. public string Execute() { return EndExecute(BeginExecute(null, null)); } /// - /// Cancels command execution in asynchronous scenarios. + /// Cancels command execution in asynchronous scenarios. /// public void CancelAsync() { @@ -351,9 +352,11 @@ public void CancelAsync() /// Executes the specified command text. /// /// The command text. - /// Command execution result - /// Client is not connected. - /// Operation has timed out. + /// + /// The result of the command execution. + /// + /// Client is not connected. + /// Operation has timed out. public string Execute(string commandText) { CommandText = commandText; @@ -373,54 +376,49 @@ private IChannelSession CreateChannel() private void Session_Disconnected(object sender, EventArgs e) { - // If objected is disposed or being disposed don't handle this event + // If objected is disposed or being disposed don't handle this event if (_isDisposed) + { return; + } _exception = new SshConnectionException("An established connection was aborted by the software in your host machine.", DisconnectReason.ConnectionLost); - _sessionErrorOccuredWaitHandle.Set(); + _ = _sessionErrorOccuredWaitHandle.Set(); } private void Session_ErrorOccured(object sender, ExceptionEventArgs e) { - // If objected is disposed or being disposed don't handle this event + // If objected is disposed or being disposed don't handle this event if (_isDisposed) + { return; + } _exception = e.Exception; - _sessionErrorOccuredWaitHandle.Set(); + _ = _sessionErrorOccuredWaitHandle.Set(); } private void Channel_Closed(object sender, ChannelEventArgs e) { - var outputStream = OutputStream; - if (outputStream != null) - { - outputStream.Flush(); - } - - var extendedOutputStream = ExtendedOutputStream; - if (extendedOutputStream != null) - { - extendedOutputStream.Flush(); - } + OutputStream?.Flush(); + ExtendedOutputStream?.Flush(); _asyncResult.IsCompleted = true; if (_callback != null) { - // Execute callback on different thread + // Execute callback on different thread ThreadAbstraction.ExecuteThread(() => _callback(_asyncResult)); } - ((EventWaitHandle) _asyncResult.AsyncWaitHandle).Set(); + + _ = ((EventWaitHandle) _asyncResult.AsyncWaitHandle).Set(); } private void Channel_RequestReceived(object sender, ChannelRequestEventArgs e) { - var exitStatusInfo = e.Info as ExitStatusRequestInfo; - if (exitStatusInfo != null) + if (e.Info is ExitStatusRequestInfo exitStatusInfo) { ExitStatus = (int) exitStatusInfo.ExitStatus; @@ -501,7 +499,9 @@ private void WaitOnHandle(WaitHandle waitHandle) private void UnsubscribeFromEventsAndDisposeChannel(IChannel channel) { if (channel == null) + { return; + } // unsubscribe from events as we do not want to be signaled should these get fired // during the dispose of the channel @@ -514,27 +514,25 @@ private void UnsubscribeFromEventsAndDisposeChannel(IChannel channel) channel.Dispose(); } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -583,14 +581,13 @@ protected virtual void Dispose(bool disposing) } /// + /// Finalizes an instance of the class. /// Releases unmanaged resources and performs other cleanup operations before the /// is reclaimed by garbage collection. /// ~SshCommand() { - Dispose(false); + Dispose(disposing: false); } - - #endregion } } diff --git a/src/Renci.SshNet/SshMessageFactory.cs b/src/Renci.SshNet/SshMessageFactory.cs index 153024dbf..61952f4b5 100644 --- a/src/Renci.SshNet/SshMessageFactory.cs +++ b/src/Renci.SshNet/SshMessageFactory.cs @@ -9,13 +9,13 @@ namespace Renci.SshNet { - internal class SshMessageFactory + internal sealed class SshMessageFactory { private readonly MessageMetadata[] _enabledMessagesByNumber; private readonly bool[] _activatedMessagesById; internal static readonly MessageMetadata[] AllMessages; - private static readonly IDictionary MessagesByName; + private static readonly Dictionary MessagesByName; /// /// Defines the highest message number that is currently supported. @@ -30,40 +30,40 @@ internal class SshMessageFactory static SshMessageFactory() { AllMessages = new MessageMetadata[] - { - new MessageMetadata(0, "SSH_MSG_KEXINIT", 20), - new MessageMetadata (1, "SSH_MSG_NEWKEYS", 21), - new MessageMetadata (2, "SSH_MSG_REQUEST_FAILURE", 82), - new MessageMetadata (3, "SSH_MSG_CHANNEL_OPEN_FAILURE", 92), - new MessageMetadata (4, "SSH_MSG_CHANNEL_FAILURE", 100), - new MessageMetadata (5, "SSH_MSG_CHANNEL_EXTENDED_DATA", 95), - new MessageMetadata (6, "SSH_MSG_CHANNEL_DATA", 94), - new MessageMetadata (7, "SSH_MSG_CHANNEL_REQUEST", 98), - new MessageMetadata (8, "SSH_MSG_USERAUTH_BANNER", 53), - new MessageMetadata (9, "SSH_MSG_USERAUTH_INFO_RESPONSE", 61), - new MessageMetadata (10, "SSH_MSG_USERAUTH_FAILURE", 51), - new MessageMetadata (11, "SSH_MSG_DEBUG", 4), - new MessageMetadata (12, "SSH_MSG_GLOBAL_REQUEST", 80), - new MessageMetadata (13, "SSH_MSG_CHANNEL_OPEN", 90), - new MessageMetadata (14, "SSH_MSG_CHANNEL_OPEN_CONFIRMATION", 91), - new MessageMetadata (15, "SSH_MSG_USERAUTH_INFO_REQUEST", 60), - new MessageMetadata (16, "SSH_MSG_UNIMPLEMENTED", 3), - new MessageMetadata (17, "SSH_MSG_REQUEST_SUCCESS", 81), - new MessageMetadata (18, "SSH_MSG_CHANNEL_SUCCESS", 99), - new MessageMetadata (19, "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ", 60), - new MessageMetadata (20, "SSH_MSG_DISCONNECT", 1), - new MessageMetadata (21, "SSH_MSG_USERAUTH_SUCCESS", 52), - new MessageMetadata (22, "SSH_MSG_USERAUTH_PK_OK", 60), - new MessageMetadata (23, "SSH_MSG_IGNORE", 2), - new MessageMetadata (24, "SSH_MSG_CHANNEL_WINDOW_ADJUST", 93), - new MessageMetadata (25, "SSH_MSG_CHANNEL_EOF", 96), - new MessageMetadata (26, "SSH_MSG_CHANNEL_CLOSE", 97), - new MessageMetadata (27, "SSH_MSG_SERVICE_ACCEPT", 6), - new MessageMetadata (28, "SSH_MSG_KEX_DH_GEX_GROUP", 31), - new MessageMetadata (29, "SSH_MSG_KEXDH_REPLY", 31), - new MessageMetadata (30, "SSH_MSG_KEX_DH_GEX_REPLY", 33), - new MessageMetadata (31, "SSH_MSG_KEX_ECDH_REPLY", 31) - }; + { + new MessageMetadata(0, "SSH_MSG_KEXINIT", 20), + new MessageMetadata(1, "SSH_MSG_NEWKEYS", 21), + new MessageMetadata(2, "SSH_MSG_REQUEST_FAILURE", 82), + new MessageMetadata(3, "SSH_MSG_CHANNEL_OPEN_FAILURE", 92), + new MessageMetadata(4, "SSH_MSG_CHANNEL_FAILURE", 100), + new MessageMetadata(5, "SSH_MSG_CHANNEL_EXTENDED_DATA", 95), + new MessageMetadata(6, "SSH_MSG_CHANNEL_DATA", 94), + new MessageMetadata(7, "SSH_MSG_CHANNEL_REQUEST", 98), + new MessageMetadata(8, "SSH_MSG_USERAUTH_BANNER", 53), + new MessageMetadata(9, "SSH_MSG_USERAUTH_INFO_RESPONSE", 61), + new MessageMetadata(10, "SSH_MSG_USERAUTH_FAILURE", 51), + new MessageMetadata(11, "SSH_MSG_DEBUG", 4), + new MessageMetadata(12, "SSH_MSG_GLOBAL_REQUEST", 80), + new MessageMetadata(13, "SSH_MSG_CHANNEL_OPEN", 90), + new MessageMetadata(14, "SSH_MSG_CHANNEL_OPEN_CONFIRMATION", 91), + new MessageMetadata(15, "SSH_MSG_USERAUTH_INFO_REQUEST", 60), + new MessageMetadata(16, "SSH_MSG_UNIMPLEMENTED", 3), + new MessageMetadata(17, "SSH_MSG_REQUEST_SUCCESS", 81), + new MessageMetadata(18, "SSH_MSG_CHANNEL_SUCCESS", 99), + new MessageMetadata(19, "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ", 60), + new MessageMetadata(20, "SSH_MSG_DISCONNECT", 1), + new MessageMetadata(21, "SSH_MSG_USERAUTH_SUCCESS", 52), + new MessageMetadata(22, "SSH_MSG_USERAUTH_PK_OK", 60), + new MessageMetadata(23, "SSH_MSG_IGNORE", 2), + new MessageMetadata(24, "SSH_MSG_CHANNEL_WINDOW_ADJUST", 93), + new MessageMetadata(25, "SSH_MSG_CHANNEL_EOF", 96), + new MessageMetadata(26, "SSH_MSG_CHANNEL_CLOSE", 97), + new MessageMetadata(27, "SSH_MSG_SERVICE_ACCEPT", 6), + new MessageMetadata(28, "SSH_MSG_KEX_DH_GEX_GROUP", 31), + new MessageMetadata(29, "SSH_MSG_KEXDH_REPLY", 31), + new MessageMetadata(30, "SSH_MSG_KEX_DH_GEX_REPLY", 33), + new MessageMetadata(31, "SSH_MSG_KEX_ECDH_REPLY", 31) + }; MessagesByName = new Dictionary(AllMessages.Length); for (var i = 0; i < AllMessages.Length; i++) @@ -73,6 +73,9 @@ static SshMessageFactory() } } + /// + /// Initializes a new instance of the class. + /// public SshMessageFactory() { _activatedMessagesById = new bool[TotalMessageCount]; @@ -129,7 +132,7 @@ public void DisableNonKeyExchangeMessages() var messageMetadata = AllMessages[i]; var messageNumber = messageMetadata.Number; - if ((messageNumber > 2 && messageNumber < 20) || messageNumber > 30) + if (messageNumber is (> 2 and < 20) or > 30) { _enabledMessagesByNumber[messageNumber] = null; } @@ -143,15 +146,18 @@ public void EnableActivatedMessages() var messageMetadata = AllMessages[i]; if (!_activatedMessagesById[messageMetadata.Id]) + { continue; + } var enabledMessageMetadata = _enabledMessagesByNumber[messageMetadata.Number]; if (enabledMessageMetadata != null && enabledMessageMetadata != messageMetadata) { throw CreateMessageTypeAlreadyEnabledForOtherMessageException(messageMetadata.Number, - messageMetadata.Name, - enabledMessageMetadata.Name); + messageMetadata.Name, + enabledMessageMetadata.Name); } + _enabledMessagesByNumber[messageMetadata.Number] = messageMetadata; } } @@ -159,13 +165,13 @@ public void EnableActivatedMessages() public void EnableAndActivateMessage(string messageName) { if (messageName == null) - throw new ArgumentNullException("messageName"); + { + throw new ArgumentNullException(nameof(messageName)); + } lock (this) { - MessageMetadata messageMetadata; - - if (!MessagesByName.TryGetValue(messageName, out messageMetadata)) + if (!MessagesByName.TryGetValue(messageName, out var messageMetadata)) { throw CreateMessageNotSupportedException(messageName); } @@ -186,13 +192,13 @@ public void EnableAndActivateMessage(string messageName) public void DisableAndDeactivateMessage(string messageName) { if (messageName == null) - throw new ArgumentNullException("messageName"); + { + throw new ArgumentNullException(nameof(messageName)); + } lock (this) { - MessageMetadata messageMetadata; - - if (!MessagesByName.TryGetValue(messageName, out messageMetadata)) + if (!MessagesByName.TryGetValue(messageName, out var messageMetadata)) { throw CreateMessageNotSupportedException(messageName); } @@ -201,8 +207,8 @@ public void DisableAndDeactivateMessage(string messageName) if (enabledMessageMetadata != null && enabledMessageMetadata != messageMetadata) { throw CreateMessageTypeAlreadyEnabledForOtherMessageException(messageMetadata.Number, - messageMetadata.Name, - enabledMessageMetadata.Name); + messageMetadata.Name, + enabledMessageMetadata.Name); } _activatedMessagesById[messageMetadata.Id] = false; @@ -245,7 +251,8 @@ protected MessageMetadata(byte id, string name, byte number) public abstract Message Create(); } - internal class MessageMetadata : MessageMetadata where T : Message, new() + internal sealed class MessageMetadata : MessageMetadata + where T : Message, new() { public MessageMetadata(byte id, string name, byte number) : base(id, name, number) diff --git a/src/Renci.SshNet/SubsystemSession.cs b/src/Renci.SshNet/SubsystemSession.cs index 943a2db9e..922312e37 100644 --- a/src/Renci.SshNet/SubsystemSession.cs +++ b/src/Renci.SshNet/SubsystemSession.cs @@ -1,6 +1,7 @@ 锘縰sing System; using System.Globalization; using System.Threading; + using Renci.SshNet.Abstractions; using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -8,7 +9,7 @@ namespace Renci.SshNet { /// - /// Base class for SSH subsystem implementations + /// Base class for SSH subsystem implementations. /// internal abstract class SubsystemSession : ISubsystemSession { @@ -18,13 +19,14 @@ internal abstract class SubsystemSession : ISubsystemSession /// private const int SystemWaitHandleCount = 3; - private ISession _session; private readonly string _subsystemName; + private ISession _session; private IChannelSession _channel; private Exception _exception; private EventWaitHandle _errorOccuredWaitHandle = new ManualResetEvent(false); private EventWaitHandle _sessionDisconnectedWaitHandle = new ManualResetEvent(false); private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(false); + private bool _isDisposed; /// /// Gets or set the number of seconds to wait for an operation to complete. @@ -72,7 +74,7 @@ public bool IsOpen } /// - /// Initializes a new instance of the SubsystemSession class. + /// Initializes a new instance of the class. /// /// The session. /// Name of the subsystem. @@ -81,9 +83,14 @@ public bool IsOpen protected SubsystemSession(ISession session, string subsystemName, int operationTimeout) { if (session == null) - throw new ArgumentNullException("session"); + { + throw new ArgumentNullException(nameof(session)); + } + if (subsystemName == null) - throw new ArgumentNullException("subsystemName"); + { + throw new ArgumentNullException(nameof(subsystemName)); + } _session = session; _subsystemName = subsystemName; @@ -101,13 +108,15 @@ public void Connect() EnsureNotDisposed(); if (IsOpen) + { throw new InvalidOperationException("The session is already connected."); + } // reset waithandles in case we're reconnecting - _errorOccuredWaitHandle.Reset(); - _sessionDisconnectedWaitHandle.Reset(); - _sessionDisconnectedWaitHandle.Reset(); - _channelClosedWaitHandle.Reset(); + _ = _errorOccuredWaitHandle.Reset(); + _ = _sessionDisconnectedWaitHandle.Reset(); + _ = _sessionDisconnectedWaitHandle.Reset(); + _ = _channelClosedWaitHandle.Reset(); _session.ErrorOccured += Session_ErrorOccured; _session.Disconnected += Session_Disconnected; @@ -122,6 +131,7 @@ public void Connect() { // close channel session Disconnect(); + // signal subsystem failure throw new SshException(string.Format(CultureInfo.InvariantCulture, "Subsystem '{0}' could not be executed.", @@ -182,9 +192,7 @@ protected void RaiseError(Exception error) DiagnosticAbstraction.Log("Raised exception: " + error); - var errorOccuredWaitHandle = _errorOccuredWaitHandle; - if (errorOccuredWaitHandle != null) - errorOccuredWaitHandle.Set(); + _ = _errorOccuredWaitHandle?.Set(); SignalErrorOccurred(error); } @@ -208,9 +216,7 @@ private void Channel_Exception(object sender, ExceptionEventArgs e) private void Channel_Closed(object sender, ChannelEventArgs e) { - var channelClosedWaitHandle = _channelClosedWaitHandle; - if (channelClosedWaitHandle != null) - channelClosedWaitHandle.Set(); + _ = _channelClosedWaitHandle?.Set(); } /// @@ -429,9 +435,7 @@ public WaitHandle[] CreateWaitHandleArray(params WaitHandle[] waitHandles) private void Session_Disconnected(object sender, EventArgs e) { - var sessionDisconnectedWaitHandle = _sessionDisconnectedWaitHandle; - if (sessionDisconnectedWaitHandle != null) - sessionDisconnectedWaitHandle.Set(); + _ = _sessionDisconnectedWaitHandle?.Set(); SignalDisconnected(); } @@ -443,26 +447,20 @@ private void Session_ErrorOccured(object sender, ExceptionEventArgs e) private void SignalErrorOccurred(Exception error) { - var errorOccurred = ErrorOccurred; - if (errorOccurred != null) - { - errorOccurred(this, new ExceptionEventArgs(error)); - } + ErrorOccurred?.Invoke(this, new ExceptionEventArgs(error)); } private void SignalDisconnected() { - var disconnected = Disconnected; - if (disconnected != null) - { - disconnected(this, new EventArgs()); - } + Disconnected?.Invoke(this, EventArgs.Empty); } private void EnsureSessionIsOpen() { if (!IsOpen) + { throw new InvalidOperationException("The session is not open."); + } } /// @@ -475,33 +473,33 @@ private void EnsureSessionIsOpen() private void UnsubscribeFromSessionEvents(ISession session) { if (session == null) + { return; + } session.Disconnected -= Session_Disconnected; session.ErrorOccured -= Session_ErrorOccured; } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -539,15 +537,15 @@ protected virtual void Dispose(bool disposing) /// ~SubsystemSession() { - Dispose(false); + Dispose(disposing: false); } private void EnsureNotDisposed() { if (_isDisposed) + { throw new ObjectDisposedException(GetType().FullName); + } } - - #endregion } } diff --git a/stylecop.json b/stylecop.json new file mode 100644 index 000000000..ff7c9dbfb --- /dev/null +++ b/stylecop.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "documentationRules": { + "xmlHeader": false, + "documentInternalElements": false + }, + "layoutRules": { + "newlineAtEndOfFile": "require" + }, + "indentation": { + "indentationSize": 4, + "tabSize": 4, + "useTabs": false + }, + "namingRules": { + "allowCommonHungarianPrefixes": false + }, + "orderingRules": { + "systemUsingDirectivesFirst": true, + "usingDirectivesPlacement": "outsideNamespace", + "blankLinesBetweenUsingGroups": "require" + } + } +} diff --git a/test/.editorconfig b/test/.editorconfig new file mode 100644 index 000000000..ff0eebcf3 --- /dev/null +++ b/test/.editorconfig @@ -0,0 +1,111 @@ +锘縖*.cs] + +# Sonar rules + +# S1854: Unused assignments should be removed +# https://rules.sonarsource.com/csharp/RSPEC-1854 +# +# We sometimes increment the value of a variable on each use to make the code future-proof. +# +# For example: +# int idSequence = 0; +# var train1 = new Train { Id = ++idSequence }; +# var train2 = new Train { Id = ++idSequence }; +# +# The increment of 'idSequence' in the last line will cause this diagnostic to be reported. We prefer to keep the increment to make +# sure the value of the variable will remain correct when we introduce a 'train3'. +# +# For unit tests, we do not care about this diagnostic. +dotnet_diagnostic.S1854.severity = none + +#### StyleCop rules #### + +# SA1202: Elements must be ordered by access +dotnet_diagnostic.SA1202.severity = none + +# SA1600: Elements must be documented +# +# For unit test projects, we do not care about documentation. +dotnet_diagnostic.SA1600.severity = none + +# SA1601: Partial elements should be documented +# +# For unit test projects, we do not care about documentation. +dotnet_diagnostic.SA1601.severity = none + +# SA1602: Enumeration items must be documented +# +# For unit test projects, we do not care about documentation. +dotnet_diagnostic.SA1602.severity = none + +# SA1604: Element documentation should have summary +# +# TODO: Remove this when code has been updated! +dotnet_diagnostic.SA1604.severity = none + +# SA1606: Element documentation should have summary text +# +# TODO: Remove this when code has been updated! +dotnet_diagnostic.SA1606.severity = none + +# SA1607: Partial element documentation should have summary text +# +# For unit test projects, we do not care about documentation. +dotnet_diagnostic.SA1607.severity = none + +# SA1611: Element parameters must be documented +# +# For unit test projects, we do not care about documentation. +dotnet_diagnostic.SA1611.severity = none + +# SA1614: Element parameter documentation must have text +# +# TODO: Remove this when code has been updated! +dotnet_diagnostic.SA1614.severity = none + +# SA1615: Element return value must be documented +# +# For unit test projects, we do not care about documentation. +dotnet_diagnostic.SA1615.severity = none + +# SA1616: Element return value documentation should have text +# +# TODO: Remove this when code has been updated! +dotnet_diagnostic.SA1616.severity = none + +# SA1623: Property summary documentation must match accessors +# +# TODO: Remove this when code has been updated! +dotnet_diagnostic.SA1623.severity = none + +# SA1629: Documentation text must end with a period +# +# For unit test projects, we do not care about documentation. +dotnet_diagnostic.SA1629.severity = none + +#### .NET Compiler Platform analysers rules #### + +# CA1001: Types that own disposable fields should be disposable +# +# We do not care about this for unit tests. +dotnet_diagnostic.CA1001.severity = none + +# CA1707: Identifiers should not contain underscores +# +# We frequently use underscores in test classes and test methods. +dotnet_diagnostic.CA1707.severity = none + +# CA1711: Identifiers should not have incorrect suffix +# +# We frequently define test classes and test method with a suffix that refers to a type. +dotnet_diagnostic.CA1711.severity = none + +# CA1720: Identifiers should not contain type names +# +# We do not care about this for unit tests. +dotnet_diagnostic.CA1720.severity = none + +# CA5394: Do not use insecure randomness +# +# We do not care about this for unit tests. +dotnet_diagnostic.CA5394.severity = none diff --git a/test/Directory.Build.props b/test/Directory.Build.props new file mode 100644 index 000000000..1e96f3c4d --- /dev/null +++ b/test/Directory.Build.props @@ -0,0 +1,16 @@ + + + + + + $(NoWarn);CS1591 + + From c04cdbcb972804efd8bd0b06dd32d85304fa5ef1 Mon Sep 17 00:00:00 2001 From: Gert Driesen Date: Mon, 29 May 2023 17:16:08 +0200 Subject: [PATCH 21/96] Round 2 of analyzer fixes and general cleanup. (#1132) --- .editorconfig_soon => .editorconfig | 11 + Directory.Build.props | 2 - src/Renci.SshNet.Tests/.editorconfig | 32 ++ .../Classes/BaseClientTestBase.cs | 12 +- ...Test_Connect_OnConnectedThrowsException.cs | 30 +- ...Connected_KeepAliveInterval_NegativeOne.cs | 39 ++- ...nected_KeepAliveInterval_NotNegativeOne.cs | 30 +- ...Connected_KeepAlivesNotSentConcurrently.cs | 22 +- .../BaseClientTest_Disconnected_Connect.cs | 30 +- ...nected_KeepAliveInterval_NotNegativeOne.cs | 30 +- ...nected_KeepAliveInterval_NotNegativeOne.cs | 20 +- .../Channels/ChannelDirectTcpipTest.cs | 128 +++---- ...pose_SessionIsConnectedAndChannelIsOpen.cs | 130 ++++--- ...pose_SessionIsConnectedAndChannelIsOpen.cs | 113 +++--- .../ChannelSessionTest_Dispose_Disposed.cs | 5 +- .../Classes/Channels/ChannelStub.cs | 22 +- ...IsConnectedAndChannelIsOpen_EofReceived.cs | 8 +- ...nChannelCloseReceived_OnClose_Exception.cs | 3 +- ...ionChannelDataReceived_OnData_Exception.cs | 5 +- ...ssionChannelEofReceived_OnEof_Exception.cs | 5 +- ...edDataReceived_OnExtendedData_Exception.cs | 5 +- ...nnelFailureReceived_OnFailure_Exception.cs | 5 +- ...nnelRequestReceived_OnRequest_Exception.cs | 9 +- ...nnelSuccessReceived_OnSuccess_Exception.cs | 5 +- ...AdjustReceived_OnWindowAdjust_Exception.cs | 5 +- ...onDisconnected_OnDisconnected_Exception.cs | 5 +- ...cted_SessionIsConnectedAndChannelIsOpen.cs | 8 +- .../Classes/Channels/ClientChannelStub.cs | 27 +- .../Classes/CipherInfoTest.cs | 9 +- ...achedFollowedBySuccessInAlternateBranch.cs | 3 +- ...stponePartialAccessAuthenticationMethod.cs | 106 +++--- .../Classes/CommandAsyncResultTest.cs | 2 +- .../Classes/Common/AsyncResultTest.cs | 42 ++- ...thenticationPasswordChangeEventArgsTest.cs | 6 +- .../AuthenticationPromptEventArgsTest.cs | 8 +- .../Common/AuthenticationPromptTest.cs | 21 +- .../Classes/Common/BigIntegerTest.cs | 245 +++++++------ .../Common/ChannelOpenFailedEventArgsTest.cs | 4 +- .../Classes/Common/CountdownEventTest.cs | 73 ++-- .../ExtensionsTest_IsEqualTo_ByteArray.cs | 8 +- .../Classes/Common/ExtensionsTest_Pad.cs | 9 +- .../Common/ExtensionsTest_ToBigInteger2.cs | 6 +- .../Classes/Common/PacketDumpTest.cs | 4 +- .../Classes/Common/PipeStreamTest.cs | 18 +- .../Common/PipeStream_Close_BlockingRead.cs | 2 +- .../Common/PipeStream_Close_BlockingWrite.cs | 2 +- ...ipeStream_Flush_BytesRemainingAfterRead.cs | 4 +- ...eStream_Flush_NoBytesRemainingAfterRead.cs | 2 +- .../Common/PortForwardEventArgsTest.cs | 6 +- ...thTest_CreateAbsoluteOrRelativeFilePath.cs | 4 +- .../Common/PosixPathTest_GetDirectoryName.cs | 2 +- .../Common/PosixPathTest_GetFileName.cs | 2 +- .../Classes/Common/SemaphoreLightTest.cs | 11 +- .../Common/SshConnectionExceptionTest.cs | 24 +- .../Classes/Compression/ZlibOpenSshTest.cs | 16 +- .../Classes/Compression/ZlibStreamTest.cs | 21 +- .../Connection/DirectConnectorTestBase.cs | 2 +- ...rTest_Connect_ConnectionRefusedByServer.cs | 22 +- ...nnectorTest_Connect_ConnectionSucceeded.cs | 28 +- ...ctConnectorTest_Connect_HostNameInvalid.cs | 8 +- ...rTest_Connect_TimeoutConnectingToServer.cs | 25 +- ...orTest_Connect_ConnectionToProxyRefused.cs | 22 +- ...yClosesConnectionBeforeStatusLineIsSent.cs | 25 +- ...pConnectorTest_Connect_ProxyHostInvalid.cs | 2 +- ...nectorTest_Connect_ProxyPasswordIsEmpty.cs | 41 +-- ...nnectorTest_Connect_ProxyPasswordIsNull.cs | 28 +- ...oxyResponseDoesNotContainHttpStatusLine.cs | 35 +- ...seStatusIs200_ExtraTextBeforeStatusLine.cs | 39 ++- ...xyResponseStatusIs200_HeadersAndContent.cs | 39 ++- ...ct_ProxyResponseStatusIs200_OnlyHeaders.cs | 24 +- ...est_Connect_ProxyResponseStatusIsNot200.cs | 35 +- ...nectorTest_Connect_ProxyUserNameIsEmpty.cs | 44 ++- ...nnect_ProxyUserNameIsNotNullAndNotEmpty.cs | 34 +- ...nnectorTest_Connect_ProxyUserNameIsNull.cs | 38 ++- ...orTest_Connect_TimeoutConnectingToProxy.cs | 30 +- ...rTest_Connect_TimeoutReadingHttpContent.cs | 50 ++- ...orTest_Connect_TimeoutReadingStatusLine.cs | 40 ++- ...entificationOnlyContainsProtocolVersion.cs | 18 +- ...rminatedByLineFeedWithoutCarriageReturn.cs | 24 +- ...Test_TimeoutReadingIdentificationString.cs | 17 +- .../Connection/Socks4ConnectorTestBase.cs | 7 +- ...rTest_Connect_ConnectionRejectedByProxy.cs | 48 +-- ...nnectorTest_Connect_ConnectionSucceeded.cs | 34 +- ...orTest_Connect_ConnectionToProxyRefused.cs | 22 +- ...orTest_Connect_TimeoutConnectingToProxy.cs | 13 +- ...onnect_TimeoutReadingDestinationAddress.cs | 36 +- ...torTest_Connect_TimeoutReadingReplyCode.cs | 34 +- ...Test_Connect_TimeoutReadingReplyVersion.cs | 19 +- .../Connection/Socks5ConnectorTestBase.cs | 7 +- ...orTest_Connect_ConnectionToProxyRefused.cs | 23 +- ...ct_NoAuthentication_ConnectionSucceeded.cs | 17 +- ...Connect_ProxySocksVersionIsNotSupported.cs | 34 +- ...orTest_Connect_TimeoutConnectingToProxy.cs | 25 +- ...wordAuthentication_AuthenticationFailed.cs | 23 +- ...swordAuthentication_ConnectionSucceeded.cs | 32 +- ...entication_PasswordExceedsMaximumLength.cs | 21 +- ...entication_UserNameExceedsMaximumLength.cs | 58 ++-- .../Connection/SshIdentificationTest.cs | 8 +- .../Classes/ConnectionInfoTest.cs | 150 ++++++-- ...ortDynamicTest_Dispose_PortNeverStarted.cs | 4 +- ...est_Dispose_PortStarted_ChannelNotBound.cs | 4 +- ...t_Started_SocketSendShutdownImmediately.cs | 33 +- ...cTest_Started_SocketVersionNotSupported.cs | 4 +- ...icTest_Stop_PortStarted_ChannelNotBound.cs | 20 +- .../Classes/ForwardedPortLocalTest.cs | 191 ++++++----- ...dedPortLocalTest_Start_PortNeverStarted.cs | 30 +- ...orwardedPortLocalTest_Start_PortStarted.cs | 36 +- ...orwardedPortLocalTest_Start_PortStopped.cs | 40 ++- .../Classes/ForwardedPortRemoteTest.cs | 34 +- ...ortRemoteTest_Start_SessionNotConnected.cs | 30 +- ...rwardedPortRemoteTest_Start_SessionNull.cs | 7 +- .../Classes/MessageEventArgsTest.cs | 6 +- .../Authentication/FailureMessageTest.cs | 10 +- .../RequestMessagePublicKeyTest.cs | 41 ++- .../Connection/ChannelCloseMessageTest.cs | 5 +- .../Connection/ChannelEofMessageTest.cs | 5 +- .../ChannelExtendedDataMessageTest.cs | 8 +- .../Connection/ChannelFailureMessageTest.cs | 10 +- .../Messages/Connection/ChannelMessageTest.cs | 13 +- .../ChannelOpen/ChannelOpenMessageTest.cs | 6 +- .../ChannelOpenConfirmationMessageTest.cs | 10 +- .../ChannelOpenFailureMessageTest.cs | 12 +- .../Connection/ChannelOpenInfoTest.cs | 11 +- .../EndOfWriteRequestInfoTest.cs | 14 +- .../KeepAliveRequestInfoTest.cs | 13 +- .../ChannelRequest/PseudoTerminalInfoTest.cs | 6 +- .../Connection/ChannelSuccessMessageTest.cs | 10 +- .../ChannelWindowAdjustMessageTest.cs | 6 +- .../Messages/Connection/RequestInfoTest.cs | 11 +- .../Connection/RequestSuccessMessageTest.cs | 10 +- .../Classes/Messages/MessageAttributeTest.cs | 20 +- .../Classes/Messages/MessageTest.cs | 12 +- .../Transport/DisconnectMessageTest.cs | 14 +- .../KeyExchangeDhGroupExchangeGroupTest.cs | 8 +- .../KeyExchangeDhGroupExchangeReplyBuilder.cs | 3 + .../KeyExchangeDhGroupExchangeRequestTest.cs | 5 +- .../KeyExchangeDhReplyMessageTest.cs | 8 +- .../Messages/Transport/NewKeysMessageTest.cs | 8 +- .../Transport/ServiceAcceptMessageTest.cs | 8 +- .../Transport/ServiceRequestMessageTest.cs | 10 +- .../Transport/UnimplementedMessageTest.cs | 3 +- .../Classes/NetConfClientTestBase.cs | 4 +- ...st_Connect_NetConfSessionConnectFailure.cs | 44 +-- .../NetConfClientTest_Dispose_Connected.cs | 71 ++-- .../NetConfClientTest_Dispose_Disconnected.cs | 69 ++-- .../NetConfClientTest_Dispose_Disposed.cs | 61 ++-- .../NetConfClientTest_Finalize_Connected.cs | 36 +- .../Classes/PasswordConnectionInfoTest.cs | 20 +- .../Classes/PrivateKeyFileTest.cs | 78 ++--- .../Classes/ScpClientTest.cs | 174 +++++----- ...rectoryInfo_SendExecRequestReturnsFalse.cs | 20 +- ...AndFileInfo_SendExecRequestReturnsFalse.cs | 20 +- ...thAndStream_SendExecRequestReturnsFalse.cs | 57 ++-- ...InfoAndPath_SendExecRequestReturnsFalse.cs | 20 +- ...InfoAndPath_SendExecRequestReturnsFalse.cs | 20 +- ...ientTest_Upload_FileInfoAndPath_Success.cs | 95 +++--- ...reamAndPath_SendExecRequestReturnsFalse.cs | 60 ++-- .../Ciphers/BlowfishCipherTest.cs | 34 +- .../Ciphers/TripleDesCipherTest.cs | 11 +- .../Cryptography/DsaDigitalSignatureTest.cs | 18 +- .../Cryptography/SymmetricCipherTest.cs | 32 +- ...yExchangeDiffieHellmanGroup14Sha256Test.cs | 4 +- .../Classes/Security/KeyExchangeTest.cs | 4 +- .../Classes/SessionTest.HttpProxy.cs | 36 -- src/Renci.SshNet.Tests/Classes/SessionTest.cs | 26 +- .../Classes/SessionTestBase.cs | 12 +- .../SessionTest_ConnectToServerFails.cs | 28 +- .../Classes/SessionTest_Connected.cs | 10 +- .../Classes/SessionTest_ConnectedBase.cs | 73 ++-- .../SessionTest_Connected_ConnectionReset.cs | 11 +- .../SessionTest_Connected_Disconnect.cs | 12 +- ...Connected_ServerAndClientDisconnectRace.cs | 73 ++-- ...sionTest_Connected_ServerSendsBadPacket.cs | 14 +- ..._Connected_ServerSendsDisconnectMessage.cs | 14 +- ...endsDisconnectMessageAndShutsDownSocket.cs | 15 +- ...ected_ServerSendsUnsupportedMessageType.cs | 16 +- ...utsDownSendAfterSendingIncompletePacket.cs | 13 +- ...ionTest_Connected_ServerShutsDownSocket.cs | 11 +- .../Classes/SessionTest_NotConnected.cs | 23 +- ...est_SocketConnected_BadPacketAndDispose.cs | 44 ++- .../Sftp/Requests/SftpRmDirRequestTest.cs | 7 +- .../Sftp/Requests/SftpUnblockRequestTest.cs | 5 +- .../ExtendedReplies/StatVfsReplyInfoTest.cs | 4 +- .../SftpExtendedReplyResponseTest.cs | 10 +- .../Classes/Sftp/SftpFileReaderTestBase.cs | 7 +- ...st_DisposeShouldUnblockReadAndReadAhead.cs | 104 +++--- ...ReaderTest_Dispose_SftpSessionIsNotOpen.cs | 96 +++--- ...SessionIsOpen_BeginCloseThrowsException.cs | 101 +++--- ...tpSessionIsOpen_EndCloseThrowsException.cs | 105 +++--- ...iousChunkIsIncompleteAndEofIsNotReached.cs | 211 ++++++------ ...reviousChunkIsIncompleteAndEofIsReached.cs | 119 ++++--- ...vokeException_PreventsFurtherReadAheads.cs | 131 +++---- ...leReaderTest_ReadBackBeginReadException.cs | 7 +- ...leReaderTest_ReadBackEndInvokeException.cs | 7 +- ...mTest_CanWrite_Disposed_FileAccessWrite.cs | 25 +- .../Sftp/SftpFileStreamTest_Close_Closed.cs | 32 +- .../Sftp/SftpFileStreamTest_Close_Disposed.cs | 25 +- .../SftpFileStreamTest_Close_SessionOpen.cs | 32 +- ...est_Ctor_FileModeAppend_FileAccessWrite.cs | 47 +-- ...t_Ctor_FileModeCreateNew_FileAccessRead.cs | 6 +- ...r_FileModeCreateNew_FileAccessReadWrite.cs | 46 ++- ...Test_Ctor_FileModeCreate_FileAccessRead.cs | 6 +- ...te_FileAccessReadWrite_FileDoesNotExist.cs | 52 +-- ...st_Ctor_FileModeTruncate_FileAccessRead.cs | 4 +- ...or_FileModeTruncate_FileAccessReadWrite.cs | 49 ++- .../Sftp/SftpFileStreamTest_Dispose_Closed.cs | 28 +- ...tpFileStreamTest_Dispose_SessionNotOpen.cs | 28 +- .../SftpFileStreamTest_Dispose_SessionOpen.cs | 27 +- ...SftpFileStreamTest_Finalize_SessionOpen.cs | 50 ++- ...ReadMode_DataInBuffer_NotReadFromBuffer.cs | 65 ++-- ...sh_ReadMode_DataInBuffer_ReadFromBuffer.cs | 65 ++-- ...treamTest_Flush_ReadMode_NoDataInBuffer.cs | 65 ++-- ...StreamTest_Flush_WriteMode_DataInBuffer.cs | 100 +++--- ...penAsync_FileModeAppend_FileAccessWrite.cs | 45 ++- ...nAsync_FileModeCreateNew_FileAccessRead.cs | 6 +- ...Async_FileModeCreateNew_FileAccessWrite.cs | 39 ++- ...OpenAsync_FileModeCreate_FileAccessRead.cs | 6 +- ...te_FileAccessReadWrite_FileDoesNotExist.cs | 41 ++- ...leModeCreate_FileAccessWrite_FileExists.cs | 41 ++- ...ileModeOpenOrCreate_FileAccessReadWrite.cs | 41 ++- ...nAsync_FileModeOpen_FileAccessReadWrite.cs | 41 ++- ...enAsync_FileModeTruncate_FileAccessRead.cs | 7 +- ...tGreatherThanTwoTimesTheWriteBufferSize.cs | 4 +- .../Classes/Sftp/SftpHandleResponseBuilder.cs | 13 +- .../Classes/Sftp/SftpNameResponseBuilder.cs | 5 +- .../Classes/Sftp/SftpOpenRequestBuilder.cs | 9 +- .../Classes/Sftp/SftpStatVfsRequestBuilder.cs | 1 + .../Sftp/SftpStatVfsResponseBuilder.cs | 8 + .../Sftp/SftpVersionResponseBuilder.cs | 2 +- .../Classes/SftpClientTest.CreateDirectory.cs | 4 +- .../Classes/SftpClientTest.DeleteDirectory.cs | 4 +- .../Classes/SftpClientTest.Download.cs | 4 +- .../Classes/SftpClientTest.Upload.cs | 102 +++--- .../Classes/SftpClientTest.cs | 15 +- .../Classes/SftpClientTestBase.cs | 8 +- ...tTest_Connect_SftpSessionConnectFailure.cs | 51 +-- .../SftpClientTest_Dispose_Connected.cs | 68 ++-- .../SftpClientTest_Dispose_Disconnected.cs | 68 ++-- .../SftpClientTest_Dispose_Disposed.cs | 68 ++-- .../SftpClientTest_Finalize_Connected.cs | 33 +- ...ferEmptyAndWriteMoreBytesThanBufferSize.cs | 62 ++-- ...Write_WriteBufferEmptyAndWriteZeroBytes.cs | 50 +-- .../Classes/SshClientTest.cs | 8 +- ...AndBufferSizeAndTerminalModes_Connected.cs | 20 +- ...ndWidthAndHeightAndBufferSize_Connected.cs | 63 ++-- ...entTest_Disconnect_ForwardedPortStarted.cs | 22 +- .../SshClientTest_Dispose_Connected.cs | 28 +- .../SshClientTest_Dispose_Disconnected.cs | 28 +- .../Classes/SshClientTest_Dispose_Disposed.cs | 28 +- ...ClientTest_Dispose_ForwardedPortStarted.cs | 22 +- .../Classes/SshCommandTest.cs | 8 +- ...EndExecute_AsyncResultFromOtherInstance.cs | 32 +- .../Classes/SubsystemSessionStub.cs | 8 +- .../SubsystemSession_Connect_Disconnected.cs | 47 ++- .../SubsystemSession_Connect_Disposed.cs | 24 +- ...SubsystemSession_Connect_NeverConnected.cs | 7 +- .../SubsystemSession_Disconnect_Connected.cs | 19 +- .../SubsystemSession_Disconnect_Disposed.cs | 26 +- ...systemSession_Disconnect_NeverConnected.cs | 11 +- .../SubsystemSession_Dispose_Connected.cs | 18 +- .../SubsystemSession_Dispose_Disconnected.cs | 19 +- .../SubsystemSession_Dispose_Disposed.cs | 19 +- ...SubsystemSession_Dispose_NeverConnected.cs | 13 +- ...stemSession_OnChannelException_Disposed.cs | 19 +- ...Session_OnSessionDisconnected_Connected.cs | 33 +- ...mSession_OnSessionDisconnected_Disposed.cs | 26 +- .../SubsystemSession_SendData_Disconnected.cs | 7 +- src/Renci.SshNet.Tests/Common/ArrayBuilder.cs | 5 +- .../Common/AsyncSocketListener.cs | 35 +- .../Common/DictionaryAssert.cs | 11 +- src/Renci.SshNet.Tests/Common/Extensions.cs | 6 +- .../Common/HttpProxyStub.cs | 18 +- .../Common/SftpFileAttributesBuilder.cs | 20 +- .../Renci.SshNet.Tests.csproj | 4 - src/Renci.SshNet/.editorconfig | 7 + .../Abstractions/SocketAbstraction.cs | 4 + .../Abstractions/SocketExtensions.cs | 2 +- .../Abstractions/ThreadAbstraction.cs | 4 +- src/Renci.SshNet/BaseClient.cs | 8 +- .../Channels/ChannelDirectTcpip.cs | 6 +- .../Channels/ChannelForwardedTcpip.cs | 4 +- src/Renci.SshNet/Channels/ClientChannel.cs | 2 +- src/Renci.SshNet/ClientAuthentication.cs | 6 +- src/Renci.SshNet/Common/AsyncResult.cs | 2 +- src/Renci.SshNet/Common/BigInteger.cs | 107 ++++-- src/Renci.SshNet/Common/Extensions.cs | 18 +- src/Renci.SshNet/Common/ObjectIdentifier.cs | 2 +- src/Renci.SshNet/Common/PacketDump.cs | 2 +- src/Renci.SshNet/Common/PipeStream.cs | 4 +- .../Common/PortForwardEventArgs.cs | 2 +- src/Renci.SshNet/Common/PosixPath.cs | 6 +- src/Renci.SshNet/Common/SemaphoreLight.cs | 2 +- src/Renci.SshNet/Common/SshData.cs | 4 +- src/Renci.SshNet/Common/SshDataStream.cs | 6 +- src/Renci.SshNet/Compression/ZlibStream.cs | 4 + src/Renci.SshNet/Connection/ConnectorBase.cs | 2 +- src/Renci.SshNet/Connection/HttpConnector.cs | 6 +- .../Connection/ProtocolVersionExchange.cs | 8 +- .../Connection/Socks5Connector.cs | 5 + .../Connection/SshIdentification.cs | 4 +- src/Renci.SshNet/ConnectionInfo.cs | 10 +- src/Renci.SshNet/ExpectAction.cs | 8 +- src/Renci.SshNet/ForwardedPort.cs | 2 +- src/Renci.SshNet/ForwardedPortDynamic.NET.cs | 15 +- src/Renci.SshNet/ForwardedPortLocal.NET.cs | 2 +- src/Renci.SshNet/ForwardedPortLocal.cs | 4 +- src/Renci.SshNet/ForwardedPortRemote.cs | 6 +- src/Renci.SshNet/ForwardedPortStatus.cs | 8 +- src/Renci.SshNet/HashInfo.cs | 2 +- src/Renci.SshNet/MessageEventArgs.cs | 2 +- .../Authentication/RequestMessagePublicKey.cs | 2 + .../Messages/Connection/ChannelDataMessage.cs | 4 +- .../ChannelRequest/ExecRequestInfo.cs | 6 +- .../Messages/Transport/IgnoreMessage.cs | 2 +- src/Renci.SshNet/Netconf/NetConfSession.cs | 2 +- src/Renci.SshNet/NoneAuthenticationMethod.cs | 2 +- .../PasswordAuthenticationMethod.cs | 4 +- .../PrivateKeyAuthenticationMethod.cs | 2 +- src/Renci.SshNet/PrivateKeyFile.cs | 10 +- .../RemotePathDoubleQuoteTransformation.cs | 2 +- .../RemotePathNoneTransformation.cs | 2 +- .../RemotePathShellQuoteTransformation.cs | 2 +- src/Renci.SshNet/ScpClient.NET.cs | 10 +- src/Renci.SshNet/ScpClient.cs | 4 +- .../Security/Cryptography/BlockCipher.cs | 12 +- .../Cryptography/CipherDigitalSignature.cs | 2 +- .../Cryptography/Ciphers/AesCipher.cs | 148 ++++---- .../Cryptography/Ciphers/Arc4Cipher.cs | 8 +- .../Cryptography/Ciphers/BlowfishCipher.cs | 14 +- .../Cryptography/Ciphers/CastCipher.cs | 10 + .../Ciphers/Modes/CtrCipherMode.cs | 10 +- .../Cryptography/Ciphers/RsaCipher.cs | 2 +- .../Cryptography/Ciphers/TripleDesCipher.cs | 8 +- .../Cryptography/Ciphers/TwofishCipher.cs | 153 +++++---- .../Cryptography/DsaDigitalSignature.cs | 2 +- .../Security/Cryptography/DsaKey.cs | 7 +- .../Cryptography/ED25519DigitalSignature.cs | 2 +- .../Security/Cryptography/ED25519Key.cs | 16 +- .../Cryptography/EcdsaDigitalSignature.cs | 2 +- .../Security/Cryptography/EcdsaKey.cs | 16 +- src/Renci.SshNet/Security/Cryptography/Key.cs | 2 +- .../Cryptography/RsaDigitalSignature.cs | 2 + .../Security/Cryptography/RsaKey.cs | 58 ++-- .../Security/Cryptography/SymmetricCipher.cs | 2 +- src/Renci.SshNet/Security/KeyExchange.cs | 9 +- src/Renci.SshNet/ServiceFactory.cs | 10 +- src/Renci.SshNet/Session.cs | 80 ++--- .../ExtendedRequests/FStatVfsRequest.cs | 1 + .../ExtendedRequests/HardLinkRequest.cs | 1 + .../Sftp/Requests/SftpMkDirRequest.cs | 5 +- .../Sftp/Requests/SftpRealPathRequest.cs | 2 +- .../Sftp/Requests/SftpSetStatRequest.cs | 6 +- src/Renci.SshNet/Sftp/SftpFile.cs | 8 +- src/Renci.SshNet/Sftp/SftpFileAttributes.cs | 21 +- src/Renci.SshNet/Sftp/SftpFileReader.cs | 4 +- src/Renci.SshNet/Sftp/SftpFileStream.cs | 20 +- src/Renci.SshNet/Sftp/SftpResponseFactory.cs | 2 + src/Renci.SshNet/Sftp/SftpSession.cs | 16 +- src/Renci.SshNet/SftpClient.cs | 322 +++++++++++++----- src/Renci.SshNet/Shell.cs | 2 +- src/Renci.SshNet/ShellStream.cs | 13 +- src/Renci.SshNet/SshClient.cs | 6 +- src/Renci.SshNet/SshCommand.cs | 19 +- src/Renci.SshNet/SshMessageFactory.cs | 8 +- src/Renci.SshNet/SubsystemSession.cs | 6 +- 365 files changed, 5146 insertions(+), 4206 deletions(-) rename .editorconfig_soon => .editorconfig (99%) create mode 100644 src/Renci.SshNet.Tests/.editorconfig delete mode 100644 src/Renci.SshNet.Tests/Classes/SessionTest.HttpProxy.cs diff --git a/.editorconfig_soon b/.editorconfig similarity index 99% rename from .editorconfig_soon rename to .editorconfig index d0edd58e3..62aefca2e 100644 --- a/.editorconfig_soon +++ b/.editorconfig @@ -535,6 +535,11 @@ dotnet_diagnostic.IDE0045.severity = none # Configured using 'dotnet_style_prefer_conditional_expression_over_return' dotnet_diagnostic.IDE0046.severity = suggestion +# IDE0047: Remove unnecessary parentheses +# +# Removing "unnecessary" parentheses is not always a clear win for readability. +dotnet_diagnostic.IDE0047.severity = suggestion + # IDE0055: Fix formatting # # When enabled, diagnostics are reported for indented object initializers. @@ -547,6 +552,12 @@ dotnet_diagnostic.IDE0046.severity = suggestion # There are no settings to configure this correctly, unless https://github.com/dotnet/roslyn/issues/63256 (or similar) is ever implemented. dotnet_diagnostic.IDE0055.severity = none +# IDE0130: Namespace does not match folder structure +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0130 +# +# TODO: Remove when https://github.com/sshnet/SSH.NET/issues/1129 is fixed +dotnet_diagnostic.IDE0130.severity = none + # IDE0270: Null check can be simplified # # var inputPath = originalDossierPathList.Find(x => x.id == updatedPath.id); diff --git a/Directory.Build.props b/Directory.Build.props index 4fd6964ad..a4f567fdb 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -9,10 +9,8 @@ $(MSBuildThisFileDirectory)src\Renci.SshNet.snk true latest - false diff --git a/src/Renci.SshNet.Tests/.editorconfig b/src/Renci.SshNet.Tests/.editorconfig new file mode 100644 index 000000000..b94e29112 --- /dev/null +++ b/src/Renci.SshNet.Tests/.editorconfig @@ -0,0 +1,32 @@ +锘縖*.cs] + +#### SYSLIB diagnostics #### + +# SYSLIB1045: Use 'GeneratedRegexAttribute' to generate the regular expression implementation at compile-time +# +# TODO: Remove this when https://github.com/sshnet/SSH.NET/issues/1131 is implemented. +dotnet_diagnostic.SYSLIB1045.severity = none + +### StyleCop Analyzers rules ### + +#### .NET Compiler Platform analysers rules #### + +# IDE0007: Use var instead of explicit type +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0007 +dotnet_diagnostic.IDE0007.severity = suggestion + +# IDE0028: Use collection initializers +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0028 +dotnet_diagnostic.IDE0028.severity = suggestion + +# IDE0058: Remove unnecessary expression value +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0058 +dotnet_diagnostic.IDE0058.severity = suggestion + +# IDE0059: Remove unnecessary value assignment +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0059 +dotnet_diagnostic.IDE0059.severity = suggestion + +# IDE0230: Use UTF-8 string literal +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0230 +dotnet_diagnostic.IDE0230.severity = suggestion diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTestBase.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTestBase.cs index 2cce2e918..7c6c58388 100644 --- a/src/Renci.SshNet.Tests/Classes/BaseClientTestBase.cs +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTestBase.cs @@ -6,15 +6,15 @@ namespace Renci.SshNet.Tests.Classes { public abstract class BaseClientTestBase : TripleATestBase { - internal Mock _serviceFactoryMock { get; private set; } - internal Mock _socketFactoryMock { get; private set; } - internal Mock _sessionMock { get; private set; } + internal Mock ServiceFactoryMock { get; private set; } + internal Mock SocketFactoryMock { get; private set; } + internal Mock SessionMock { get; private set; } protected virtual void CreateMocks() { - _serviceFactoryMock = new Mock(MockBehavior.Strict); - _socketFactoryMock = new Mock(MockBehavior.Strict); - _sessionMock = new Mock(MockBehavior.Strict); + ServiceFactoryMock = new Mock(MockBehavior.Strict); + SocketFactoryMock = new Mock(MockBehavior.Strict); + SessionMock = new Mock(MockBehavior.Strict); } protected virtual void SetupData() diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs index e21f516dc..f2a30bbe2 100644 --- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs @@ -24,20 +24,20 @@ protected override void SetupData() protected override void SetupMocks() { - _serviceFactoryMock.Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.Setup(p => p.Connect()); - _sessionMock.Setup(p => p.Dispose()); + ServiceFactoryMock.Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.Setup(p => p.Connect()); + SessionMock.Setup(p => p.Dispose()); } protected override void TearDown() { if (_client != null) { - _sessionMock.Setup(p => p.OnDisconnecting()); - _sessionMock.Setup(p => p.Dispose()); + SessionMock.Setup(p => p.OnDisconnecting()); + SessionMock.Setup(p => p.Dispose()); _client.Dispose(); } } @@ -46,7 +46,7 @@ protected override void Arrange() { base.Arrange(); - _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object) + _client = new MyClient(_connectionInfo, false, ServiceFactoryMock.Object) { OnConnectedException = _onConnectException }; @@ -75,26 +75,26 @@ public void ConnectShouldRethrowExceptionThrownByOnConnect() [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void ConnectOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Connect(), Times.Once); + SessionMock.Verify(p => p.Connect(), Times.Once); } [TestMethod] public void DisposeOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Dispose(), Times.Once); + SessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] @@ -104,7 +104,7 @@ public void ErrorOccuredOnSessionShouldNoLongerBeSignaledViaErrorOccurredOnBaseC _client.ErrorOccurred += (sender, args) => Interlocked.Increment(ref errorOccurredSignalCount); - _sessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception())); + SessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception())); Assert.AreEqual(0, errorOccurredSignalCount); } @@ -116,7 +116,7 @@ public void HostKeyReceivedOnSessionShouldNoLongerBeSignaledViaHostKeyReceivedOn _client.HostKeyReceived += (sender, args) => Interlocked.Increment(ref hostKeyReceivedSignalCount); - _sessionMock.Raise(p => p.HostKeyReceived += null, new HostKeyEventArgs(GetKeyHostAlgorithm())); + SessionMock.Raise(p => p.HostKeyReceived += null, new HostKeyEventArgs(GetKeyHostAlgorithm())); Assert.AreEqual(0, hostKeyReceivedSignalCount); } diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs index 46d730119..4f98bde82 100644 --- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs @@ -1,8 +1,10 @@ 锘縰sing System; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.Connection; + using Renci.SshNet.Messages.Transport; namespace Renci.SshNet.Tests.Classes @@ -24,22 +26,23 @@ protected override void SetupData() protected override void SetupMocks() { - _serviceFactoryMock.Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.Setup(p => p.Connect()); - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.Setup(p => p.TrySendMessage(It.IsAny())) - .Returns(true) - .Callback(() => Interlocked.Increment(ref _keepAliveCount)); + _ = ServiceFactoryMock.Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.Setup(p => p.Connect()); + _ = SessionMock.Setup(p => p.IsConnected) + .Returns(true); + _ = SessionMock.Setup(p => p.TrySendMessage(It.IsAny())) + .Returns(true) + .Callback(() => Interlocked.Increment(ref _keepAliveCount)); } protected override void Arrange() { base.Arrange(); - _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object); + _client = new MyClient(_connectionInfo, false, ServiceFactoryMock.Object); _client.Connect(); _client.KeepAliveInterval = _keepAliveInterval; } @@ -48,8 +51,8 @@ protected override void TearDown() { if (_client != null) { - _sessionMock.Setup(p => p.OnDisconnecting()); - _sessionMock.Setup(p => p.Dispose()); + SessionMock.Setup(p => p.OnDisconnecting()); + SessionMock.Setup(p => p.Dispose()); _client.Dispose(); } } @@ -72,25 +75,25 @@ public void KeepAliveIntervalShouldReturnConfiguredValue() [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void ConnectOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Connect(), Times.Once); + SessionMock.Verify(p => p.Connect(), Times.Once); } [TestMethod] public void IsConnectedOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.IsConnected, Times.Once); + SessionMock.Verify(p => p.IsConnected, Times.Once); } [TestMethod] @@ -99,7 +102,7 @@ public void SendMessageOnSessionShouldBeInvokedOneTime() // allow keep-alive to be sent once Thread.Sleep(100); - _sessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Exactly(1)); + SessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Exactly(1)); } private class MyClient : BaseClient diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs index b9c50e76d..2afb84609 100644 --- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs @@ -23,13 +23,13 @@ protected override void SetupData() protected override void SetupMocks() { - _serviceFactoryMock.Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.Setup(p => p.Connect()); - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.Setup(p => p.TrySendMessage(It.IsAny())) + ServiceFactoryMock.Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.Setup(p => p.Connect()); + SessionMock.Setup(p => p.IsConnected).Returns(true); + SessionMock.Setup(p => p.TrySendMessage(It.IsAny())) .Returns(true) .Callback(() => Interlocked.Increment(ref _keepAliveCount)); } @@ -38,7 +38,7 @@ protected override void Arrange() { base.Arrange(); - _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object); + _client = new MyClient(_connectionInfo, false, ServiceFactoryMock.Object); _client.Connect(); } @@ -46,8 +46,8 @@ protected override void TearDown() { if (_client != null) { - _sessionMock.Setup(p => p.OnDisconnecting()); - _sessionMock.Setup(p => p.Dispose()); + SessionMock.Setup(p => p.OnDisconnecting()); + SessionMock.Setup(p => p.Dispose()); _client.Dispose(); } } @@ -74,32 +74,32 @@ public void KeepAliveIntervalShouldReturnConfiguredValue() [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void ConnectOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Connect(), Times.Once); + SessionMock.Verify(p => p.Connect(), Times.Once); } [TestMethod] public void IsConnectedOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.IsConnected, Times.Once); + SessionMock.Verify(p => p.IsConnected, Times.Once); } [TestMethod] public void SendMessageOnSessionShouldBeInvokedThreeTimes() { - _sessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Exactly(3)); + SessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Exactly(3)); } private class MyClient : BaseClient diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs index 25d6ec7c0..ac0539e98 100644 --- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs @@ -24,15 +24,15 @@ protected override void SetupMocks() { _mockSequence = new MockSequence(); - _serviceFactoryMock.InSequence(_mockSequence) + ServiceFactoryMock.InSequence(_mockSequence) .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(_mockSequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(_mockSequence) + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.InSequence(_mockSequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.InSequence(_mockSequence) .Setup(p => p.Connect()); - _sessionMock.InSequence(_mockSequence) + SessionMock.InSequence(_mockSequence) .Setup(p => p.TrySendMessage(It.IsAny())) .Returns(true) .Callback(() => @@ -46,7 +46,7 @@ protected override void Arrange() { base.Arrange(); - _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object) + _client = new MyClient(_connectionInfo, false, ServiceFactoryMock.Object) { KeepAliveInterval = TimeSpan.FromMilliseconds(50d) }; @@ -57,8 +57,8 @@ protected override void TearDown() { if (_client != null) { - _sessionMock.InSequence(_mockSequence).Setup(p => p.OnDisconnecting()); - _sessionMock.InSequence(_mockSequence).Setup(p => p.Dispose()); + SessionMock.InSequence(_mockSequence).Setup(p => p.OnDisconnecting()); + SessionMock.InSequence(_mockSequence).Setup(p => p.Dispose()); _client.Dispose(); } } @@ -79,7 +79,7 @@ protected override void Act() [TestMethod] public void SendMessageOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Once); + SessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Once); } private class MyClient : BaseClient diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_Connect.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_Connect.cs index 51cd2d81e..ebde0c20c 100644 --- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_Connect.cs +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_Connect.cs @@ -29,22 +29,22 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence) + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.InSequence(sequence) .Setup(p => p.Connect()); - _sessionMock.InSequence(sequence) + SessionMock.InSequence(sequence) .Setup(p => p.OnDisconnecting()); - _sessionMock.InSequence(sequence) + SessionMock.InSequence(sequence) .Setup(p => p.Dispose()); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSocketFactory()) .Returns(_socketFactory2Mock.Object); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSession(_connectionInfo, _socketFactory2Mock.Object)) .Returns(_session2Mock.Object); _session2Mock.InSequence(sequence) @@ -55,7 +55,7 @@ protected override void Arrange() { base.Arrange(); - _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object); + _client = new MyClient(_connectionInfo, false, ServiceFactoryMock.Object); _client.Connect(); _client.Disconnect(); } @@ -78,22 +78,22 @@ protected override void Act() [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedTwic() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Exactly(2)); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Exactly(2)); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedTwice() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactory2Mock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactory2Mock.Object), Times.Once); } [TestMethod] public void ConnectOnSessionShouldBeInvokedTwice() { - _sessionMock.Verify(p => p.Connect(), Times.Once); + SessionMock.Verify(p => p.Connect(), Times.Once); _session2Mock.Verify(p => p.Connect(), Times.Once); } diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs index 1ca4b19d5..e026d09b8 100644 --- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs @@ -21,13 +21,13 @@ protected override void SetupData() protected override void SetupMocks() { - _serviceFactoryMock.Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.Setup(p => p.Connect()); - _sessionMock.Setup(p => p.IsConnected).Returns(false); - _sessionMock.Setup(p => p.TrySendMessage(It.IsAny())) + ServiceFactoryMock.Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.Setup(p => p.Connect()); + SessionMock.Setup(p => p.IsConnected).Returns(false); + SessionMock.Setup(p => p.TrySendMessage(It.IsAny())) .Returns(true); } @@ -35,7 +35,7 @@ protected override void Arrange() { base.Arrange(); - _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object); + _client = new MyClient(_connectionInfo, false, ServiceFactoryMock.Object); _client.Connect(); } @@ -43,8 +43,8 @@ protected override void TearDown() { if (_client != null) { - _sessionMock.Setup(p => p.OnDisconnecting()); - _sessionMock.Setup(p => p.Dispose()); + SessionMock.Setup(p => p.OnDisconnecting()); + SessionMock.Setup(p => p.Dispose()); _client.Dispose(); } } @@ -66,32 +66,32 @@ public void KeepAliveIntervalShouldReturnConfiguredValue() [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void ConnectOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Connect(), Times.Once); + SessionMock.Verify(p => p.Connect(), Times.Once); } [TestMethod] public void IsConnectedOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.IsConnected, Times.Once); + SessionMock.Verify(p => p.IsConnected, Times.Once); } [TestMethod] public void SendMessageOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Never); + SessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Never); } private class MyClient : BaseClient diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs index 0f449c82d..e0720e422 100644 --- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs @@ -25,15 +25,15 @@ protected override void Arrange() { base.Arrange(); - _client = new MyClient(_connectionInfo, false, _serviceFactoryMock.Object); + _client = new MyClient(_connectionInfo, false, ServiceFactoryMock.Object); } protected override void TearDown() { if (_client != null) { - _sessionMock.Setup(p => p.OnDisconnecting()); - _sessionMock.Setup(p => p.Dispose()); + SessionMock.Setup(p => p.OnDisconnecting()); + SessionMock.Setup(p => p.Dispose()); _client.Dispose(); } } @@ -55,12 +55,12 @@ public void KeepAliveIntervalShouldReturnConfiguredValue() [TestMethod] public void ConnectShouldActivateKeepAliveIfSessionIs() { - _serviceFactoryMock.Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.Setup(p => p.Connect()); - _sessionMock.Setup(p => p.TrySendMessage(It.IsAny())) + ServiceFactoryMock.Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.Setup(p => p.Connect()); + SessionMock.Setup(p => p.TrySendMessage(It.IsAny())) .Returns(true) .Callback(() => Interlocked.Increment(ref _keepAliveCount)); @@ -70,7 +70,7 @@ public void ConnectShouldActivateKeepAliveIfSessionIs() Thread.Sleep(250); // Exactly two keep-alives should be sent - _sessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Exactly(2)); + SessionMock.Verify(p => p.TrySendMessage(It.IsAny()), Times.Exactly(2)); } private class MyClient : BaseClient diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs index 1dce239e5..649f6a4f1 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs @@ -3,8 +3,11 @@ using System.Net; using System.Net.Sockets; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; using Renci.SshNet.Messages; @@ -53,16 +56,17 @@ protected override void OnInit() [TestMethod] public void SocketShouldBeClosedAndBindShouldEndWhenForwardedPortSignalsClosingEvent() { - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.Setup(p => p.SendMessage(It.IsAny())) - .Callback(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null, + _ = _sessionMock.Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.Setup(p => p.SendMessage(It.IsAny())) + .Callback(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null, new MessageEventArgs( new ChannelOpenConfirmationMessage(((ChannelOpenMessage) m).LocalChannelNumber, _remoteWindowSize, _remotePacketSize, _remoteChannelNumber)))); - _sessionMock.Setup(p => p.WaitOnHandle(It.IsAny())) - .Callback(p => p.WaitOne(Session.Infinite)); + _ = _sessionMock.Setup(p => p.WaitOnHandle(It.IsAny())) + .Callback(p => p.WaitOne(Session.Infinite)); var localPortEndPoint = new IPEndPoint(IPAddress.Loopback, 8122); using (var localPortListener = new AsyncSocketListener(localPortEndPoint)) @@ -108,16 +112,17 @@ public void SocketShouldBeClosedAndBindShouldEndWhenForwardedPortSignalsClosingE [TestMethod] public void SocketShouldBeClosedAndBindShouldEndWhenOnErrorOccurredIsInvoked() { - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.Setup(p => p.SendMessage(It.IsAny())) - .Callback(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null, + _ = _sessionMock.Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.Setup(p => p.SendMessage(It.IsAny())) + .Callback(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null, new MessageEventArgs( new ChannelOpenConfirmationMessage(((ChannelOpenMessage) m).LocalChannelNumber, _remoteWindowSize, _remotePacketSize, _remoteChannelNumber)))); - _sessionMock.Setup(p => p.WaitOnHandle(It.IsAny())) - .Callback(p => p.WaitOne(Session.Infinite)); + _ = _sessionMock.Setup(p => p.WaitOnHandle(It.IsAny())) + .Callback(p => p.WaitOne(Session.Infinite)); var localPortEndPoint = new IPEndPoint(IPAddress.Loopback, 8122); using (var localPortListener = new AsyncSocketListener(localPortEndPoint)) @@ -166,46 +171,53 @@ public void SocketShouldBeClosedAndEofShouldBeSentToServerWhenClientShutsDownSoc { var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) - .Setup(p => p.SendMessage(It.IsAny())) - .Callback(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null, + _ = _sessionMock.InSequence(sequence).Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.SendMessage(It.IsAny())) + .Callback(m => _sessionMock.Raise(p => p.ChannelOpenConfirmationReceived += null, new MessageEventArgs( new ChannelOpenConfirmationMessage(((ChannelOpenMessage) m).LocalChannelNumber, _remoteWindowSize, _remotePacketSize, _remoteChannelNumber)))); - _sessionMock.InSequence(sequence) - .Setup(p => p.WaitOnHandle(It.IsAny())) - .Callback(p => p.WaitOne(Session.Infinite)); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) - .Setup(p => p.TrySendMessage(It.IsAny())) - .Returns(true) - .Callback( - m => new Thread(() => - { - Thread.Sleep(50); - _sessionMock.Raise(s => s.ChannelEofReceived += null, - new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); - }).Start()); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) - .Setup(p => p.TrySendMessage(It.IsAny())) - .Returns(true) - .Callback( - m => new Thread(() => - { - Thread.Sleep(50); - _sessionMock.Raise(s => s.ChannelCloseReceived += null, - new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); - }).Start()); - _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); - _sessionMock.InSequence(sequence) - .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) - .Callback((waitHandle, channelCloseTimeout) => waitHandle.WaitOne()) - .Returns(WaitResult.Success); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.WaitOnHandle(It.IsAny())) + .Callback(p => p.WaitOne(Session.Infinite)); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.TrySendMessage(It.IsAny())) + .Returns(true) + .Callback(m => new Thread(() => + { + Thread.Sleep(50); + _sessionMock.Raise(s => s.ChannelEofReceived += null, + new MessageEventArgs(new ChannelEofMessage(_localChannelNumber))); + }).Start()); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.TrySendMessage(It.IsAny())) + .Returns(true) + .Callback(m => new Thread(() => + { + Thread.Sleep(50); + _sessionMock.Raise(s => s.ChannelCloseReceived += null, + new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + }).Start()); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _ = _connectionInfoMock.InSequence(sequence) + .Setup(p => p.ChannelCloseTimeout) + .Returns(_channelCloseTimeout); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => waitHandle.WaitOne()) + .Returns(WaitResult.Success); var channelBindFinishedWaitHandle = new ManualResetEvent(false); Socket handler = null; @@ -217,26 +229,26 @@ public void SocketShouldBeClosedAndEofShouldBeSentToServerWhenClientShutsDownSoc localPortListener.Start(); localPortListener.Connected += socket => - { - channel = new ChannelDirectTcpip(_sessionMock.Object, - _localChannelNumber, - _localWindowSize, - _localPacketSize); - channel.Open(_remoteHost, _port, _forwardedPortMock.Object, socket); - channel.Bind(); - channel.Dispose(); + { + channel = new ChannelDirectTcpip(_sessionMock.Object, + _localChannelNumber, + _localWindowSize, + _localPacketSize); + channel.Open(_remoteHost, _port, _forwardedPortMock.Object, socket); + channel.Bind(); + channel.Dispose(); - handler = socket; + handler = socket; - channelBindFinishedWaitHandle.Set(); - }; + _ = channelBindFinishedWaitHandle.Set(); + }; var client = new Socket(localPortEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); client.Connect(localPortEndPoint); client.Shutdown(SocketShutdown.Send); Assert.IsFalse(client.Connected); - channelBindFinishedWaitHandle.WaitOne(); + _ = channelBindFinishedWaitHandle.WaitOne(); Assert.IsNotNull(handler); Assert.IsFalse(handler.Connected); @@ -251,4 +263,4 @@ public void SocketShouldBeClosedAndEofShouldBeSentToServerWhenClientShutsDownSoc } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs index da7739694..6ccda5c82 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs @@ -79,45 +79,53 @@ private void Arrange() _forwardedPortMock = new Mock(MockBehavior.Strict); var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) - .Setup(p => p.SendMessage(It.Is(m => AssertExpectedMessage(m)))); - _sessionMock.InSequence(sequence) - .Setup(p => p.WaitOnHandle(It.IsNotNull())) - .Callback( - w => - { - _sessionMock.Raise( - s => s.ChannelOpenConfirmationReceived += null, - new MessageEventArgs( - new ChannelOpenConfirmationMessage( - _localChannelNumber, - _remoteWindowSize, - _remotePacketSize, - _remoteChannelNumber))); - w.WaitOne(); - }); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) - .Setup( - p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) - .Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) - .Setup(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) - .Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); - _sessionMock.InSequence(sequence) - .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) - .Callback((waitHandle, channelCloseTimeout) => - { - _sessionMock.Raise( - s => s.ChannelCloseReceived += null, - new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); - waitHandle.WaitOne(); - }) - .Returns(WaitResult.Success); + + _ = _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.SendMessage(It.Is(m => AssertExpectedMessage(m)))); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.WaitOnHandle(It.IsNotNull())) + .Callback( + w => + { + _sessionMock.Raise( + s => s.ChannelOpenConfirmationReceived += null, + new MessageEventArgs( + new ChannelOpenConfirmationMessage( + _localChannelNumber, + _remoteWindowSize, + _remotePacketSize, + _remoteChannelNumber))); + _ = w.WaitOne(); + }); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) + .Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) + .Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _ = _connectionInfoMock.InSequence(sequence) + .Setup(p => p.ChannelCloseTimeout) + .Returns(_channelCloseTimeout); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => + { + _sessionMock.Raise( + s => s.ChannelCloseReceived += null, + new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + _ = waitHandle.WaitOne(); + }) + .Returns(WaitResult.Success); var localEndpoint = new IPEndPoint(IPAddress.Loopback, 8122); _listener = new AsyncSocketListener(localEndpoint); @@ -138,7 +146,7 @@ private void Arrange() } finally { - _channelBindFinishedWaitHandle.Set(); + _ = _channelBindFinishedWaitHandle.Set(); } }; _listener.Start(); @@ -154,7 +162,7 @@ private void Arrange() if (bytesReceived == 0) { _client.Shutdown(SocketShutdown.Send); - _clientReceivedFinishedWaitHandle.Set(); + _ = _clientReceivedFinishedWaitHandle.Set(); } } ); @@ -166,17 +174,14 @@ private void Arrange() private void Act() { - if (_channel != null) - { - _channel.Dispose(); - } + _channel?.Dispose(); } [TestMethod] public void BindShouldHaveFinishedWithoutException() { Assert.IsTrue(_channelBindFinishedWaitHandle.WaitOne(0)); - Assert.IsNull(_channelException, _channelException != null ? _channelException.ToString() : null); + Assert.IsNull(_channelException, _channelException?.ToString()); } [TestMethod] @@ -206,29 +211,54 @@ public void IsOpenShouldReturnFalse() private bool AssertExpectedMessage(ChannelOpenMessage channelOpenMessage) { if (channelOpenMessage == null) + { return false; + } + if (channelOpenMessage.LocalChannelNumber != _localChannelNumber) + { return false; + } + if (channelOpenMessage.InitialWindowSize != _localWindowSize) + { return false; + } + if (channelOpenMessage.MaximumPacketSize != _localPacketSize) + { return false; + } - var directTcpipChannelInfo = channelOpenMessage.Info as DirectTcpipChannelInfo; - if (directTcpipChannelInfo == null) + if (channelOpenMessage.Info is not DirectTcpipChannelInfo directTcpipChannelInfo) + { return false; + } + if (directTcpipChannelInfo.HostToConnect != _remoteHost) + { return false; + } + if (directTcpipChannelInfo.PortToConnect != _port) + { return false; + } - var clientEndpoint = _client.LocalEndPoint as IPEndPoint; - if (clientEndpoint == null) + if (_client.LocalEndPoint is not IPEndPoint clientEndpoint) + { return false; + } + if (directTcpipChannelInfo.OriginatorAddress != clientEndpoint.Address.ToString()) + { return false; + } + if (directTcpipChannelInfo.OriginatorPort != clientEndpoint.Port) + { return false; + } return true; } diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs index bbbff6d37..393eae093 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs @@ -1,11 +1,13 @@ 锘縰sing System; -using System.Collections; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; @@ -53,10 +55,10 @@ public void CleanUp() if (_channelThread != null) { - if (_channelThread.IsAlive) - _channelThread.Abort(); + _channelThread.Join(); _channelThread = null; } + if (_channel != null) { _channel.Dispose(); @@ -87,56 +89,63 @@ private void Arrange() _forwardedPortMock = new Mock(MockBehavior.Strict); var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(sequence).Setup(p => p.Timeout).Returns(_connectionInfoTimeout); - _sessionMock.InSequence(sequence).Setup( - p => p.SendMessage( - It.Is( - m => m.LocalChannelNumber == _remoteChannelNumber - && - m.InitialWindowSize == _localWindowSize - && - m.MaximumPacketSize == _localPacketSize - && - m.RemoteChannelNumber == _localChannelNumber) - )); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) - .Setup( - p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) - .Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(sequence) - .Setup( - p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) - .Returns(true); - _sessionMock.InSequence(sequence).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(sequence).Setup(p => p.ChannelCloseTimeout).Returns(_channelCloseTimeout); - _sessionMock.InSequence(sequence) - .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) - .Callback((waitHandle, channelCloseTimeout) => - { - _sessionMock.Raise( - s => s.ChannelCloseReceived += null, - new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); - waitHandle.WaitOne(); - }) - .Returns(WaitResult.Success); + + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _ = _connectionInfoMock.InSequence(sequence) + .Setup(p => p.Timeout) + .Returns(_connectionInfoTimeout); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.SendMessage(It.Is(m => + m.LocalChannelNumber == _remoteChannelNumber && + m.InitialWindowSize == _localWindowSize && + m.MaximumPacketSize == _localPacketSize && + m.RemoteChannelNumber == _localChannelNumber))); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) + .Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.TrySendMessage(It.Is(m => m.LocalChannelNumber == _remoteChannelNumber))) + .Returns(true); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _ = _connectionInfoMock.InSequence(sequence) + .Setup(p => p.ChannelCloseTimeout) + .Returns(_channelCloseTimeout); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.TryWait(It.IsAny(), _channelCloseTimeout)) + .Callback((waitHandle, channelCloseTimeout) => + { + _sessionMock.Raise( + s => s.ChannelCloseReceived += null, + new MessageEventArgs(new ChannelCloseMessage(_localChannelNumber))); + _ = waitHandle.WaitOne(); + }) + .Returns(WaitResult.Success); _remoteListener = new AsyncSocketListener(_remoteEndpoint); - _remoteListener.Connected += socket => _connectedRegister.Add(socket); - _remoteListener.Disconnected += socket => _disconnectedRegister.Add(socket); + _remoteListener.Connected += _connectedRegister.Add; + _remoteListener.Disconnected += _disconnectedRegister.Add; _remoteListener.Start(); - _channel = new ChannelForwardedTcpip( - _sessionMock.Object, - _localChannelNumber, - _localWindowSize, - _localPacketSize, - _remoteChannelNumber, - _remoteWindowSize, - _remotePacketSize); + _channel = new ChannelForwardedTcpip(_sessionMock.Object, + _localChannelNumber, + _localWindowSize, + _localPacketSize, + _remoteChannelNumber, + _remoteWindowSize, + _remotePacketSize); _channelThread = new Thread(() => { @@ -150,7 +159,7 @@ private void Arrange() } finally { - _channelBindFinishedWaitHandle.Set(); + _ = _channelBindFinishedWaitHandle.Set(); } }); _channelThread.Start(); @@ -175,7 +184,7 @@ public void ChannelShouldShutdownSocketToRemoteListener() [TestMethod] public void BindShouldHaveFinishedWithoutException() { - Assert.IsNull(_channelException, _channelException != null ? _channelException.ToString() : null); + Assert.IsNull(_channelException, _channelException?.ToString()); Assert.IsTrue(_channelBindFinishedWaitHandle.WaitOne(0)); } @@ -197,4 +206,4 @@ public void IsOpenShouldReturnFalse() Assert.IsFalse(_channel.IsOpen); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs index 379f7e181..07ba0d53e 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs @@ -1,8 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; @@ -144,4 +147,4 @@ public void IsOpenShouldReturnFalse() Assert.IsFalse(_channel.IsOpen); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelStub.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelStub.cs index ac141b9b6..6476ec919 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelStub.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelStub.cs @@ -54,7 +54,7 @@ public void SetIsOpen(bool value) public void InitializeRemoteChannelInfo(uint remoteChannelNumber, uint remoteWindowSize, uint remotePacketSize) { - base.InitializeRemoteInfo(remoteChannelNumber, remoteWindowSize, remotePacketSize); + InitializeRemoteInfo(remoteChannelNumber, remoteWindowSize, remotePacketSize); } protected override void OnClose() @@ -62,7 +62,9 @@ protected override void OnClose() base.OnClose(); if (OnCloseException != null) + { throw OnCloseException; + } } protected override void OnData(byte[] data) @@ -70,7 +72,9 @@ protected override void OnData(byte[] data) base.OnData(data); if (OnDataException != null) + { throw OnDataException; + } } protected override void OnDisconnected() @@ -78,7 +82,9 @@ protected override void OnDisconnected() base.OnDisconnected(); if (OnDisconnectedException != null) + { throw OnDisconnectedException; + } } protected override void OnEof() @@ -86,7 +92,9 @@ protected override void OnEof() base.OnEof(); if (OnEofException != null) + { throw OnEofException; + } } protected override void OnExtendedData(byte[] data, uint dataTypeCode) @@ -94,7 +102,9 @@ protected override void OnExtendedData(byte[] data, uint dataTypeCode) base.OnExtendedData(data, dataTypeCode); if (OnExtendedDataException != null) + { throw OnExtendedDataException; + } } protected override void OnErrorOccured(Exception exp) @@ -102,7 +112,9 @@ protected override void OnErrorOccured(Exception exp) OnErrorOccurredInvocations.Add(exp); if (OnErrorOccurredException != null) + { throw OnErrorOccurredException; + } } protected override void OnFailure() @@ -110,7 +122,9 @@ protected override void OnFailure() base.OnFailure(); if (OnFailureException != null) + { throw OnFailureException; + } } protected override void OnRequest(RequestInfo info) @@ -118,7 +132,9 @@ protected override void OnRequest(RequestInfo info) base.OnRequest(info); if (OnRequestException != null) + { throw OnRequestException; + } } protected override void OnSuccess() @@ -126,7 +142,9 @@ protected override void OnSuccess() base.OnSuccess(); if (OnSuccessException != null) + { throw OnSuccessException; + } } protected override void OnWindowAdjust(uint bytesToAdd) @@ -134,7 +152,9 @@ protected override void OnWindowAdjust(uint bytesToAdd) base.OnWindowAdjust(bytesToAdd); if (OnWindowAdjustException != null) + { throw OnWindowAdjustException; + } } } } diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs index 0bb9e862d..23a00ca83 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs @@ -94,12 +94,10 @@ public void TearDown() _channelClosedReceived = null; } - if (_raiseChannelCloseReceivedThread != null && _raiseChannelCloseReceivedThread.IsAlive) + if (_raiseChannelCloseReceivedThread != null) { - if (!_raiseChannelCloseReceivedThread.Join(1000)) - { - _raiseChannelCloseReceivedThread.Abort(); - } + _raiseChannelCloseReceivedThread.Join(); + _raiseChannelCloseReceivedThread = null; } if (_channelClosedEventHandlerCompleted != null) diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs index 102a57698..8a7368499 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs @@ -1,7 +1,8 @@ 锘縰sing System; using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs index 3c2884f2c..bdb3cadfa 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs @@ -1,7 +1,8 @@ 锘縰sing System; using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; @@ -61,4 +62,4 @@ public void OnErrorOccuredShouldBeInvokedOnce() Assert.AreSame(_onDataException, _channel.OnErrorOccurredInvocations[0]); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs index ff4a38bb3..69a5adb47 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs @@ -1,7 +1,8 @@ 锘縰sing System; using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; @@ -69,4 +70,4 @@ public void OnErrorOccuredShouldBeInvokedOnce() Assert.AreSame(_onEofException, _channel.OnErrorOccurredInvocations[0]); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs index 9f582933c..c27f73392 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs @@ -1,7 +1,8 @@ 锘縰sing System; using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; @@ -61,4 +62,4 @@ public void OnErrorOccuredShouldBeInvokedOnce() Assert.AreSame(_onExtendedDataException, _channel.OnErrorOccurredInvocations[0]); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs index 935048a28..360628ca2 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs @@ -1,7 +1,8 @@ 锘縰sing System; using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; @@ -61,4 +62,4 @@ public void OnErrorOccuredShouldBeInvokedOnce() Assert.AreSame(_onFailureException, _channel.OnErrorOccurredInvocations[0]); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs index d5c82801d..407480dea 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs @@ -1,7 +1,8 @@ 锘縰sing System; using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; @@ -32,8 +33,8 @@ protected override void SetupData() protected override void SetupMocks() { - SessionMock.Setup(p => p.ConnectionInfo) - .Returns(new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "password"))); + _ = SessionMock.Setup(p => p.ConnectionInfo) + .Returns(new ConnectionInfo("host", "user", new PasswordAuthenticationMethod("user", "password"))); } protected override void Arrange() @@ -65,4 +66,4 @@ public void OnErrorOccuredShouldBeInvokedOnce() Assert.AreSame(_onRequestException, _channel.OnErrorOccurredInvocations[0]); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs index 2caa91f1b..09a9e1ea2 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs @@ -1,7 +1,8 @@ 锘縰sing System; using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; @@ -61,4 +62,4 @@ public void OnErrorOccuredShouldBeInvokedOnce() Assert.AreSame(_onSuccessException, _channel.OnErrorOccurredInvocations[0]); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs index ba223ad91..1019204b2 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs @@ -1,7 +1,8 @@ 锘縰sing System; using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; @@ -70,4 +71,4 @@ public void OnErrorOccuredShouldBeInvokedOnce() Assert.AreSame(_onWindowAdjustException, _channel.OnErrorOccurredInvocations[0]); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs index 4796c4e6f..989ea952c 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs @@ -1,7 +1,8 @@ 锘縰sing System; using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; + using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes.Channels @@ -59,4 +60,4 @@ public void OnErrorOccuredShouldBeInvokedOnce() Assert.AreSame(_onDisconnectedException, _channel.OnErrorOccurredInvocations[0]); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs index e228c36bc..327aa1268 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs @@ -1,7 +1,8 @@ 锘縰sing System; using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; + using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes.Channels @@ -35,7 +36,8 @@ protected override void SetupData() protected override void SetupMocks() { - SessionMock.Setup(p => p.IsConnected).Returns(true); + _ = SessionMock.Setup(p => p.IsConnected) + .Returns(true); } protected override void Arrange() @@ -72,4 +74,4 @@ public void ExceptionShouldNeverHaveFired() Assert.AreEqual(0, _channelExceptionRegister.Count); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ClientChannelStub.cs b/src/Renci.SshNet.Tests/Classes/Channels/ClientChannelStub.cs index 621c47002..05c52f2ac 100644 --- a/src/Renci.SshNet.Tests/Classes/Channels/ClientChannelStub.cs +++ b/src/Renci.SshNet.Tests/Classes/Channels/ClientChannelStub.cs @@ -1,5 +1,6 @@ 锘縰sing System; using System.Collections.Generic; + using Renci.SshNet.Channels; using Renci.SshNet.Messages.Connection; @@ -58,7 +59,7 @@ public void SetIsOpen(bool value) public void InitializeRemoteChannelInfo(uint remoteChannelNumber, uint remoteWindowSize, uint remotePacketSize) { - base.InitializeRemoteInfo(remoteChannelNumber, remoteWindowSize, remotePacketSize); + InitializeRemoteInfo(remoteChannelNumber, remoteWindowSize, remotePacketSize); } protected override void OnClose() @@ -66,7 +67,9 @@ protected override void OnClose() base.OnClose(); if (OnCloseException != null) + { throw OnCloseException; + } } protected override void OnData(byte[] data) @@ -74,7 +77,9 @@ protected override void OnData(byte[] data) base.OnData(data); if (OnDataException != null) + { throw OnDataException; + } } protected override void OnDisconnected() @@ -82,7 +87,9 @@ protected override void OnDisconnected() base.OnDisconnected(); if (OnDisconnectedException != null) + { throw OnDisconnectedException; + } } protected override void OnEof() @@ -90,7 +97,9 @@ protected override void OnEof() base.OnEof(); if (OnEofException != null) + { throw OnEofException; + } } protected override void OnExtendedData(byte[] data, uint dataTypeCode) @@ -98,7 +107,9 @@ protected override void OnExtendedData(byte[] data, uint dataTypeCode) base.OnExtendedData(data, dataTypeCode); if (OnExtendedDataException != null) + { throw OnExtendedDataException; + } } protected override void OnErrorOccured(Exception exp) @@ -106,7 +117,9 @@ protected override void OnErrorOccured(Exception exp) OnErrorOccurredInvocations.Add(exp); if (OnErrorOccurredException != null) + { throw OnErrorOccurredException; + } } protected override void OnFailure() @@ -114,7 +127,9 @@ protected override void OnFailure() base.OnFailure(); if (OnFailureException != null) + { throw OnFailureException; + } } protected override void OnRequest(RequestInfo info) @@ -122,7 +137,9 @@ protected override void OnRequest(RequestInfo info) base.OnRequest(info); if (OnRequestException != null) + { throw OnRequestException; + } } protected override void OnSuccess() @@ -130,7 +147,9 @@ protected override void OnSuccess() base.OnSuccess(); if (OnSuccessException != null) + { throw OnSuccessException; + } } protected override void OnWindowAdjust(uint bytesToAdd) @@ -138,7 +157,9 @@ protected override void OnWindowAdjust(uint bytesToAdd) base.OnWindowAdjust(bytesToAdd); if (OnWindowAdjustException != null) + { throw OnWindowAdjustException; + } } protected override void OnOpenConfirmation(uint remoteChannelNumber, uint initialWindowSize, uint maximumPacketSize) @@ -146,7 +167,9 @@ protected override void OnOpenConfirmation(uint remoteChannelNumber, uint initia base.OnOpenConfirmation(remoteChannelNumber, initialWindowSize, maximumPacketSize); if (OnOpenConfirmationException != null) + { throw OnOpenConfirmationException; + } } protected override void OnOpenFailure(uint reasonCode, string description, string language) @@ -154,7 +177,9 @@ protected override void OnOpenFailure(uint reasonCode, string description, strin base.OnOpenFailure(reasonCode, description, language); if (OnOpenFailureException != null) + { throw OnOpenFailureException; + } } } } diff --git a/src/Renci.SshNet.Tests/Classes/CipherInfoTest.cs b/src/Renci.SshNet.Tests/Classes/CipherInfoTest.cs index 4014fc3ce..832c92f8b 100644 --- a/src/Renci.SshNet.Tests/Classes/CipherInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/CipherInfoTest.cs @@ -1,7 +1,8 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; + using Renci.SshNet.Security.Cryptography; using Renci.SshNet.Tests.Common; + using System; namespace Renci.SshNet.Tests.Classes @@ -19,10 +20,10 @@ public class CipherInfoTest : TestBase [Ignore] // placeholder public void CipherInfoConstructorTest() { - int keySize = 0; // TODO: Initialize to an appropriate value + var keySize = 0; // TODO: Initialize to an appropriate value Func cipher = null; // TODO: Initialize to an appropriate value - CipherInfo target = new CipherInfo(keySize, cipher); + var target = new CipherInfo(keySize, cipher); Assert.Inconclusive("TODO: Implement code to verify target"); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs b/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs index 16f08ba92..877874145 100644 --- a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs +++ b/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs @@ -1,7 +1,8 @@ 锘縰sing System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes { diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PostponePartialAccessAuthenticationMethod.cs b/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PostponePartialAccessAuthenticationMethod.cs index dd7c14c32..4a0d5fc24 100644 --- a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PostponePartialAccessAuthenticationMethod.cs +++ b/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PostponePartialAccessAuthenticationMethod.cs @@ -1,5 +1,7 @@ 锘縰sing System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; namespace Renci.SshNet.Tests.Classes @@ -19,52 +21,68 @@ protected override void SetupMocks() { var seq = new MockSequence(); - SessionMock.InSequence(seq).Setup(p => p.RegisterMessage("SSH_MSG_USERAUTH_FAILURE")); - SessionMock.InSequence(seq).Setup(p => p.RegisterMessage("SSH_MSG_USERAUTH_SUCCESS")); - SessionMock.InSequence(seq).Setup(p => p.RegisterMessage("SSH_MSG_USERAUTH_BANNER")); - - ConnectionInfoMock.InSequence(seq).Setup(p => p.CreateNoneAuthenticationMethod()) - .Returns(NoneAuthenticationMethodMock.Object); - - NoneAuthenticationMethodMock.InSequence(seq) - .Setup(p => p.Authenticate(SessionMock.Object)) - .Returns(AuthenticationResult.Failure); - ConnectionInfoMock.InSequence(seq) - .Setup(p => p.AuthenticationMethods) - .Returns(new List - { - KeyboardInteractiveAuthenticationMethodMock.Object, - PasswordAuthenticationMethodMock.Object, - PublicKeyAuthenticationMethodMock.Object - }); - NoneAuthenticationMethodMock.InSequence(seq).Setup(p => p.AllowedAuthentications).Returns(new[] { "password" }); - KeyboardInteractiveAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("keyboard-interactive"); - PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password"); - PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey"); - - PasswordAuthenticationMethodMock.InSequence(seq) + _ = SessionMock.InSequence(seq) + .Setup(p => p.RegisterMessage("SSH_MSG_USERAUTH_FAILURE")); + _ = SessionMock.InSequence(seq) + .Setup(p => p.RegisterMessage("SSH_MSG_USERAUTH_SUCCESS")); + _ = SessionMock.InSequence(seq) + .Setup(p => p.RegisterMessage("SSH_MSG_USERAUTH_BANNER")); + _ = ConnectionInfoMock.InSequence(seq) + .Setup(p => p.CreateNoneAuthenticationMethod()) + .Returns(NoneAuthenticationMethodMock.Object); + _ = NoneAuthenticationMethodMock.InSequence(seq) .Setup(p => p.Authenticate(SessionMock.Object)) - .Returns(AuthenticationResult.PartialSuccess); - PasswordAuthenticationMethodMock.InSequence(seq) + .Returns(AuthenticationResult.Failure); + _ = ConnectionInfoMock.InSequence(seq) + .Setup(p => p.AuthenticationMethods) + .Returns(new List + { + KeyboardInteractiveAuthenticationMethodMock.Object, + PasswordAuthenticationMethodMock.Object, + PublicKeyAuthenticationMethodMock.Object + }); + _ = NoneAuthenticationMethodMock.InSequence(seq) .Setup(p => p.AllowedAuthentications) - .Returns(new[] {"password", "publickey"}); - KeyboardInteractiveAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("keyboard-interactive"); - PasswordAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("password"); - PublicKeyAuthenticationMethodMock.InSequence(seq).Setup(p => p.Name).Returns("publickey"); - - PublicKeyAuthenticationMethodMock.InSequence(seq) - .Setup(p => p.Authenticate(SessionMock.Object)) - .Returns(AuthenticationResult.Failure); - PublicKeyAuthenticationMethodMock.InSequence(seq) - .Setup(p => p.Name) - .Returns("publickey"); - PasswordAuthenticationMethodMock.InSequence(seq) - .Setup(p => p.Authenticate(SessionMock.Object)) - .Returns(AuthenticationResult.Success); - - SessionMock.InSequence(seq).Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_FAILURE")); - SessionMock.InSequence(seq).Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_SUCCESS")); - SessionMock.InSequence(seq).Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_BANNER")); + .Returns(new[] { "password" }); + _ = KeyboardInteractiveAuthenticationMethodMock.InSequence(seq) + .Setup(p => p.Name) + .Returns("keyboard-interactive"); + _ = PasswordAuthenticationMethodMock.InSequence(seq) + .Setup(p => p.Name) + .Returns("password"); + _ = PublicKeyAuthenticationMethodMock.InSequence(seq) + .Setup(p => p.Name) + .Returns("publickey"); + _ = PasswordAuthenticationMethodMock.InSequence(seq) + .Setup(p => p.Authenticate(SessionMock.Object)) + .Returns(AuthenticationResult.PartialSuccess); + _ = PasswordAuthenticationMethodMock.InSequence(seq) + .Setup(p => p.AllowedAuthentications) + .Returns(new[] {"password", "publickey"}); + _ = KeyboardInteractiveAuthenticationMethodMock.InSequence(seq) + .Setup(p => p.Name) + .Returns("keyboard-interactive"); + _ = PasswordAuthenticationMethodMock.InSequence(seq) + .Setup(p => p.Name) + .Returns("password"); + _ = PublicKeyAuthenticationMethodMock.InSequence(seq) + .Setup(p => p.Name) + .Returns("publickey"); + _ = PublicKeyAuthenticationMethodMock.InSequence(seq) + .Setup(p => p.Authenticate(SessionMock.Object)) + .Returns(AuthenticationResult.Failure); + _ = PublicKeyAuthenticationMethodMock.InSequence(seq) + .Setup(p => p.Name) + .Returns("publickey"); + _ = PasswordAuthenticationMethodMock.InSequence(seq) + .Setup(p => p.Authenticate(SessionMock.Object)) + .Returns(AuthenticationResult.Success); + _ = SessionMock.InSequence(seq) + .Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_FAILURE")); + _ = SessionMock.InSequence(seq) + .Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_SUCCESS")); + _ = SessionMock.InSequence(seq) + .Setup(p => p.UnRegisterMessage("SSH_MSG_USERAUTH_BANNER")); } protected override void Arrange() diff --git a/src/Renci.SshNet.Tests/Classes/CommandAsyncResultTest.cs b/src/Renci.SshNet.Tests/Classes/CommandAsyncResultTest.cs index c04b83d72..c340f40f4 100644 --- a/src/Renci.SshNet.Tests/Classes/CommandAsyncResultTest.cs +++ b/src/Renci.SshNet.Tests/Classes/CommandAsyncResultTest.cs @@ -11,7 +11,7 @@ public class CommandAsyncResultTest : TestBase public void BytesSentTest() { var target = new CommandAsyncResult(); - int expected = new Random().Next(); + var expected = new Random().Next(); target.BytesSent = expected; diff --git a/src/Renci.SshNet.Tests/Classes/Common/AsyncResultTest.cs b/src/Renci.SshNet.Tests/Classes/Common/AsyncResultTest.cs index e000fbe6f..5a972e69f 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/AsyncResultTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/AsyncResultTest.cs @@ -1,6 +1,7 @@ 锘縰sing System; -using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; @@ -19,10 +20,9 @@ public class AsyncResultTest : TestBase /// public void EndInvokeTest1Helper() { - AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - TResult expected = default(TResult); // TODO: Initialize to an appropriate value - TResult actual; - actual = target.EndInvoke(); + var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value + var expected = default(TResult); // TODO: Initialize to an appropriate value + var actual = target.EndInvoke(); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); } @@ -45,9 +45,9 @@ public void EndInvokeTest1() /// public void SetAsCompletedTest1Helper() { - AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - TResult result = default(TResult); // TODO: Initialize to an appropriate value - bool completedSynchronously = false; // TODO: Initialize to an appropriate value + var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value + TResult result = default; // TODO: Initialize to an appropriate value + var completedSynchronously = false; // TODO: Initialize to an appropriate value target.SetAsCompleted(result, completedSynchronously); Assert.Inconclusive("A method that does not return a value cannot be verified."); } @@ -71,7 +71,7 @@ internal virtual AsyncResult CreateAsyncResult() [TestMethod] public void EndInvokeTest() { - AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value + var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value target.EndInvoke(); Assert.Inconclusive("A method that does not return a value cannot be verified."); } @@ -82,9 +82,9 @@ public void EndInvokeTest() [TestMethod] public void SetAsCompletedTest() { - AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value + var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value Exception exception = null; // TODO: Initialize to an appropriate value - bool completedSynchronously = false; // TODO: Initialize to an appropriate value + var completedSynchronously = false; // TODO: Initialize to an appropriate value target.SetAsCompleted(exception, completedSynchronously); Assert.Inconclusive("A method that does not return a value cannot be verified."); } @@ -95,9 +95,8 @@ public void SetAsCompletedTest() [TestMethod] public void AsyncStateTest() { - AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - object actual; - actual = target.AsyncState; + var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value + var actual = target.AsyncState; Assert.Inconclusive("Verify the correctness of this test method."); } @@ -107,9 +106,8 @@ public void AsyncStateTest() [TestMethod] public void AsyncWaitHandleTest() { - AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - WaitHandle actual; - actual = target.AsyncWaitHandle; + var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value + var actual = target.AsyncWaitHandle; Assert.Inconclusive("Verify the correctness of this test method."); } @@ -119,9 +117,8 @@ public void AsyncWaitHandleTest() [TestMethod] public void CompletedSynchronouslyTest() { - AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - bool actual; - actual = target.CompletedSynchronously; + var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value + var actual = target.CompletedSynchronously; Assert.Inconclusive("Verify the correctness of this test method."); } @@ -131,9 +128,8 @@ public void CompletedSynchronouslyTest() [TestMethod] public void IsCompletedTest() { - AsyncResult target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - bool actual; - actual = target.IsCompleted; + var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value + var actual = target.IsCompleted; Assert.Inconclusive("Verify the correctness of this test method."); } } diff --git a/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs index e381cf1b0..9200d2a43 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs @@ -19,8 +19,8 @@ public class AuthenticationPasswordChangeEventArgsTest : TestBase [TestMethod] public void AuthenticationPasswordChangeEventArgsConstructorTest() { - string username = string.Empty; // TODO: Initialize to an appropriate value - AuthenticationPasswordChangeEventArgs target = new AuthenticationPasswordChangeEventArgs(username); + var username = string.Empty; // TODO: Initialize to an appropriate value + var target = new AuthenticationPasswordChangeEventArgs(username); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -31,7 +31,7 @@ public void AuthenticationPasswordChangeEventArgsConstructorTest() public void NewPasswordTest() { string username = string.Empty; // TODO: Initialize to an appropriate value - AuthenticationPasswordChangeEventArgs target = new AuthenticationPasswordChangeEventArgs(username); // TODO: Initialize to an appropriate value + var target = new AuthenticationPasswordChangeEventArgs(username); // TODO: Initialize to an appropriate value byte[] expected = null; // TODO: Initialize to an appropriate value byte[] actual; target.NewPassword = expected; diff --git a/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs index 698d1ab23..47b83126f 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs @@ -20,11 +20,11 @@ public class AuthenticationPromptEventArgsTest : TestBase [TestMethod] public void AuthenticationPromptEventArgsConstructorTest() { - string username = string.Empty; // TODO: Initialize to an appropriate value - string instruction = string.Empty; // TODO: Initialize to an appropriate value - string language = string.Empty; // TODO: Initialize to an appropriate value + var username = string.Empty; // TODO: Initialize to an appropriate value + var instruction = string.Empty; // TODO: Initialize to an appropriate value + var language = string.Empty; // TODO: Initialize to an appropriate value IEnumerable prompts = null; // TODO: Initialize to an appropriate value - AuthenticationPromptEventArgs target = new AuthenticationPromptEventArgs(username, instruction, language, prompts); + var target = new AuthenticationPromptEventArgs(username, instruction, language, prompts); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs b/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs index 763f74094..5fbf25821 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs @@ -17,10 +17,10 @@ public class AuthenticationPromptTest : TestBase [TestMethod] public void AuthenticationPromptConstructorTest() { - int id = 0; // TODO: Initialize to an appropriate value - bool isEchoed = false; // TODO: Initialize to an appropriate value - string request = string.Empty; // TODO: Initialize to an appropriate value - AuthenticationPrompt target = new AuthenticationPrompt(id, isEchoed, request); + var id = 0; // TODO: Initialize to an appropriate value + var isEchoed = false; // TODO: Initialize to an appropriate value + var request = string.Empty; // TODO: Initialize to an appropriate value + var target = new AuthenticationPrompt(id, isEchoed, request); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -30,14 +30,13 @@ public void AuthenticationPromptConstructorTest() [TestMethod] public void ResponseTest() { - int id = 0; // TODO: Initialize to an appropriate value - bool isEchoed = false; // TODO: Initialize to an appropriate value - string request = string.Empty; // TODO: Initialize to an appropriate value - AuthenticationPrompt target = new AuthenticationPrompt(id, isEchoed, request); // TODO: Initialize to an appropriate value - string expected = string.Empty; // TODO: Initialize to an appropriate value - string actual; + var id = 0; // TODO: Initialize to an appropriate value + var isEchoed = false; // TODO: Initialize to an appropriate value + var request = string.Empty; // TODO: Initialize to an appropriate value + var target = new AuthenticationPrompt(id, isEchoed, request); // TODO: Initialize to an appropriate value + var expected = string.Empty; // TODO: Initialize to an appropriate value target.Response = expected; - actual = target.Response; + var actual = target.Response; Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); } diff --git a/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs b/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs index c99fb2a6e..0640697a2 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs @@ -28,7 +28,7 @@ namespace Renci.SshNet.Tests.Classes.Common [TestClass] public class BigIntegerTest { - private static readonly byte[] huge_a = + private static readonly byte[] Huge_a = { 0x1D, 0x33, 0xFB, 0xFE, 0xB1, 0x2, 0x85, 0x44, 0xCA, 0xDC, 0xFB, 0x70, 0xD, 0x39, 0xB1, 0x47, 0xB6, 0xE6, 0xA2, 0xD1, 0x19, 0x1E, 0x9F, 0xE4, 0x3C, 0x1E, 0x16, 0x56, 0x13, 0x9C, 0x4D, 0xD3, @@ -36,7 +36,7 @@ public class BigIntegerTest 0xF6, 0x8C }; - private static readonly byte[] huge_b = + private static readonly byte[] Huge_b = { 0x96, 0x5, 0xDA, 0xFE, 0x93, 0x17, 0xC1, 0x93, 0xEC, 0x2F, 0x30, 0x2D, 0x8F, 0x28, 0x13, 0x99, 0x70, 0xF4, 0x4C, 0x60, 0xA6, 0x49, 0x24, 0xF9, 0xB3, 0x4A, 0x41, 0x67, 0xDC, 0xDD, 0xB1, @@ -44,7 +44,7 @@ public class BigIntegerTest 0xA8, 0xC8, 0xB0, 0x20, 0x95, 0xE6, 0x4C, 0xE1, 0xE0, 0x4B, 0x49, 0xD5, 0x5A, 0xB7 }; - private static readonly byte[] huge_add = + private static readonly byte[] Huge_add = { 0xB3, 0x38, 0xD5, 0xFD, 0x45, 0x1A, 0x46, 0xD8, 0xB6, 0xC, 0x2C, 0x9E, 0x9C, 0x61, 0xC4, 0xE0, 0x26, 0xDB, 0xEF, 0x31, 0xC0, 0x67, 0xC3, 0xDD, 0xF0, 0x68, 0x57, 0xBD, 0xEF, 0x79, 0xFF, @@ -52,7 +52,7 @@ public class BigIntegerTest 0x16, 0xBF, 0x3D, 0x20, 0x95, 0xE6, 0x4C, 0xE1, 0xE0, 0x4B, 0x49, 0xD5, 0x5A, 0xB7 }; - private static readonly byte[] a_m_b = + private static readonly byte[] A_m_b = { 0x87, 0x2D, 0x21, 0x0, 0x1E, 0xEB, 0xC3, 0xB0, 0xDD, 0xAC, 0xCB, 0x43, 0x7E, 0x10, 0x9E, 0xAE, 0x45, 0xF2, 0x55, 0x71, 0x73, 0xD4, 0x7A, 0xEB, 0x88, 0xD3, 0xD4, 0xEE, 0x36, 0xBE, 0x9B, 0x2D, @@ -60,7 +60,7 @@ public class BigIntegerTest 0x2D, 0xDC, 0xDE, 0x6A, 0x19, 0xB3, 0x1E, 0x1F, 0xB4, 0xB6, 0x2A, 0xA5, 0x48 }; - private static readonly byte[] b_m_a = + private static readonly byte[] B_m_a = { 0x79, 0xD2, 0xDE, 0xFF, 0xE1, 0x14, 0x3C, 0x4F, 0x22, 0x53, 0x34, 0xBC, 0x81, 0xEF, 0x61, 0x51, 0xBA, 0xD, 0xAA, 0x8E, 0x8C, 0x2B, 0x85, 0x14, 0x77, 0x2C, 0x2B, 0x11, 0xC9, 0x41, 0x64, @@ -68,7 +68,7 @@ public class BigIntegerTest 0x3B, 0xD2, 0x23, 0x21, 0x95, 0xE6, 0x4C, 0xE1, 0xE0, 0x4B, 0x49, 0xD5, 0x5A, 0xB7 }; - private static readonly byte[] huge_mul = + private static readonly byte[] Huge_mul = { 0xFE, 0x83, 0xE1, 0x9B, 0x8D, 0x61, 0x40, 0xD1, 0x60, 0x19, 0xBD, 0x38, 0xF0, 0xFF, 0x90, 0xAE, 0xDD, 0xAE, 0x73, 0x2C, 0x20, 0x23, 0xCF, 0x6, 0x7A, 0xB4, 0x1C, 0xE7, 0xD9, 0x64, 0x96, @@ -79,18 +79,18 @@ public class BigIntegerTest 0x57, 0x40, 0x51, 0xB6, 0x5D, 0xC, 0x17, 0xD1, 0x86, 0xE9, 0xA4, 0x20 }; - private static readonly byte[] huge_div = {0x0}; + private static readonly byte[] Huge_div = {0x0}; - private static readonly byte[] huge_rem = + private static readonly byte[] Huge_rem = { 0x1D, 0x33, 0xFB, 0xFE, 0xB1, 0x2, 0x85, 0x44, 0xCA, 0xDC, 0xFB, 0x70, 0xD, 0x39, 0xB1, 0x47, 0xB6, 0xE6, 0xA2, 0xD1, 0x19, 0x1E, 0x9F, 0xE4, 0x3C, 0x1E, 0x16, 0x56, 0x13, 0x9C, 0x4D, 0xD3, 0x5C, 0x74, 0xC9, 0xBD, 0xFA, 0x56, 0x40, 0x58, 0xAC, 0x20, 0x6B, 0x55, 0xA2, 0xD5, 0x41, 0x38, 0xA4, 0x6D, 0xF6, 0x8C }; - private static readonly byte[][] add_a = {new byte[] {1}, new byte[] {0xFF}, huge_a}; - private static readonly byte[][] add_b = {new byte[] {1}, new byte[] {1}, huge_b}; - private static readonly byte[][] add_c = {new byte[] {2}, new byte[] {0}, huge_add}; + private static readonly byte[][] Add_a = { new byte[] { 1 }, new byte[] { 0xFF }, Huge_a }; + private static readonly byte[][] Add_b = { new byte[] { 1 }, new byte[] { 1 }, Huge_b }; + private static readonly byte[][] Add_c = { new byte[] { 2 }, new byte[] { 0 }, Huge_add }; private readonly NumberFormatInfo _nfi = NumberFormatInfo.InvariantInfo; private NumberFormatInfo _nfiUser; @@ -98,22 +98,24 @@ public class BigIntegerTest [TestInitialize] public void SetUpFixture() { - _nfiUser = new NumberFormatInfo(); - _nfiUser.CurrencyDecimalDigits = 3; - _nfiUser.CurrencyDecimalSeparator = ":"; - _nfiUser.CurrencyGroupSeparator = "/"; - _nfiUser.CurrencyGroupSizes = new[] { 2, 1, 0 }; - _nfiUser.CurrencyNegativePattern = 10; // n $- - _nfiUser.CurrencyPositivePattern = 3; // n $ - _nfiUser.CurrencySymbol = "XYZ"; - _nfiUser.PercentDecimalDigits = 1; - _nfiUser.PercentDecimalSeparator = ";"; - _nfiUser.PercentGroupSeparator = "~"; - _nfiUser.PercentGroupSizes = new[] { 1 }; - _nfiUser.PercentNegativePattern = 2; - _nfiUser.PercentPositivePattern = 2; - _nfiUser.PercentSymbol = "%%%"; - _nfiUser.NumberDecimalSeparator = "."; + _nfiUser = new NumberFormatInfo + { + CurrencyDecimalDigits = 3, + CurrencyDecimalSeparator = ":", + CurrencyGroupSeparator = "/", + CurrencyGroupSizes = new[] { 2, 1, 0 }, + CurrencyNegativePattern = 10, // n $- + CurrencyPositivePattern = 3, // n $ + CurrencySymbol = "XYZ", + PercentDecimalDigits = 1, + PercentDecimalSeparator = ";", + PercentGroupSeparator = "~", + PercentGroupSizes = new[] { 1 }, + PercentNegativePattern = 2, + PercentPositivePattern = 2, + PercentSymbol = "%%%", + NumberDecimalSeparator = "." + }; } [TestMethod] @@ -136,10 +138,10 @@ public void Mul() [TestMethod] public void TestHugeMul() { - var a = new BigInteger(huge_a); - var b = new BigInteger(huge_b); + var a = new BigInteger(Huge_a); + var b = new BigInteger(Huge_b); - Assert.IsTrue(huge_mul.IsEqualTo((a * b).ToByteArray())); + Assert.IsTrue(Huge_mul.IsEqualTo((a * b).ToByteArray())); } [TestMethod] @@ -152,11 +154,13 @@ public void DivRem() for (var j = 0; j < values.Length; ++j) { if (values[j] == 0) + { continue; + } + var a = new BigInteger(values[i]); var b = new BigInteger(values[j]); - BigInteger d; - var c = BigInteger.DivRem(a, b, out d); + var c = BigInteger.DivRem(a, b, out var d); Assert.AreEqual(values[i] / values[j], (long)c, "#a_" + i + "_" + j); Assert.AreEqual(values[i] % values[j], (long)d, "#b_" + i + "_" + j); @@ -167,13 +171,12 @@ public void DivRem() [TestMethod] public void TestHugeDivRem() { - var a = new BigInteger(huge_a); - var b = new BigInteger(huge_b); - BigInteger d; - var c = BigInteger.DivRem(a, b, out d); + var a = new BigInteger(Huge_a); + var b = new BigInteger(Huge_b); + var c = BigInteger.DivRem(a, b, out var d); - AssertEqual(huge_div, c.ToByteArray()); - AssertEqual(huge_rem, d.ToByteArray()); + AssertEqual(Huge_div, c.ToByteArray()); + AssertEqual(Huge_rem, d.ToByteArray()); } [TestMethod] @@ -181,7 +184,7 @@ public void Pow() { try { - BigInteger.Pow(1, -1); + _ = BigInteger.Pow(1, -1); Assert.Fail("#1"); } catch (ArgumentOutOfRangeException) { } @@ -198,14 +201,14 @@ public void ModPow() { try { - BigInteger.ModPow(1, -1, 5); + _ = BigInteger.ModPow(1, -1, 5); Assert.Fail("#1"); } catch (ArgumentOutOfRangeException) { } try { - BigInteger.ModPow(1, 5, 0); + _ = BigInteger.ModPow(1, 5, 0); Assert.Fail("#2"); } catch (DivideByZeroException) { } @@ -281,8 +284,7 @@ public void DivRemByZero() { try { - BigInteger d; - BigInteger.DivRem(100, 0, out d); + _ = BigInteger.DivRem(100, 0, out var d); Assert.Fail("#1"); } catch (DivideByZeroException) @@ -293,16 +295,16 @@ public void DivRemByZero() [TestMethod] public void TestAdd() { - for (var i = 0; i < add_a.Length; ++i) + for (var i = 0; i < Add_a.Length; ++i) { - var a = new BigInteger(add_a[i]); - var b = new BigInteger(add_b[i]); - var c = new BigInteger(add_c[i]); + var a = new BigInteger(Add_a[i]); + var b = new BigInteger(Add_b[i]); + var c = new BigInteger(Add_c[i]); Assert.AreEqual(c, a + b, "#" + i + "a"); Assert.AreEqual(c, b + a, "#" + i + "b"); Assert.AreEqual(c, BigInteger.Add(a, b), "#" + i + "c"); - AssertEqual(add_c[i], (a + b).ToByteArray()); + AssertEqual(Add_c[i], (a + b).ToByteArray()); } } @@ -326,11 +328,11 @@ public void TestAdd2() [TestMethod] public void TestHugeSub() { - var a = new BigInteger(huge_a); - var b = new BigInteger(huge_b); + var a = new BigInteger(Huge_a); + var b = new BigInteger(Huge_b); - AssertEqual(a_m_b, (a - b).ToByteArray()); - AssertEqual(b_m_a, (b - a).ToByteArray()); + AssertEqual(A_m_b, (a - b).ToByteArray()); + AssertEqual(B_m_a, (b - a).ToByteArray()); } [TestMethod] @@ -732,7 +734,7 @@ public void ByteArrayCtorRoundTrip() [TestMethod] public void TestIntCtorProperties() { - BigInteger a = new BigInteger(10); + var a = new BigInteger(10); Assert.IsTrue(a.IsEven, "#1"); Assert.IsFalse(a.IsOne, "#2"); Assert.IsFalse(a.IsPowerOfTwo, "#3"); @@ -784,11 +786,11 @@ public void TestToStringFmt() [TestMethod] public void TestToStringFmtProvider() { - NumberFormatInfo info = new NumberFormatInfo - { - NegativeSign = ">", - PositiveSign = "%" - }; + var info = new NumberFormatInfo + { + NegativeSign = ">", + PositiveSign = "%" + }; Assert.AreEqual("10", new BigInteger(10).ToString(info), "#1"); Assert.AreEqual(">10", new BigInteger(-10).ToString(info), "#2"); @@ -801,12 +803,16 @@ public void TestToStringFmtProvider() Assert.AreEqual("10", new BigInteger(10).ToString("R", info), "#9"); Assert.AreEqual(">10", new BigInteger(-10).ToString("R", info), "#10"); - info = new NumberFormatInfo(); - info.NegativeSign = "#$%"; + info = new NumberFormatInfo + { + NegativeSign = "#$%" + }; + Assert.AreEqual("#$%10", new BigInteger(-10).ToString(info), "#2"); Assert.AreEqual("#$%10", new BigInteger(-10).ToString(null, info), "#2"); info = new NumberFormatInfo(); + Assert.AreEqual("-10", new BigInteger(-10).ToString(info), "#2"); } @@ -816,21 +822,21 @@ public void TestToIntOperator() { try { - int v = (int)new BigInteger(huge_a); + _ = (int) new BigInteger(Huge_a); Assert.Fail("#1"); } catch (OverflowException) { } try { - int v = (int)new BigInteger(1L + int.MaxValue); + _ = (int) new BigInteger(1L + int.MaxValue); Assert.Fail("#2"); } catch (OverflowException) { } try { - int v = (int)new BigInteger(-1L + int.MinValue); + _ = (int) new BigInteger(-1L + int.MinValue); Assert.Fail("#3"); } catch (OverflowException) { } @@ -845,7 +851,7 @@ public void TestToLongOperator() { try { - long v = (long)new BigInteger(huge_a); + _ = (long) new BigInteger(Huge_a); Assert.Fail("#1"); } catch (OverflowException) { } @@ -853,7 +859,7 @@ public void TestToLongOperator() //long.MaxValue + 1 try { - long v = (long)new BigInteger(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }); + _ = (long) new BigInteger(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }); Assert.Fail("#2"); } catch (OverflowException) { } @@ -861,7 +867,7 @@ public void TestToLongOperator() //TODO long.MinValue - 1 try { - long v = (long)new BigInteger(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF }); + _ = (long) new BigInteger(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF }); Assert.Fail("#3"); } catch (OverflowException) { } @@ -931,14 +937,14 @@ public void ShortOperators() try { - short x = (short)new BigInteger(10000000); + _ = (short) new BigInteger(10000000); Assert.Fail("#3"); } catch (OverflowException) { } try { - short x = (short)new BigInteger(-10000000); + _ = (short) new BigInteger(-10000000); Assert.Fail("#4"); } catch (OverflowException) { } @@ -949,7 +955,7 @@ public void Ctor_Double_NaN() { try { - new BigInteger(double.NaN); + _ = new BigInteger(double.NaN); Assert.Fail(); } catch (OverflowException) @@ -962,7 +968,7 @@ public void Ctor_Double_NegativeInfinity() { try { - new BigInteger(double.NegativeInfinity); + _ = new BigInteger(double.NegativeInfinity); Assert.Fail(); } catch (OverflowException) @@ -975,7 +981,7 @@ public void Ctor_Double_PositiveInfinity() { try { - new BigInteger(double.PositiveInfinity); + _ = new BigInteger(double.PositiveInfinity); Assert.Fail(); } catch (OverflowException) @@ -1019,9 +1025,9 @@ public void DoubleConversion() Assert.AreEqual(result4, (double)new BigInteger(new byte[] { 0, 0, 0, 0, 48, 128, 208, 159, 60, 46, 59, 3 }), "#13"); Assert.AreEqual(result5, (double)new BigInteger(new byte[] { 0, 0, 0, 0, 64, 128, 208, 159, 60, 46, 59, 3 }), "#14"); - Assert.AreEqual(BitConverter.Int64BitsToDouble(-2748107935317889142), (double)new BigInteger(huge_a), "#15"); - Assert.AreEqual(BitConverter.Int64BitsToDouble(-2354774254443231289), (double)new BigInteger(huge_b), "#16"); - Assert.AreEqual(BitConverter.Int64BitsToDouble(8737073938546854790), (double)new BigInteger(huge_mul), "#17"); + Assert.AreEqual(BitConverter.Int64BitsToDouble(-2748107935317889142), (double)new BigInteger(Huge_a), "#15"); + Assert.AreEqual(BitConverter.Int64BitsToDouble(-2354774254443231289), (double)new BigInteger(Huge_b), "#16"); + Assert.AreEqual(BitConverter.Int64BitsToDouble(8737073938546854790), (double)new BigInteger(Huge_mul), "#17"); Assert.AreEqual(BitConverter.Int64BitsToDouble(6912920136897069886), (double)(2278888483353476799 * BigInteger.Pow(2, 451)), "#18"); Assert.AreEqual(double.PositiveInfinity, (double)(843942696292817306 * BigInteger.Pow(2, 965)), "#19"); @@ -1070,14 +1076,14 @@ public void Parse() { try { - BigInteger.Parse(null); + _ = BigInteger.Parse(null); Assert.Fail("#1"); } catch (ArgumentNullException) { } try { - BigInteger.Parse(""); + _ = BigInteger.Parse(""); Assert.Fail("#2"); } catch (FormatException) { } @@ -1085,28 +1091,28 @@ public void Parse() try { - BigInteger.Parse(" "); + _ = BigInteger.Parse(" "); Assert.Fail("#3"); } catch (FormatException) { } try { - BigInteger.Parse("hh"); + _ = BigInteger.Parse("hh"); Assert.Fail("#4"); } catch (FormatException) { } try { - BigInteger.Parse("-"); + _ = BigInteger.Parse("-"); Assert.Fail("#5"); } catch (FormatException) { } try { - BigInteger.Parse("-+"); + _ = BigInteger.Parse("-+"); Assert.Fail("#6"); } catch (FormatException) { } @@ -1137,7 +1143,7 @@ public void Parse() try { - BigInteger.Parse("2E3.0", NumberStyles.AllowExponent); // decimal notation for the exponent + _ = BigInteger.Parse("2E3.0", NumberStyles.AllowExponent); // decimal notation for the exponent Assert.Fail("#25"); } catch (FormatException) @@ -1146,7 +1152,7 @@ public void Parse() try { - Int32.Parse("2" + dsep + "09E1", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent); + _ = int.Parse("2" + dsep + "09E1", NumberStyles.AllowDecimalPoint | NumberStyles.AllowExponent); Assert.Fail("#26"); } catch (OverflowException) @@ -1157,9 +1163,7 @@ public void Parse() [TestMethod] public void TryParse_Value_ShouldReturnFalseWhenValueIsNull() { - BigInteger x; - - var actual = BigInteger.TryParse(null, out x); + var actual = BigInteger.TryParse(null, out var x); Assert.IsFalse(actual); Assert.AreEqual(BigInteger.Zero, x); @@ -1168,9 +1172,7 @@ public void TryParse_Value_ShouldReturnFalseWhenValueIsNull() [TestMethod] public void TryParse_Value() { - BigInteger x; - - Assert.IsFalse(BigInteger.TryParse("", out x)); + Assert.IsFalse(BigInteger.TryParse("", out var x)); Assert.AreEqual(BigInteger.Zero, x); Assert.IsFalse(BigInteger.TryParse(" ", out x)); @@ -1198,9 +1200,7 @@ public void TryParse_Value() [TestMethod] public void TryParse_ValueAndStyleAndProvider() { - BigInteger x; - - Assert.IsFalse(BigInteger.TryParse("null", NumberStyles.None, null, out x)); + Assert.IsFalse(BigInteger.TryParse("null", NumberStyles.None, null, out var x)); Assert.AreEqual(BigInteger.Zero, x); Assert.IsFalse(BigInteger.TryParse("-10", NumberStyles.None, null, out x)); @@ -1252,9 +1252,7 @@ public void TryParse_ValueAndStyleAndProvider() [TestMethod] public void TryParse_ValueAndStyleAndProvider_ShouldReturnFalseWhenValueIsNull() { - BigInteger x; - - var actual = BigInteger.TryParse(null, NumberStyles.Any, CultureInfo.InvariantCulture, out x); + var actual = BigInteger.TryParse(null, NumberStyles.Any, CultureInfo.InvariantCulture, out var x); Assert.IsFalse(actual); Assert.AreEqual(BigInteger.Zero, x); @@ -1284,20 +1282,17 @@ public void TryParseWeirdCulture() { var old = Thread.CurrentThread.CurrentCulture; var cur = (CultureInfo)old.Clone(); - - var ninfo = new NumberFormatInfo - { - NegativeSign = ">", - PositiveSign = "%" - }; - cur.NumberFormat = ninfo; + cur.NumberFormat = new NumberFormatInfo + { + NegativeSign = ">", + PositiveSign = "%" + }; Thread.CurrentThread.CurrentCulture = cur; try { - BigInteger x; - Assert.IsTrue(BigInteger.TryParse("%11", out x)); + Assert.IsTrue(BigInteger.TryParse("%11", out var x)); Assert.AreEqual(11, (int) x); Assert.IsTrue(BigInteger.TryParse(">11", out x)); @@ -1403,7 +1398,7 @@ public void LeftShiftByInt() public void RightShiftByInt() { var v = BigInteger.Parse("230794411440927908251127453634"); - v = v * BigInteger.Pow(2, 70); + v *= BigInteger.Pow(2, 70); Assert.AreEqual("272473948255566133040220955950698177909118065442816", (v >> 0).ToString(), "#0"); Assert.AreEqual("136236974127783066520110477975349088954559032721408", (v >> 1).ToString(), "#1"); @@ -1482,12 +1477,15 @@ public void Bug10887() { BigInteger b = 0; for (var i = 1; i <= 16; i++) - b = b * 256 + i; + { + b = (b * 256) + i; + } + var p = BigInteger.Pow(2, 32); Assert.AreEqual("1339673755198158349044581307228491536", b.ToString()); Assert.AreEqual("1339673755198158349044581307228491536", ((b << 32) / p).ToString()); - Assert.AreEqual("1339673755198158349044581307228491536", (b * p >> 32).ToString()); + Assert.AreEqual("1339673755198158349044581307228491536", ((b * p) >> 32).ToString()); } [TestMethod] @@ -1567,22 +1565,22 @@ public void Bug16526() public void ToArray_Performance() { const int loopCount = 100000000; - var bigInteger = new BigInteger(huge_a); + var bigInteger = new BigInteger(Huge_a); var stopWatch = new Stopwatch(); GC.Collect(); - GC.WaitForFullGCComplete(); + _ = GC.WaitForFullGCComplete(); stopWatch.Start(); for (var i = 0; i < loopCount; i++) { - bigInteger.ToByteArray(); + _ = bigInteger.ToByteArray(); } GC.Collect(); - GC.WaitForFullGCComplete(); + _ = GC.WaitForFullGCComplete(); stopWatch.Stop(); @@ -1599,17 +1597,17 @@ public void Ctor_ByteArray_Performance() var stopWatch = new Stopwatch(); GC.Collect(); - GC.WaitForFullGCComplete(); + _ = GC.WaitForFullGCComplete(); stopWatch.Start(); for (var i = 0; i < loopCount; i++) { - new BigInteger(huge_a); + _ = new BigInteger(Huge_a); } GC.Collect(); - GC.WaitForFullGCComplete(); + _ = GC.WaitForFullGCComplete(); stopWatch.Stop(); @@ -1656,8 +1654,7 @@ public void Zero() public void Random() { var max = "26432534714839143538998938508341375449389492936207135611931371046236385860280414659368073862189301615603000443463893527273703804361856647266218472759410964268979057798543462774631912259980510080575520846081682603934587649566608158932346151315049355432937004801361578344502537300865702429436253728164365180058583916866804254965536833106467354901266304654706123552932560896874808786957654734387252964281680963136344135750381838556467139236094522411774117748615141352874979928570068255439327082539676660277104989857941859821396157749462154431239343148671646397611770487668571604363151098131876313773395912355145689712506"; - BigInteger maxBigInt; - Assert.IsTrue(BigInteger.TryParse(max, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out maxBigInt)); + Assert.IsTrue(BigInteger.TryParse(max, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out var maxBigInt)); var random = BigInteger.One; while (random <= BigInteger.One || random >= maxBigInt) @@ -1670,8 +1667,7 @@ public void Random() public void TestClientExhcangeGenerationItem130() { var test = "1090748135619415929450294929359784500348155124953172211774101106966150168922785639028532473848836817769712164169076432969224698752674677662739994265785437233596157045970922338040698100507861033047312331823982435279475700199860971612732540528796554502867919746776983759391475987142521315878719577519148811830879919426939958487087540965716419167467499326156226529675209172277001377591248147563782880558861083327174154014975134893125116015776318890295960698011614157721282527539468816519319333337503114777192360412281721018955834377615480468479252748867320362385355596601795122806756217713579819870634321561907813255153703950795271232652404894983869492174481652303803498881366210508647263668376514131031102336837488999775744046733651827239395353540348414872854639719294694323450186884189822544540647226987292160693184734654941906936646576130260972193280317171696418971553954161446191759093719524951116705577362073481319296041201283516154269044389257727700289684119460283480452306204130024913879981135908026983868205969318167819680850998649694416907952712904962404937775789698917207356355227455066183815847669135530549755439819480321732925869069136146085326382334628745456398071603058051634209386708703306545903199608523824513729625136659128221100967735450519952404248198262813831097374261650380017277916975324134846574681307337017380830353680623216336949471306191686438249305686413380231046096450953594089375540285037292470929395114028305547452584962074309438151825437902976012891749355198678420603722034900311364893046495761404333938686140037848030916292543273684533640032637639100774502371542479302473698388692892420946478947733800387782741417786484770190108867879778991633218628640533982619322466154883011452291890252336487236086654396093853898628805813177559162076363154436494477507871294119841637867701722166609831201845484078070518041336869808398454625586921201308185638888082699408686536045192649569198110353659943111802300636106509865023943661829436426563007917282050894429388841748885398290707743052973605359277515749619730823773215894755121761467887865327707115573804264519206349215850195195364813387526811742474131549802130246506341207020335797706780705406945275438806265978516209706795702579244075380490231741030862614968783306207869687868108423639971983209077624758080499988275591392787267627182442892809646874228263172435642368588260139161962836121481966092745325488641054238839295138992979335446110090325230955276870524611359124918392740353154294858383359"; - BigInteger prime; - BigInteger.TryParse(test, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out prime); + _ = BigInteger.TryParse(test, NumberStyles.Number, NumberFormatInfo.CurrentInfo, out var prime); BigInteger group = 2; var bitLength = prime.BitLength; @@ -1683,15 +1679,15 @@ public void TestClientExhcangeGenerationItem130() //clientExchangeValue = BigInteger.ModPow(group, randomValue, prime); clientExchangeValue = (group ^ randomValue) % prime; - } while (clientExchangeValue < 1 || clientExchangeValue > (prime - 1)); + } + while (clientExchangeValue < 1 || clientExchangeValue > (prime - 1)); } [TestMethod] public void TestClientExhcangeGenerationGroup1() { var test = "00FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"; - BigInteger prime; - BigInteger.TryParse(test, NumberStyles.AllowHexSpecifier, NumberFormatInfo.CurrentInfo, out prime); + _ = BigInteger.TryParse(test, NumberStyles.AllowHexSpecifier, NumberFormatInfo.CurrentInfo, out var prime); BigInteger group = 2; var bitLength = prime.BitLength; @@ -1703,15 +1699,15 @@ public void TestClientExhcangeGenerationGroup1() //clientExchangeValue = BigInteger.ModPow(group, randomValue, prime); clientExchangeValue = (group ^ randomValue) % prime; - } while (clientExchangeValue < 1 || clientExchangeValue > (prime - 1)); + } + while (clientExchangeValue < 1 || clientExchangeValue > (prime - 1)); } [TestMethod] public void TestClientExhcangeGenerationGroup14() { var test = "00FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF"; - BigInteger prime; - BigInteger.TryParse(test, NumberStyles.AllowHexSpecifier, NumberFormatInfo.CurrentInfo, out prime); + _ = BigInteger.TryParse(test, NumberStyles.AllowHexSpecifier, NumberFormatInfo.CurrentInfo, out var prime); BigInteger group = 2; var bitLength = prime.BitLength; @@ -1723,7 +1719,8 @@ public void TestClientExhcangeGenerationGroup14() //clientExchangeValue = BigInteger.ModPow(group, randomValue, prime); clientExchangeValue = (group ^ randomValue) % prime; - } while (clientExchangeValue < 1 || clientExchangeValue > (prime - 1)); + } + while (clientExchangeValue < 1 || clientExchangeValue > (prime - 1)); } private static void AssertEqual(byte[] a, byte[] b) diff --git a/src/Renci.SshNet.Tests/Classes/Common/ChannelOpenFailedEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/Common/ChannelOpenFailedEventArgsTest.cs index 8a8efdf27..2265a5f79 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/ChannelOpenFailedEventArgsTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/ChannelOpenFailedEventArgsTest.cs @@ -4,10 +4,10 @@ namespace Renci.SshNet.Tests.Classes.Common { /// - /// Provides data for event. + /// Provides data for event. /// [TestClass] public class ChannelOpenFailedEventArgsTest : TestBase { } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs b/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs index 6ab52acef..427e07ccf 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs @@ -1,6 +1,7 @@ 锘縰sing System; using System.Diagnostics; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Renci.SshNet.Tests.Classes.Common @@ -71,7 +72,7 @@ public void Signal_CurrentCountZero() try { - countdownEvent.Signal(); + _ = countdownEvent.Signal(); Assert.Fail(); } catch (InvalidOperationException) @@ -95,7 +96,9 @@ public void Wait_TimeoutInfinite_ShouldBlockUntilCountdownEventIsSet() var expectedSignalCount = _random.Next(5, 20); for (var i = 0; i < (expectedSignalCount - 1); i++) + { countdownEvent.AddCount(); + } var threads = new Thread[expectedSignalCount]; for (var i = 0; i < expectedSignalCount; i++) @@ -103,8 +106,8 @@ public void Wait_TimeoutInfinite_ShouldBlockUntilCountdownEventIsSet() threads[i] = new Thread(() => { Thread.Sleep(sleep); - Interlocked.Increment(ref signalCount); - countdownEvent.Signal(); + _ = Interlocked.Increment(ref signalCount); + _ = countdownEvent.Signal(); }); threads[i].Start(); } @@ -135,17 +138,19 @@ public void Wait_ShouldReturnTrueWhenCountdownEventIsSetBeforeTimeoutExpires() var expectedSignalCount = _random.Next(5, 20); for (var i = 0; i < (expectedSignalCount - 1); i++) + { countdownEvent.AddCount(); + } var threads = new Thread[expectedSignalCount]; for (var i = 0; i < expectedSignalCount; i++) { threads[i] = new Thread(() => - { - Thread.Sleep(sleep); - Interlocked.Increment(ref signalCount); - countdownEvent.Signal(); - }); + { + Thread.Sleep(sleep); + _ = Interlocked.Increment(ref signalCount); + _ = countdownEvent.Signal(); + }); threads[i].Start(); } @@ -175,17 +180,19 @@ public void Wait_ShouldReturnFalseWhenTimeoutExpiresBeforeCountdownEventIsSet() var expectedSignalCount = _random.Next(5, 20); for (var i = 0; i < (expectedSignalCount - 1); i++) + { countdownEvent.AddCount(); + } var threads = new Thread[expectedSignalCount]; for (var i = 0; i < expectedSignalCount; i++) { threads[i] = new Thread(() => - { - Thread.Sleep(sleep); - countdownEvent.Signal(); - Interlocked.Increment(ref signalCount); - }); + { + Thread.Sleep(sleep); + _ = countdownEvent.Signal(); + _ = Interlocked.Increment(ref signalCount); + }); threads[i].Start(); } @@ -198,7 +205,7 @@ public void Wait_ShouldReturnFalseWhenTimeoutExpiresBeforeCountdownEventIsSet() Assert.IsFalse(countdownEvent.IsSet); Assert.IsFalse(countdownEvent.WaitHandle.WaitOne(0)); - countdownEvent.Wait(Session.InfiniteTimeSpan); + _ = countdownEvent.Wait(Session.InfiniteTimeSpan); countdownEvent.Dispose(); } @@ -225,17 +232,19 @@ public void WaitHandle_WaitOne_TimeoutInfinite_ShouldBlockUntilCountdownEventIsS var expectedSignalCount = _random.Next(5, 20); for (var i = 0; i < (expectedSignalCount - 1); i++) + { countdownEvent.AddCount(); + } var threads = new Thread[expectedSignalCount]; for (var i = 0; i < expectedSignalCount; i++) { threads[i] = new Thread(() => - { - Thread.Sleep(sleep); - Interlocked.Increment(ref signalCount); - countdownEvent.Signal(); - }); + { + Thread.Sleep(sleep); + _ = Interlocked.Increment(ref signalCount); + _ = countdownEvent.Signal(); + }); threads[i].Start(); } @@ -265,17 +274,19 @@ public void WaitHandle_WaitOne_ShouldReturnTrueWhenCountdownEventIsSetBeforeTime var expectedSignalCount = _random.Next(5, 20); for (var i = 0; i < (expectedSignalCount - 1); i++) + { countdownEvent.AddCount(); + } var threads = new Thread[expectedSignalCount]; for (var i = 0; i < expectedSignalCount; i++) { threads[i] = new Thread(() => - { - Thread.Sleep(sleep); - Interlocked.Increment(ref signalCount); - countdownEvent.Signal(); - }); + { + Thread.Sleep(sleep); + _ = Interlocked.Increment(ref signalCount); + _ = countdownEvent.Signal(); + }); threads[i].Start(); } @@ -305,17 +316,19 @@ public void WaitHandle_WaitOne_ShouldReturnFalseWhenTimeoutExpiresBeforeCountdow var expectedSignalCount = _random.Next(5, 20); for (var i = 0; i < (expectedSignalCount - 1); i++) + { countdownEvent.AddCount(); + } var threads = new Thread[expectedSignalCount]; for (var i = 0; i < expectedSignalCount; i++) { threads[i] = new Thread(() => - { - Thread.Sleep(sleep); - countdownEvent.Signal(); - Interlocked.Increment(ref signalCount); - }); + { + Thread.Sleep(sleep); + _ = countdownEvent.Signal(); + _ = Interlocked.Increment(ref signalCount); + }); threads[i].Start(); } @@ -328,7 +341,7 @@ public void WaitHandle_WaitOne_ShouldReturnFalseWhenTimeoutExpiresBeforeCountdow Assert.IsFalse(countdownEvent.IsSet); Assert.IsFalse(countdownEvent.WaitHandle.WaitOne(0)); - countdownEvent.Wait(Session.InfiniteTimeSpan); + _ = countdownEvent.Wait(Session.InfiniteTimeSpan); countdownEvent.Dispose(); } diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs index 42fe8fd54..c59fd5843 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs @@ -26,7 +26,7 @@ public void ShouldThrowArgumentNullExceptionWhenLeftIsNull() try { - Extensions.IsEqualTo(left, right); + _ = Extensions.IsEqualTo(left, right); Assert.Fail(); } catch (ArgumentNullException ex) @@ -44,7 +44,7 @@ public void ShouldThrowArgumentNullExceptionWhenRightIsNull() try { - Extensions.IsEqualTo(left, right); + _ = Extensions.IsEqualTo(left, right); Assert.Fail(); } catch (ArgumentNullException ex) @@ -62,7 +62,7 @@ public void ShouldThrowArgumentNullExceptionWhenLeftAndRightAreNull() try { - Extensions.IsEqualTo(left, right); + _ = Extensions.IsEqualTo(left, right); Assert.Fail(); } catch (ArgumentNullException ex) @@ -157,7 +157,7 @@ private static void Performance(byte[] left, byte[] right, int runs) for (var i = 0; i < runs; i++) { - Extensions.IsEqualTo(left, right); + _ = Extensions.IsEqualTo(left, right); } GC.Collect(); diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Pad.cs b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Pad.cs index f39c45ded..ba41dfb39 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Pad.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Pad.cs @@ -1,6 +1,7 @@ -锘縰sing System; -using System.Diagnostics.CodeAnalysis; +锘縰sing System.Diagnostics.CodeAnalysis; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes.Common @@ -13,7 +14,7 @@ public class ExtensionsTest_Pad public void ShouldReturnNotPadded() { byte[] value = {0x0a, 0x0d}; - byte[] padded = value.Pad(2); + var padded = value.Pad(2); Assert.AreEqual(value, padded); Assert.AreEqual(value.Length, padded.Length); } @@ -22,7 +23,7 @@ public void ShouldReturnNotPadded() public void ShouldReturnPadded() { byte[] value = { 0x0a, 0x0d }; - byte[] padded = value.Pad(3); + var padded = value.Pad(3); Assert.AreEqual(value.Length + 1, padded.Length); Assert.AreEqual(0x00, padded[0]); Assert.AreEqual(0x0a, padded[1]); diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToBigInteger2.cs b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToBigInteger2.cs index 1299f17ad..f9299165e 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToBigInteger2.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToBigInteger2.cs @@ -1,12 +1,10 @@ -锘縰sing System; -using System.Diagnostics.CodeAnalysis; -using Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes.Common { [TestClass] - [SuppressMessage("ReSharper", "InvokeAsExtensionMethod")] public class ExtensionsTest_ToBigInteger2 { [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs b/src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs index 845f433ba..13c649bde 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs @@ -15,7 +15,7 @@ public void Create_ByteArrayAndIndentLevel_DataIsNull() try { - PacketDump.Create(data, 0); + _ = PacketDump.Create(data, 0); Assert.Fail(); } catch (ArgumentNullException ex) @@ -32,7 +32,7 @@ public void Create_ByteArrayAndIndentLevel_IndentLevelLessThanZero() try { - PacketDump.Create(data, -1); + _ =PacketDump.Create(data, -1); Assert.Fail(); } catch (ArgumentOutOfRangeException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs index 4c11b432a..6d56807fd 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs @@ -1,7 +1,9 @@ 锘縰sing System; using System.IO; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; @@ -25,7 +27,7 @@ public void Test_PipeStream_Write_Read_Buffer() Assert.AreEqual(stream.Length, testBuffer.Length); - stream.Read(outputBuffer, 0, outputBuffer.Length); + _ = stream.Read(outputBuffer, 0, outputBuffer.Length); Assert.AreEqual(stream.Length, 0); @@ -44,9 +46,9 @@ public void Test_PipeStream_Write_Read_Byte() { stream.Write(testBuffer, 0, testBuffer.Length); Assert.AreEqual(stream.Length, testBuffer.Length); - stream.ReadByte(); + _ = stream.ReadByte(); Assert.AreEqual(stream.Length, testBuffer.Length - 1); - stream.ReadByte(); + _ = stream.ReadByte(); Assert.AreEqual(stream.Length, testBuffer.Length - 2); } } @@ -92,7 +94,7 @@ public void SeekShouldThrowNotSupportedException() try { - target.Seek(offset, origin); + _ = target.Seek(offset, origin); Assert.Fail(); } catch (NotSupportedException) @@ -169,9 +171,9 @@ public void LengthTest() Assert.AreEqual(2L, target.Length); target.WriteByte(0x0a); Assert.AreEqual(3L, target.Length); - target.Read(new byte[2], 0, 2); + _ = target.Read(new byte[2], 0, 2); Assert.AreEqual(1L, target.Length); - target.ReadByte(); + _ = target.ReadByte(); Assert.AreEqual(0L, target.Length); } @@ -195,7 +197,7 @@ public void Position_GetterAlwaysReturnsZero() Assert.AreEqual(0, target.Position); target.WriteByte(0x0a); Assert.AreEqual(0, target.Position); - target.ReadByte(); + _ = target.ReadByte(); Assert.AreEqual(0, target.Position); } @@ -214,4 +216,4 @@ public void Position_SetterAlwaysThrowsNotSupportedException() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs index fb010c14f..ed25b260a 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs @@ -34,7 +34,7 @@ protected override void Act() _pipeStream.Close(); // give async read time to complete - _readThread.Join(100); + _ = _readThread.Join(100); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs index 0b6210046..eb314d4d7 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs @@ -45,7 +45,7 @@ protected override void Act() _pipeStream.Close(); // give write time to complete - _writehread.Join(100); + _ = _writehread.Join(100); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs index 95047cac1..415466af2 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs @@ -30,7 +30,7 @@ protected override void Arrange() _readThread.Start(); // ensure we've started reading - _readThread.Join(50); + _ = _readThread.Join(50); } protected override void Act() @@ -38,7 +38,7 @@ protected override void Act() _pipeStream.Flush(); // give async read time to complete - _readThread.Join(100); + _ = _readThread.Join(100); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs index 44c7f3f71..f306edf1d 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs @@ -34,7 +34,7 @@ protected override void Act() _pipeStream.Flush(); // give async read time to complete - _readThread.Join(100); + _ = _readThread.Join(100); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Common/PortForwardEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/Common/PortForwardEventArgsTest.cs index d0b9860c1..c1f41dd70 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PortForwardEventArgsTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PortForwardEventArgsTest.cs @@ -18,7 +18,7 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenHostIsNull() { try { - new PortForwardEventArgs(null, 80); + _ = new PortForwardEventArgs(null, 80); } catch (ArgumentNullException ex) { @@ -54,7 +54,7 @@ public void ConstructorShouldThrowArgumentOutOfRangeExceptionWhenPortIsGreaterTh try { - new PortForwardEventArgs(Resources.HOST, port); + _ = new PortForwardEventArgs(Resources.HOST, port); Assert.Fail(); } catch (ArgumentOutOfRangeException ex) @@ -64,4 +64,4 @@ public void ConstructorShouldThrowArgumentOutOfRangeExceptionWhenPortIsGreaterTh } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs index 7378a30e3..519c95434 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs @@ -15,7 +15,7 @@ public void Path_Null() try { - PosixPath.CreateAbsoluteOrRelativeFilePath(path); + _ = PosixPath.CreateAbsoluteOrRelativeFilePath(path); Assert.Fail(); } catch (ArgumentNullException ex) @@ -32,7 +32,7 @@ public void Path_Empty() try { - PosixPath.CreateAbsoluteOrRelativeFilePath(path); + _ = PosixPath.CreateAbsoluteOrRelativeFilePath(path); Assert.Fail(); } catch (ArgumentException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetDirectoryName.cs b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetDirectoryName.cs index db1a38e70..0767c11e7 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetDirectoryName.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetDirectoryName.cs @@ -14,7 +14,7 @@ public void Path_Null() try { - PosixPath.GetDirectoryName(path); + _ = PosixPath.GetDirectoryName(path); Assert.Fail(); } catch (ArgumentNullException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs index 3c7d74e2e..d81a13d2d 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs @@ -14,7 +14,7 @@ public void Path_Null() try { - PosixPath.GetFileName(path); + _ = PosixPath.GetFileName(path); Assert.Fail(); } catch (ArgumentNullException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs b/src/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs index 93322c780..17d5e72f2 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs @@ -67,12 +67,11 @@ public void WaitTest() Assert.IsTrue(watch.ElapsedMilliseconds < 50); - var releaseThread = new Thread( - () => - { - Thread.Sleep(sleepTime); - target.Release(); - }); + var releaseThread = new Thread(() => + { + Thread.Sleep(sleepTime); + _ = target.Release(); + }); releaseThread.Start(); target.Wait(); diff --git a/src/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs b/src/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs index b960e4f41..2a305fcb9 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs @@ -1,6 +1,8 @@ 锘縰sing System; using System.Runtime.Serialization; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; @@ -20,7 +22,7 @@ public class SshConnectionExceptionTest : TestBase [TestMethod] public void SshConnectionExceptionConstructorTest() { - SshConnectionException target = new SshConnectionException(); + var target = new SshConnectionException(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -30,8 +32,8 @@ public void SshConnectionExceptionConstructorTest() [TestMethod] public void SshConnectionExceptionConstructorTest1() { - string message = string.Empty; // TODO: Initialize to an appropriate value - SshConnectionException target = new SshConnectionException(message); + var message = string.Empty; // TODO: Initialize to an appropriate value + var target = new SshConnectionException(message); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -41,9 +43,9 @@ public void SshConnectionExceptionConstructorTest1() [TestMethod] public void SshConnectionExceptionConstructorTest2() { - string message = string.Empty; // TODO: Initialize to an appropriate value - DisconnectReason disconnectReasonCode = new DisconnectReason(); // TODO: Initialize to an appropriate value - SshConnectionException target = new SshConnectionException(message, disconnectReasonCode); + var message = string.Empty; // TODO: Initialize to an appropriate value + var disconnectReasonCode = new DisconnectReason(); // TODO: Initialize to an appropriate value + var target = new SshConnectionException(message, disconnectReasonCode); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -53,10 +55,10 @@ public void SshConnectionExceptionConstructorTest2() [TestMethod] public void SshConnectionExceptionConstructorTest3() { - string message = string.Empty; // TODO: Initialize to an appropriate value - DisconnectReason disconnectReasonCode = new DisconnectReason(); // TODO: Initialize to an appropriate value + var message = string.Empty; // TODO: Initialize to an appropriate value + var disconnectReasonCode = new DisconnectReason(); // TODO: Initialize to an appropriate value Exception inner = null; // TODO: Initialize to an appropriate value - SshConnectionException target = new SshConnectionException(message, disconnectReasonCode, inner); + var target = new SshConnectionException(message, disconnectReasonCode, inner); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -67,9 +69,9 @@ public void SshConnectionExceptionConstructorTest3() [Ignore] // placeholder for actual test public void GetObjectDataTest() { - SshConnectionException target = new SshConnectionException(); // TODO: Initialize to an appropriate value + var target = new SshConnectionException(); // TODO: Initialize to an appropriate value SerializationInfo info = null; // TODO: Initialize to an appropriate value - StreamingContext context = new StreamingContext(); // TODO: Initialize to an appropriate value + var context = new StreamingContext(); // TODO: Initialize to an appropriate value target.GetObjectData(info, context); Assert.Inconclusive("A method that does not return a value cannot be verified."); } diff --git a/src/Renci.SshNet.Tests/Classes/Compression/ZlibOpenSshTest.cs b/src/Renci.SshNet.Tests/Classes/Compression/ZlibOpenSshTest.cs index c11e13dcb..b3e166501 100644 --- a/src/Renci.SshNet.Tests/Classes/Compression/ZlibOpenSshTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Compression/ZlibOpenSshTest.cs @@ -1,7 +1,6 @@ -锘縰sing Renci.SshNet.Compression; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using Renci.SshNet; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Compression; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Compression @@ -20,7 +19,7 @@ public class ZlibOpenSshTest : TestBase [TestMethod()] public void ZlibOpenSshConstructorTest() { - ZlibOpenSsh target = new ZlibOpenSsh(); + var target = new ZlibOpenSsh(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -30,7 +29,7 @@ public void ZlibOpenSshConstructorTest() [TestMethod()] public void InitTest() { - ZlibOpenSsh target = new ZlibOpenSsh(); // TODO: Initialize to an appropriate value + var target = new ZlibOpenSsh(); // TODO: Initialize to an appropriate value Session session = null; // TODO: Initialize to an appropriate value target.Init(session); Assert.Inconclusive("A method that does not return a value cannot be verified."); @@ -42,9 +41,8 @@ public void InitTest() [TestMethod()] public void NameTest() { - ZlibOpenSsh target = new ZlibOpenSsh(); // TODO: Initialize to an appropriate value - string actual; - actual = target.Name; + var target = new ZlibOpenSsh(); // TODO: Initialize to an appropriate value + var actual = target.Name; Assert.Inconclusive("Verify the correctness of this test method."); } } diff --git a/src/Renci.SshNet.Tests/Classes/Compression/ZlibStreamTest.cs b/src/Renci.SshNet.Tests/Classes/Compression/ZlibStreamTest.cs index dd1c93bf2..6ee6236c2 100644 --- a/src/Renci.SshNet.Tests/Classes/Compression/ZlibStreamTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Compression/ZlibStreamTest.cs @@ -1,11 +1,12 @@ -锘縰sing Renci.SshNet.Compression; +锘縰sing System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.IO; + +using Renci.SshNet.Compression; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Compression -{ +{ /// ///This is a test class for ZlibStreamTest and is intended ///to contain all ZlibStreamTest Unit Tests @@ -21,8 +22,8 @@ public class ZlibStreamTest : TestBase public void ZlibStreamConstructorTest() { Stream stream = null; // TODO: Initialize to an appropriate value - CompressionMode mode = new CompressionMode(); // TODO: Initialize to an appropriate value - ZlibStream target = new ZlibStream(stream, mode); + var mode = new CompressionMode(); // TODO: Initialize to an appropriate value + var target = new ZlibStream(stream, mode); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -34,11 +35,11 @@ public void ZlibStreamConstructorTest() public void WriteTest() { Stream stream = null; // TODO: Initialize to an appropriate value - CompressionMode mode = new CompressionMode(); // TODO: Initialize to an appropriate value - ZlibStream target = new ZlibStream(stream, mode); // TODO: Initialize to an appropriate value + var mode = new CompressionMode(); // TODO: Initialize to an appropriate value + var target = new ZlibStream(stream, mode); // TODO: Initialize to an appropriate value byte[] buffer = null; // TODO: Initialize to an appropriate value - int offset = 0; // TODO: Initialize to an appropriate value - int count = 0; // TODO: Initialize to an appropriate value + var offset = 0; // TODO: Initialize to an appropriate value + var count = 0; // TODO: Initialize to an appropriate value target.Write(buffer, offset, count); Assert.Inconclusive("A method that does not return a value cannot be verified."); } diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs index edb146808..d1989c3de 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs @@ -1,7 +1,7 @@ 锘縰sing Moq; + using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; -using System.Net; namespace Renci.SshNet.Tests.Classes.Connection { diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionRefusedByServer.cs b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionRefusedByServer.cs index 0583729a5..2a0976197 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionRefusedByServer.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionRefusedByServer.cs @@ -1,11 +1,12 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using System; +锘縰sing System; using System.Diagnostics; using System.Net; using System.Net.Sockets; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -30,18 +31,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _clientSocket?.Dispose(); } protected override void Act() @@ -50,7 +48,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SocketException ex) @@ -86,7 +84,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionSucceeded.cs b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionSucceeded.cs index d2abc7749..433adff45 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionSucceeded.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionSucceeded.cs @@ -1,12 +1,13 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Diagnostics; using System.Net; using System.Net.Sockets; -using System.Threading; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Connection { @@ -41,23 +42,16 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_server != null) - { - _server.Dispose(); - } - - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _server?.Dispose(); + _clientSocket?.Dispose(); } protected override void Act() diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs index 05a69e94b..068169248 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs @@ -1,6 +1,6 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using System.Net.Sockets; +锘縰sing System.Net.Sockets; + +using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Renci.SshNet.Tests.Classes.Connection { @@ -22,7 +22,7 @@ protected override void Act() { try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SocketException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs index 44cfe62c6..661b286ae 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs @@ -1,13 +1,15 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Diagnostics; using System.Globalization; using System.Net; using System.Net.Sockets; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -34,18 +36,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _clientSocket?.Dispose(); } protected override void Act() @@ -54,7 +53,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SshOperationTimeoutException ex) @@ -91,7 +90,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ConnectionToProxyRefused.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ConnectionToProxyRefused.cs index e507b92b7..518303329 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ConnectionToProxyRefused.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ConnectionToProxyRefused.cs @@ -1,6 +1,7 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.Common; + using System; using System.Diagnostics; using System.Net; @@ -28,8 +29,10 @@ protected override void SetupData() 8122, "proxyUser", "proxyPwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(5000); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(5000) + }; _stopWatch = new Stopwatch(); _actualException = null; @@ -38,18 +41,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _clientSocket?.Dispose(); } protected override void Act() @@ -58,7 +58,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SocketException ex) @@ -94,7 +94,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs index cd577ec9c..ece0aa9e1 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs @@ -30,8 +30,10 @@ protected override void SetupData() 8122, "proxyUser", "proxyPwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(100); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(100) + }; _actualException = null; _clientSocket = SocketFactory.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); @@ -47,30 +49,23 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } - - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _proxyServer?.Dispose(); + _clientSocket?.Dispose(); } protected override void Act() { try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (ProxyException ex) @@ -101,7 +96,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs index 5843947dc..59524ffd7 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs @@ -29,7 +29,7 @@ protected override void Act() { try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SocketException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs index 59fb77aaa..9a7e876a5 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs @@ -1,7 +1,4 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Globalization; using System.Net; @@ -9,6 +6,12 @@ using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -34,8 +37,10 @@ protected override void SetupData() 8122, "proxyUser", string.Empty, - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(20); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(20) + }; _expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" + "Proxy-Authorization: Basic cHJveHlVc2VyOg=={2}{2}", _connectionInfo.Host, @@ -49,13 +54,14 @@ protected override void SetupData() _proxyServer.Disconnected += (socket) => _disconnected = true; _proxyServer.Connected += socket => { - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n")); - socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); - socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); - socket.Shutdown(SocketShutdown.Send); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); + + socket.Shutdown(SocketShutdown.Send); }; _proxyServer.BytesReceived += (bytesReceived, socket) => { @@ -66,18 +72,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _proxyServer?.Dispose(); if (_clientSocket != null) { diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs index dd267ef5d..ccbf2b751 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs @@ -34,8 +34,10 @@ protected override void SetupData() 8122, "proxyUser", null, - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(20); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(20) + }; _expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" + "Proxy-Authorization: Basic cHJveHlVc2VyOg=={2}{2}", _connectionInfo.Host, @@ -49,12 +51,13 @@ protected override void SetupData() _proxyServer.Disconnected += (socket) => _disconnected = true; _proxyServer.Connected += socket => { - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n")); - socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); - socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); + socket.Shutdown(SocketShutdown.Send); }; _proxyServer.BytesReceived += (bytesReceived, socket) => @@ -66,18 +69,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _proxyServer?.Dispose(); if (_clientSocket != null) { diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs index 77f9091ad..eebb70faf 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs @@ -1,14 +1,17 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -33,8 +36,10 @@ protected override void SetupData() 8122, "proxyUser", "proxyPwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(100); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(100) + }; _bytesReceivedByProxy = new List(); _actualException = null; @@ -46,7 +51,8 @@ protected override void SetupData() { if (_bytesReceivedByProxy.Count == 0) { - socket.Send(Encoding.ASCII.GetBytes("Whatever\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("Whatever\r\n")); + socket.Shutdown(SocketShutdown.Send); } @@ -57,25 +63,22 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _proxyServer?.Dispose(); } protected override void Act() { try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (ProxyException ex) @@ -106,7 +109,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs index da56fa458..f2287807a 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs @@ -1,7 +1,4 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Globalization; using System.Net; @@ -9,6 +6,12 @@ using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -34,8 +37,10 @@ protected override void SetupData() 8122, "proxyUser", "proxyPwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(20); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(20) + }; _expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" + "Proxy-Authorization: Basic cHJveHlVc2VyOnByb3h5UHdk{2}{2}", _connectionInfo.Host, @@ -56,12 +61,13 @@ protected override void SetupData() // it sends the CONNECT request if (_bytesReceivedByProxy.Count == _expectedHttpRequest.Length) { - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n")); - socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); - socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); + socket.Shutdown(SocketShutdown.Send); } }; @@ -70,18 +76,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _proxyServer?.Dispose(); if (_clientSocket != null) { diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs index e89547b66..765e7f81a 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs @@ -1,7 +1,4 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Globalization; using System.Net; @@ -9,6 +6,12 @@ using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -34,8 +37,10 @@ protected override void SetupData() 8122, "proxyUser", "proxyPwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(20); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(20) + }; _expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" + "Proxy-Authorization: Basic cHJveHlVc2VyOnByb3h5UHdk{2}{2}", _connectionInfo.Host, @@ -56,12 +61,13 @@ protected override void SetupData() // it sends the CONNECT request if (_bytesReceivedByProxy.Count == _expectedHttpRequest.Length) { - socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); - socket.Send(Encoding.ASCII.GetBytes("Content-Length: 10\r\n")); - socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("TEEN_BYTES")); - socket.Send(Encoding.ASCII.GetBytes("!666!")); + _ = socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("Content-Length: 10\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("TEEN_BYTES")); + _ = socket.Send(Encoding.ASCII.GetBytes("!666!")); + socket.Shutdown(SocketShutdown.Send); } }; @@ -70,18 +76,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _proxyServer?.Dispose(); if (_clientSocket != null) { diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs index 30cca421e..17da268c6 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs @@ -34,8 +34,10 @@ protected override void SetupData() 8122, "proxyUser", "proxyPwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(20); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(20) + }; _expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" + "Proxy-Authorization: Basic cHJveHlVc2VyOnByb3h5UHdk{2}{2}", _connectionInfo.Host, @@ -56,10 +58,11 @@ protected override void SetupData() // it sends the CONNECT request if (_bytesReceivedByProxy.Count == _expectedHttpRequest.Length) { - socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); - socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); + _ = socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); + socket.Shutdown(SocketShutdown.Send); } }; @@ -68,18 +71,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _proxyServer?.Dispose(); if (_clientSocket != null) { diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs index 8edca1811..b2cdc5fd3 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs @@ -1,14 +1,17 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -33,8 +36,10 @@ protected override void SetupData() 8122, "proxyUser", "proxyPwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(100); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(100) + }; _bytesReceivedByProxy = new List(); _actualException = null; @@ -46,7 +51,8 @@ protected override void SetupData() { if (_bytesReceivedByProxy.Count == 0) { - socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 404 I searched everywhere, really...\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 404 I searched everywhere, really...\r\n")); + socket.Shutdown(SocketShutdown.Send); } @@ -57,25 +63,22 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _proxyServer?.Dispose(); } protected override void Act() { try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (ProxyException ex) @@ -106,7 +109,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs index d6b71bd04..455a41a9f 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs @@ -1,7 +1,4 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Globalization; using System.Net; @@ -9,6 +6,12 @@ using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -34,8 +37,10 @@ protected override void SetupData() 8122, string.Empty, "proxyPwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(20); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(20) + }; _expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}{2}", _connectionInfo.Host, _connectionInfo.Port.ToString(CultureInfo.InvariantCulture), @@ -55,12 +60,12 @@ protected override void SetupData() // it sends the CONNECT request if (_bytesReceivedByProxy.Count == _expectedHttpRequest.Length) { - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n")); - socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); - socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); } }; _proxyServer.Start(); @@ -68,23 +73,16 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } - - if (_clientSocket != null) - { - _clientSocket.Close(); - } + _proxyServer?.Dispose(); + _clientSocket?.Close(); } protected override void Act() diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs index a12558714..b49d1b12a 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs @@ -1,7 +1,4 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Globalization; using System.Net; @@ -9,6 +6,12 @@ using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -34,8 +37,10 @@ protected override void SetupData() 8122, "user", "pwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(20); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(20) + }; _expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" + "Proxy-Authorization: Basic dXNlcjpwd2Q={2}{2}", _connectionInfo.Host, @@ -48,10 +53,10 @@ protected override void SetupData() _proxyServer = new AsyncSocketListener(new IPEndPoint(IPAddress.Loopback, _connectionInfo.ProxyPort)); _proxyServer.Connected += (socket) => { - socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); - socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); + _ = socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); }; _proxyServer.Disconnected += (socket) => _disconnected = true; _proxyServer.BytesReceived += (bytesReceived, socket) => @@ -63,18 +68,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _proxyServer?.Dispose(); if (_clientSocket != null) { diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs index 0e11e189b..59a022bc8 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs @@ -1,7 +1,4 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Globalization; using System.Net; @@ -9,6 +6,12 @@ using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -34,8 +37,10 @@ protected override void SetupData() 8122, null, "proxyPwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(20); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(20) + }; _expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}{2}", _connectionInfo.Host, _connectionInfo.Port.ToString(CultureInfo.InvariantCulture), @@ -55,12 +60,12 @@ protected override void SetupData() // it sends the CONNECT request if (_bytesReceivedByProxy.Count == _expectedHttpRequest.Length) { - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n")); - socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); - socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("SSH.NET\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("SSH4EVER")); } }; _proxyServer.Start(); @@ -68,8 +73,8 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() @@ -82,10 +87,7 @@ protected override void TearDown() _clientSocket.Close(); } - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _proxyServer?.Dispose(); } protected override void Act() diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs index 61e35cf36..bb8041c89 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs @@ -1,12 +1,15 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using System; +锘縰sing System; using System.Diagnostics; using System.Globalization; using System.Net; using System.Net.Sockets; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -31,8 +34,10 @@ protected override void SetupData() 8122, "proxyUser", "proxyPwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200)); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200)) + }; _stopWatch = new Stopwatch(); _actualException = null; @@ -41,18 +46,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _clientSocket?.Dispose(); } protected override void Act() @@ -61,7 +63,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SshOperationTimeoutException ex) @@ -98,7 +100,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs index 9c219c016..5db6b2353 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs @@ -1,9 +1,4 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Connection; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; @@ -12,6 +7,14 @@ using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; +using Renci.SshNet.Connection; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -41,8 +44,10 @@ protected override void SetupData() 8122, "proxyUser", "proxyPwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200)); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200)) + }; _expectedHttpRequest = string.Format("CONNECT {0}:{1} HTTP/1.0{2}" + "Proxy-Authorization: Basic cHJveHlVc2VyOnByb3h5UHdk{2}{2}", _connectionInfo.Host, @@ -63,11 +68,11 @@ protected override void SetupData() // Force a timeout by sending less content than indicated by Content-Length header if (_bytesReceivedByProxy.Count == _expectedHttpRequest.Length) { - socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); - socket.Send(Encoding.ASCII.GetBytes("Content-Length: 10\r\n")); - socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); - socket.Send(Encoding.ASCII.GetBytes("\r\n")); - socket.Send(Encoding.ASCII.GetBytes("TOO_FEW")); + _ = socket.Send(Encoding.ASCII.GetBytes("HTTP/1.0 200 OK\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("Content-Length: 10\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("Content-Type: application/octet-stream\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("\r\n")); + _ = socket.Send(Encoding.ASCII.GetBytes("TOO_FEW")); } }; _proxyServer.Start(); @@ -78,23 +83,16 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_server != null) - { - _server.Dispose(); - } - - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _server?.Dispose(); + _proxyServer?.Dispose(); } protected override void Act() @@ -103,7 +101,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SshOperationTimeoutException ex) @@ -156,7 +154,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs index a05212312..10aa8bd91 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs @@ -1,15 +1,18 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Connection; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Diagnostics; using System.Globalization; using System.Net; using System.Net.Sockets; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; +using Renci.SshNet.Connection; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -37,8 +40,10 @@ protected override void SetupData() 8122, "proxyUser", "proxyPwd", - new KeyboardInteractiveAuthenticationMethod("user")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200)); + new KeyboardInteractiveAuthenticationMethod("user")) + { + Timeout = TimeSpan.FromMilliseconds(random.Next(50, 200)) + }; _stopWatch = new Stopwatch(); _actualException = null; @@ -54,23 +59,16 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_server != null) - { - _server.Dispose(); - } - - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _server?.Dispose(); + _proxyServer?.Dispose(); } protected override void Act() @@ -79,7 +77,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SshOperationTimeoutException ex) @@ -126,7 +124,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs index b97ba5f8f..3b0649517 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs @@ -1,8 +1,4 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Connection; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -10,6 +6,12 @@ using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Common; +using Renci.SshNet.Connection; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -63,7 +65,9 @@ protected void Arrange() _server.BytesReceived += (bytes, socket) => { _dataReceivedByServer.AddRange(bytes); - socket.Send(_serverIdentification); + + _ = socket.Send(_serverIdentification); + socket.Shutdown(SocketShutdown.Send); }; _server.Disconnected += (socket) => _clientDisconnected = true; @@ -78,7 +82,7 @@ protected void Act() { try { - _protocolVersionExchange.Start(_clientVersion, _client, _timeout); + _ = _protocolVersionExchange.Start(_clientVersion, _client, _timeout); Assert.Fail(); } catch (SshConnectionException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs index f66afe057..7aa26b309 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs @@ -1,8 +1,4 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Connection; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -10,6 +6,12 @@ using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Common; +using Renci.SshNet.Connection; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -61,11 +63,13 @@ protected void Arrange() _server = new AsyncSocketListener(_serverEndPoint); _server.Start(); _server.BytesReceived += (bytes, socket) => - { - _dataReceivedByServer.AddRange(bytes); - socket.Send(_serverIdentification); - socket.Shutdown(SocketShutdown.Send); - }; + { + _dataReceivedByServer.AddRange(bytes); + + _ = socket.Send(_serverIdentification); + + socket.Shutdown(SocketShutdown.Send); + }; _server.Disconnected += (socket) => _clientDisconnected = true; _client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs index 238d7e337..3710e2064 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs @@ -1,8 +1,4 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Connection; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -10,6 +6,12 @@ using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Common; +using Renci.SshNet.Connection; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -61,7 +63,8 @@ protected void Arrange() _server.BytesReceived += (bytes, socket) => { _dataReceivedByServer.AddRange(bytes); - socket.Send(Encoding.UTF8.GetBytes("Welcome!\r\n")); + + _ = socket.Send(Encoding.UTF8.GetBytes("Welcome!\r\n")); }; _server.Disconnected += (socket) => _clientDisconnected = true; @@ -75,7 +78,7 @@ protected void Act() { try { - _protocolVersionExchange.Start(_clientVersion, _client, _timeout); + _ = _protocolVersionExchange.Start(_clientVersion, _client, _timeout); Assert.Fail(); } catch (SshOperationTimeoutException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs index 16dc70006..0c3497f12 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs @@ -1,8 +1,9 @@ -锘縰sing Moq; +锘縰sing System.Net; + +using Moq; + using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; -using System.Net; -using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs index e993fa573..a220b9423 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs @@ -1,13 +1,16 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -36,7 +39,7 @@ protected override void SetupData() { if (_bytesReceivedByProxy.Count == 0) { - socket.Send(new byte[] + _ = socket.Send(new byte[] { // Reply version (null byte) 0x00, @@ -52,30 +55,23 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } - - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _proxyServer?.Dispose(); + _clientSocket?.Dispose(); } protected override void Act() { try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (ProxyException ex) @@ -106,7 +102,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) @@ -120,19 +116,5 @@ public void CreateOnSocketFactoryShouldHaveBeenInvokedOnce() SocketFactoryMock.Verify(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp), Times.Once()); } - - private static byte GetNotSupportedSocksVersion() - { - var random = new Random(); - - while (true) - { - var socksVersion = random.Next(1, 255); - if (socksVersion != 4) - { - return (byte) socksVersion; - } - } - } } } diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs index f4c97c639..b482b753c 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs @@ -1,15 +1,18 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Connection; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; +using Renci.SshNet.Connection; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -43,7 +46,7 @@ protected override void SetupData() if (_bytesReceivedByProxy.Count == bytesReceived.Length) { // Send SOCKS response - socket.Send(new byte[] + _ = socket.Send(new byte[] { // Reply version (null byte) 0x00, @@ -60,7 +63,7 @@ protected override void SetupData() }); // Send extra byte to allow us to verify that connector did not consume too much - socket.Send(new byte[] + _ = socket.Send(new byte[] { 0xfe }); @@ -71,23 +74,16 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } - - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _proxyServer?.Dispose(); + _clientSocket?.Dispose(); } protected override void Act() diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionToProxyRefused.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionToProxyRefused.cs index 176a5a57b..7c41d93d0 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionToProxyRefused.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionToProxyRefused.cs @@ -1,10 +1,11 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using System; +锘縰sing System; using System.Diagnostics; using System.Net.Sockets; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -29,18 +30,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _clientSocket?.Dispose(); } protected override void Act() @@ -49,7 +47,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SocketException ex) @@ -85,7 +83,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs index 7c7ad08f4..d7ad42157 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs @@ -31,18 +31,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _clientSocket?.Dispose(); } protected override void Act() @@ -51,7 +48,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SshOperationTimeoutException ex) @@ -88,7 +85,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs index 0981e13a9..d8121e894 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs @@ -1,15 +1,18 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Connection; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Diagnostics; using System.Globalization; using System.Net; using System.Net.Sockets; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; +using Renci.SshNet.Connection; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -40,7 +43,7 @@ protected override void SetupData() _proxyServer.Disconnected += socket => _disconnected = true; _proxyServer.Connected += socket => { - socket.Send(new byte[] + _ = socket.Send(new byte[] { // Reply version (null byte) 0x00, @@ -58,23 +61,16 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_server != null) - { - _server.Dispose(); - } - - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _server?.Dispose(); + _proxyServer?.Dispose(); } protected override void Act() @@ -83,7 +79,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SshOperationTimeoutException ex) @@ -130,7 +126,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs index cdcc667ec..1aaa36e4a 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs @@ -1,15 +1,18 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Connection; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Diagnostics; using System.Globalization; using System.Net; using System.Net.Sockets; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; +using Renci.SshNet.Connection; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -40,7 +43,7 @@ protected override void SetupData() _proxyServer.Disconnected += socket => _disconnected = true; _proxyServer.Connected += socket => { - socket.Send(new byte[] + _ = socket.Send(new byte[] { // Reply version (null byte) 0x00 @@ -54,23 +57,16 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_server != null) - { - _server.Dispose(); - } - - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _server?.Dispose(); + _proxyServer?.Dispose(); } protected override void Act() @@ -79,7 +75,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SshOperationTimeoutException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs index 15751c79a..37b7f8389 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs @@ -46,23 +46,16 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_server != null) - { - _server.Dispose(); - } - - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _server?.Dispose(); + _proxyServer?.Dispose(); } protected override void Act() @@ -71,7 +64,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SshOperationTimeoutException ex) @@ -118,7 +111,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs index 9125fb34e..fefe5728e 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs @@ -1,10 +1,11 @@ 锘縰sing Moq; + using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; + using System; using System.Net; using System.Text; -using System.Threading; namespace Renci.SshNet.Tests.Classes.Connection { @@ -59,8 +60,8 @@ protected static string GenerateRandomString(int minLength, int maxLength) for (var i = 0; i < length; i++) { - var @char = (char) random.Next(offset, offset + 26); - sb.Append(@char); + var c = (char) random.Next(offset, offset + 26); + _ = sb.Append(c); } return sb.ToString(); diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ConnectionToProxyRefused.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ConnectionToProxyRefused.cs index 82e195fb4..05bd850dc 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ConnectionToProxyRefused.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ConnectionToProxyRefused.cs @@ -1,11 +1,11 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using System; +锘縰sing System; using System.Diagnostics; -using System.Net; using System.Net.Sockets; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -30,18 +30,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _clientSocket?.Dispose(); } protected override void Act() @@ -50,7 +47,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SocketException ex) @@ -86,7 +83,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs index 61afbf71c..e51548840 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs @@ -39,7 +39,7 @@ protected override void SetupData() { // We received the greeting - socket.Send(new byte[] + _ = socket.Send(new byte[] { // SOCKS version 0x05, @@ -51,7 +51,7 @@ protected override void SetupData() { // We received the connection request - socket.Send(new byte[] + _ = socket.Send(new byte[] { // SOCKS version 0x05, @@ -62,7 +62,7 @@ protected override void SetupData() }); // Send server bound address - socket.Send(new byte[] + _ = socket.Send(new byte[] { // IPv6 0x04, @@ -89,7 +89,7 @@ protected override void SetupData() }); // Send extra byte to allow us to verify that connector did not consume too much - socket.Send(new byte[] + _ = socket.Send(new byte[] { 0xff }); @@ -100,18 +100,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _proxyServer?.Dispose(); if (_clientSocket != null) { diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs index e90bd32c1..76cd2568f 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs @@ -1,12 +1,15 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Net; using System.Net.Sockets; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -34,37 +37,30 @@ protected override void SetupData() _proxyServer.Disconnected += socket => _disconnected = true; _proxyServer.BytesReceived += (bytesReceived, socket) => { - socket.Send(new byte[] { _proxySocksVersion }); + _ = socket.Send(new byte[] { _proxySocksVersion }); }; _proxyServer.Start(); } protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } - - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _proxyServer?.Dispose(); + _clientSocket?.Dispose(); } protected override void Act() { try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (ProxyException ex) @@ -95,7 +91,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs index e93d8dc55..720c24ff9 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs @@ -1,12 +1,14 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using System; +锘縰sing System; using System.Diagnostics; using System.Globalization; -using System.Net; using System.Net.Sockets; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -33,18 +35,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _clientSocket?.Dispose(); } protected override void Act() @@ -53,7 +52,7 @@ protected override void Act() try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (SshOperationTimeoutException ex) @@ -90,7 +89,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs index a76a100e2..e6bcf5abe 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs @@ -42,7 +42,7 @@ protected override void SetupData() { // We received the greeting - socket.Send(new byte[] + _ = socket.Send(new byte[] { // SOCKS version 0x05, @@ -54,7 +54,7 @@ protected override void SetupData() { // We received the username/password authentication request - socket.Send(new byte[] + _ = socket.Send(new byte[] { // Authentication version 0x01, @@ -68,30 +68,23 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } - - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _proxyServer?.Dispose(); + _clientSocket?.Dispose(); } protected override void Act() { try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (ProxyException ex) @@ -163,7 +156,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs index a9f7e4ef1..0c13af50d 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs @@ -1,8 +1,4 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Linq; using System.Net; @@ -10,6 +6,13 @@ using System.Text; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -40,7 +43,7 @@ protected override void SetupData() { // We received the greeting - socket.Send(new byte[] + _ = socket.Send(new byte[] { // SOCKS version 0x05, @@ -52,7 +55,7 @@ protected override void SetupData() { // We received the username/password authentication request - socket.Send(new byte[] + _ = socket.Send(new byte[] { // Authentication version 0x01, @@ -64,7 +67,7 @@ protected override void SetupData() { // We received the connection request - socket.Send(new byte[] + _ = socket.Send(new byte[] { // SOCKS version 0x05, @@ -75,7 +78,7 @@ protected override void SetupData() }); // Send server bound address - socket.Send(new byte[] + _ = socket.Send(new byte[] { // IPv4 0x01, @@ -90,7 +93,7 @@ protected override void SetupData() }); // Send extra byte to allow us to verify that connector did not consume too much - socket.Send(new byte[] + _ = socket.Send(new byte[] { 0xfe }); @@ -101,18 +104,15 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } + _proxyServer?.Dispose(); if (_clientSocket != null) { diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs index 5e1d5389b..b36a7eff9 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs @@ -41,7 +41,7 @@ protected override void SetupData() // Wait until we received the greeting if (_bytesReceivedByProxy.Count == 4) { - socket.Send(new byte[] + _ = socket.Send(new byte[] { // SOCKS version 0x05, @@ -55,30 +55,23 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } - - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _proxyServer?.Dispose(); + _clientSocket?.Dispose(); } protected override void Act() { try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (ProxyException ex) @@ -135,7 +128,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs index 653b41181..83a58f89e 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs @@ -1,14 +1,17 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; -using System; +锘縰sing System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Moq; + +using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; + namespace Renci.SshNet.Tests.Classes.Connection { [TestClass] @@ -41,7 +44,7 @@ protected override void SetupData() // Wait until we received the greeting if (_bytesReceivedByProxy.Count == 4) { - socket.Send(new byte[] + _ = socket.Send(new byte[] { // SOCKS version 0x05, @@ -55,30 +58,23 @@ protected override void SetupData() protected override void SetupMocks() { - SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - .Returns(_clientSocket); + _ = SocketFactoryMock.Setup(p => p.Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + .Returns(_clientSocket); } protected override void TearDown() { base.TearDown(); - if (_proxyServer != null) - { - _proxyServer.Dispose(); - } - - if (_clientSocket != null) - { - _clientSocket.Dispose(); - } + _proxyServer?.Dispose(); + _clientSocket?.Dispose(); } protected override void Act() { try { - Connector.Connect(_connectionInfo); + _ = Connector.Connect(_connectionInfo); Assert.Fail(); } catch (ProxyException ex) @@ -101,20 +97,18 @@ public void ConnectShouldHaveThrownProxyException() [TestMethod] public void ProxyShouldHaveReceivedExpectedSocksRequest() { - var expectedSocksRequest = new List(); - - // // Client greeting - // - - // SOCKS version - expectedSocksRequest.Add(0x05); - // Number of authentication methods supported - expectedSocksRequest.Add(0x02); - // No authentication - expectedSocksRequest.Add(0x00); - // Username/password - expectedSocksRequest.Add(0x02); + var expectedSocksRequest = new List + { + // SOCKS version + 0x05, + // Number of authentication methods supported + 0x02, + // No authentication + 0x00, + // Username/password + 0x02 + }; var errorText = string.Format("Expected:{0}{1}{0}but was:{0}{2}", Environment.NewLine, @@ -135,7 +129,7 @@ public void ClientSocketShouldHaveBeenDisposed() { try { - _clientSocket.Receive(new byte[0]); + _ = _clientSocket.Receive(new byte[0]); Assert.Fail(); } catch (ObjectDisposedException) diff --git a/src/Renci.SshNet.Tests/Classes/Connection/SshIdentificationTest.cs b/src/Renci.SshNet.Tests/Classes/Connection/SshIdentificationTest.cs index 2a7137aed..3d18cfa53 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/SshIdentificationTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/SshIdentificationTest.cs @@ -27,7 +27,7 @@ public void Ctor_ProtocolVersionAndSoftwareVersion_ProtocolVersionIsNull() try { - new SshIdentification(protocolVersion, softwareVersion); + _ = new SshIdentification(protocolVersion, softwareVersion); Assert.Fail(); } catch (ArgumentNullException ex) @@ -45,7 +45,7 @@ public void Ctor_ProtocolVersionAndSoftwareVersion_SoftwareVersionIsNull() try { - new SshIdentification(protocolVersion, softwareVersion); + _ = new SshIdentification(protocolVersion, softwareVersion); Assert.Fail(); } catch (ArgumentNullException ex) @@ -90,7 +90,7 @@ public void Ctor_ProtocolVersionAndSoftwareVersionAndComments_ProtocolVersionIsN try { - new SshIdentification(protocolVersion, softwareVersion, comments); + _ = new SshIdentification(protocolVersion, softwareVersion, comments); Assert.Fail(); } catch (ArgumentNullException ex) @@ -109,7 +109,7 @@ public void Ctor_ProtocolVersionAndSoftwareVersionAndComments_SoftwareVersionIsN try { - new SshIdentification(protocolVersion, softwareVersion, comments); + _ = new SshIdentification(protocolVersion, softwareVersion, comments); Assert.Fail(); } catch (ArgumentNullException ex) diff --git a/src/Renci.SshNet.Tests/Classes/ConnectionInfoTest.cs b/src/Renci.SshNet.Tests/Classes/ConnectionInfoTest.cs index 5fc1cd832..c6b19ca49 100644 --- a/src/Renci.SshNet.Tests/Classes/ConnectionInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ConnectionInfoTest.cs @@ -33,9 +33,15 @@ public void ConstructorShouldThrowArgumentNullExceptionhenProxyTypesIsNotNoneAnd { try { - new ConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, ProxyTypes.Http, null, - int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD, - new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME)); + _ = new ConnectionInfo(Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + ProxyTypes.Http, + null, + int.Parse(Resources.PORT), + Resources.USERNAME, + Resources.PASSWORD, + new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME)); Assert.Fail(); } catch (ArgumentNullException ex) @@ -51,8 +57,14 @@ public void ConstructorShouldNotThrowExceptionWhenProxyTypesIsNotNoneAndProxyHos { var proxyHost = string.Empty; - var connectionInfo = new ConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, - ProxyTypes.Http, string.Empty, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD, + var connectionInfo = new ConnectionInfo(Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + ProxyTypes.Http, + string.Empty, + int.Parse(Resources.PORT), + Resources.USERNAME, + Resources.PASSWORD, new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME)); Assert.AreSame(proxyHost, connectionInfo.ProxyHost); @@ -66,7 +78,15 @@ public void ConstructorShouldThrowArgumentOutOfRangeExceptionWhenProxyTypesIsNot try { - new ConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, ProxyTypes.Http, Resources.HOST, ++maxPort, Resources.USERNAME, Resources.PASSWORD, null); + _ = new ConnectionInfo(Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + ProxyTypes.Http, + Resources.HOST, + ++maxPort, + Resources.USERNAME, + Resources.PASSWORD, + null); Assert.Fail(); } catch (ArgumentOutOfRangeException ex) @@ -84,7 +104,15 @@ public void ConstructorShouldThrowArgumentOutOfRangeExceptionWhenProxyTypesIsNot try { - new ConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, ProxyTypes.Http, Resources.HOST, --minPort, Resources.USERNAME, Resources.PASSWORD, null); + _ = new ConnectionInfo(Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + ProxyTypes.Http, + Resources.HOST, + --minPort, + Resources.USERNAME, + Resources.PASSWORD, + null); Assert.Fail(); } catch (ArgumentOutOfRangeException ex) @@ -126,8 +154,15 @@ public void ConstructorShouldThrowArgumentNullExceptionhenHostIsNull() { try { - new ConnectionInfo(null, int.Parse(Resources.PORT), Resources.USERNAME, ProxyTypes.None, Resources.HOST, - int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD, null); + _ = new ConnectionInfo(null, + int.Parse(Resources.PORT), + Resources.USERNAME, + ProxyTypes.None, + Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + Resources.PASSWORD, + null); } catch (ArgumentNullException ex) { @@ -183,8 +218,15 @@ public void ConstructorShouldThrowArgumentOutOfRangeExceptionWhenPortIsGreaterTh try { - new ConnectionInfo(Resources.HOST, port, Resources.USERNAME, ProxyTypes.None, Resources.HOST, - int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD, null); + _ = new ConnectionInfo(Resources.HOST, + port, + Resources.USERNAME, + ProxyTypes.None, + Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + Resources.PASSWORD, + null); Assert.Fail(); } catch (ArgumentOutOfRangeException ex) @@ -202,8 +244,15 @@ public void ConstructorShouldThrowArgumentOutOfRangeExceptionWhenPortIsLessThanM try { - new ConnectionInfo(Resources.HOST, port, Resources.USERNAME, ProxyTypes.None, Resources.HOST, - int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD, null); + _ = new ConnectionInfo(Resources.HOST, + port, + Resources.USERNAME, + ProxyTypes.None, + Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + Resources.PASSWORD, + null); Assert.Fail(); } catch (ArgumentOutOfRangeException ex) @@ -234,9 +283,15 @@ public void ConstructorShouldThrowArgumentExceptionhenUsernameIsNull() try { - new ConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), username, ProxyTypes.Http, Resources.USERNAME, - int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD, - new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME)); + _ = new ConnectionInfo(Resources.HOST, + int.Parse(Resources.PORT), + username, + ProxyTypes.Http, + Resources.USERNAME, + int.Parse(Resources.PORT), + Resources.USERNAME, + Resources.PASSWORD, + new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME)); Assert.Fail(); } catch (ArgumentNullException ex) @@ -254,9 +309,15 @@ public void ConstructorShouldThrowArgumentExceptionhenUsernameIsEmpty() try { - new ConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), username, ProxyTypes.Http, Resources.USERNAME, - int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD, - new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME)); + _ = new ConnectionInfo(Resources.HOST, + int.Parse(Resources.PORT), + username, + ProxyTypes.Http, + Resources.USERNAME, + int.Parse(Resources.PORT), + Resources.USERNAME, + Resources.PASSWORD, + new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME)); Assert.Fail(); } catch (ArgumentException ex) @@ -275,9 +336,15 @@ public void ConstructorShouldThrowArgumentExceptionhenUsernameContainsOnlyWhites try { - new ConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), username, ProxyTypes.Http, Resources.USERNAME, - int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD, - new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME)); + _ = new ConnectionInfo(Resources.HOST, + int.Parse(Resources.PORT), + username, + ProxyTypes.Http, + Resources.USERNAME, + int.Parse(Resources.PORT), + Resources.USERNAME, + Resources.PASSWORD, + new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME)); Assert.Fail(); } catch (ArgumentException ex) @@ -294,8 +361,15 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenAuthenticationMethods { try { - new ConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, ProxyTypes.None, Resources.HOST, - int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD, null); + _ = new ConnectionInfo(Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + ProxyTypes.None, + Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + Resources.PASSWORD, + null); Assert.Fail(); } catch (ArgumentNullException ex) @@ -311,8 +385,15 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenAuthenticationMethods { try { - new ConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, ProxyTypes.None, Resources.HOST, - int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD, new AuthenticationMethod[0]); + _ = new ConnectionInfo(Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + ProxyTypes.None, + Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + Resources.PASSWORD, + new AuthenticationMethod[0]); Assert.Fail(); } catch (ArgumentException ex) @@ -326,11 +407,18 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenAuthenticationMethods [TestCategory("ConnectionInfo")] public void AuthenticateShouldThrowArgumentNullExceptionWhenServiceFactoryIsNull() { - var connectionInfo = new ConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, ProxyTypes.None, - Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD, - new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME)); + var connectionInfo = new ConnectionInfo(Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + ProxyTypes.None, + Resources.HOST, + int.Parse(Resources.PORT), + Resources.USERNAME, + Resources.PASSWORD, + new KeyboardInteractiveAuthenticationMethod(Resources.USERNAME)); + var session = new Mock(MockBehavior.Strict).Object; - IServiceFactory serviceFactory = null; + const IServiceFactory serviceFactory = null; try { @@ -344,4 +432,4 @@ public void AuthenticateShouldThrowArgumentNullExceptionWhenServiceFactoryIsNull } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortNeverStarted.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortNeverStarted.cs index afa281d89..dfd07a273 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortNeverStarted.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortNeverStarted.cs @@ -2,9 +2,11 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.Channels; + using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs index 6c4439440..aa9957389 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs @@ -2,10 +2,12 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; -using System.Runtime.InteropServices; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketSendShutdownImmediately.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketSendShutdownImmediately.cs index ffc104f17..9859be49f 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketSendShutdownImmediately.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketSendShutdownImmediately.cs @@ -2,10 +2,12 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; -using System.Text; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; @@ -38,8 +40,11 @@ public void Cleanup() { if (_forwardedPort != null && _forwardedPort.IsStarted) { - _sessionMock.Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.Setup(p => p.Timeout).Returns(TimeSpan.FromSeconds(5)); + _ = _sessionMock.Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _ = _connectionInfoMock.Setup(p => p.Timeout) + .Returns(TimeSpan.FromSeconds(5)); + _forwardedPort.Stop(); } @@ -87,11 +92,21 @@ private void SetupMocks() { var seq = new MockSequence(); - _sessionMock.InSequence(seq).Setup(p => p.IsConnected).Returns(true); - _sessionMock.InSequence(seq).Setup(p => p.CreateChannelDirectTcpip()).Returns(_channelMock.Object); - _sessionMock.InSequence(seq).Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(seq).Setup(p => p.Timeout).Returns(_connectionTimeout); - _channelMock.InSequence(seq).Setup(p => p.Dispose()).Callback(() => _channelDisposed.Set()); + _ = _sessionMock.InSequence(seq) + .Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.InSequence(seq) + .Setup(p => p.CreateChannelDirectTcpip()) + .Returns(_channelMock.Object); + _ = _sessionMock.InSequence(seq) + .Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _ = _connectionInfoMock.InSequence(seq) + .Setup(p => p.Timeout) + .Returns(_connectionTimeout); + _ = _channelMock.InSequence(seq) + .Setup(p => p.Dispose()) + .Callback(() => _channelDisposed.Set()); } private void Arrange() @@ -110,7 +125,7 @@ private void Act() _client.Shutdown(SocketShutdown.Send); // wait for channel to be disposed - _channelDisposed.WaitOne(TimeSpan.FromMilliseconds(200)); + _ = _channelDisposed.WaitOne(TimeSpan.FromMilliseconds(200)); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketVersionNotSupported.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketVersionNotSupported.cs index 8eef3061f..e3dc264b5 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketVersionNotSupported.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketVersionNotSupported.cs @@ -2,10 +2,12 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; -using System.Text; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs index b84d947d5..34db4f9dd 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs @@ -2,10 +2,12 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; -using System.Runtime.InteropServices; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -55,11 +57,15 @@ protected void Arrange() _sessionMock = new Mock(MockBehavior.Strict); _channelMock = new Mock(MockBehavior.Strict); - _connectionInfoMock.Setup(p => p.Timeout).Returns(TimeSpan.FromSeconds(15)); - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _sessionMock.Setup(p => p.CreateChannelDirectTcpip()).Returns(_channelMock.Object); - _channelMock.Setup(p => p.Dispose()); + _ = _connectionInfoMock.Setup(p => p.Timeout) + .Returns(TimeSpan.FromSeconds(15)); + _ = _sessionMock.Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _ = _sessionMock.Setup(p => p.CreateChannelDirectTcpip()) + .Returns(_channelMock.Object); + _ = _channelMock.Setup(p => p.Dispose()); _forwardedPort = new ForwardedPortDynamic(_endpoint.Address.ToString(), (uint) _endpoint.Port); _forwardedPort.Closing += (sender, args) => _closingRegister.Add(args); @@ -112,7 +118,7 @@ public void ExistingConnectionShouldBeClosed() { try { - _client.Send(new byte[] { 0x0a }, 0, 1, SocketFlags.None); + _ = _client.Send(new byte[] { 0x0a }, 0, 1, SocketFlags.None); Assert.Fail(); } catch (SocketException ex) diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs index 13b2c81b9..82459d00a 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs @@ -1,11 +1,18 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; -using System; +锘縰sing System; using System.Diagnostics; +#if NET6_0_OR_GREATER +using System.Net.Http; +#else using System.Net; +#endif // NET6_0_OR_GREATER using System.Threading; +using System.Threading.Tasks; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; +using Renci.SshNet.Tests.Properties; namespace Renci.SshNet.Tests.Classes { @@ -23,7 +30,7 @@ public partial class ForwardedPortLocalTest : TestBase [Description("Test if calling Stop on ForwardedPortLocal instance causes wait.")] public void Test_PortForwarding_Local_Stop_Hangs_On_Wait() { - using (var client = new SshClient(Resources.HOST, Int32.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD)) + using (var client = new SshClient(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD)) { client.Connect(); @@ -36,47 +43,57 @@ public void Test_PortForwarding_Local_Stop_Hangs_On_Wait() port1.Start(); - bool hasTestedTunnel = false; - System.Threading.ThreadPool.QueueUserWorkItem(delegate(object state) - { - try + var hasTestedTunnel = false; + + _ = ThreadPool.QueueUserWorkItem(delegate(object state) { - var url = "http://www.google.com/"; - Debug.WriteLine("Starting web request to \"" + url + "\""); - HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); - HttpWebResponse response = (HttpWebResponse)request.GetResponse(); + try + { + var url = "http://www.google.com/"; + Debug.WriteLine("Starting web request to \"" + url + "\""); - Assert.IsNotNull(response); +#if NET6_0_OR_GREATER + var httpClient = new HttpClient(); + var response = httpClient.GetAsync(url) + .ConfigureAwait(false) + .GetAwaiter() + .GetResult(); +#else + var request = (HttpWebRequest) WebRequest.Create(url); + var response = (HttpWebResponse) request.GetResponse(); +#endif // NET6_0_OR_GREATER - Debug.WriteLine("Http Response status code: " + response.StatusCode.ToString()); + Assert.IsNotNull(response); - response.Close(); + Debug.WriteLine("Http Response status code: " + response.StatusCode.ToString()); - hasTestedTunnel = true; - } - catch (Exception ex) - { - Assert.Fail(ex.ToString()); - } - }); + response.Dispose(); + + hasTestedTunnel = true; + } + catch (Exception ex) + { + Assert.Fail(ex.ToString()); + } + }); // Wait for the web request to complete. while (!hasTestedTunnel) { - System.Threading.Thread.Sleep(1000); + Thread.Sleep(1000); } try { // Try stop the port forwarding, wait 3 seconds and fail if it is still started. - System.Threading.ThreadPool.QueueUserWorkItem(delegate(object state) - { - Debug.WriteLine("Trying to stop port forward."); - port1.Stop(); - Debug.WriteLine("Port forwarding stopped."); - }); + _ = ThreadPool.QueueUserWorkItem(delegate(object state) + { + Debug.WriteLine("Trying to stop port forward."); + port1.Stop(); + Debug.WriteLine("Port forwarding stopped."); + }); - System.Threading.Thread.Sleep(3000); + Thread.Sleep(3000); if (port1.IsStarted) { Assert.Fail("Port forwarding not stopped."); @@ -96,7 +113,7 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenBoundHostIsNull() { try { - new ForwardedPortLocal(null, 8080, Resources.HOST, 80); + _ = new ForwardedPortLocal(null, 8080, Resources.HOST, 80); Assert.Fail(); } catch (ArgumentNullException ex) @@ -131,7 +148,7 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenHostIsNull() { try { - new ForwardedPortLocal(Resources.HOST, 8080, null, 80); + _ = new ForwardedPortLocal(Resources.HOST, 8080, null, 80); Assert.Fail(); } catch (ArgumentNullException ex) @@ -188,7 +205,6 @@ public void Test_ForwardedPortRemote() Assert.Inconclusive("TODO: Implement code to verify target"); } -#if FEATURE_TPL [TestMethod] [TestCategory("integration")] [ExpectedException(typeof(SshConnectionException))] @@ -199,30 +215,33 @@ public void Test_PortForwarding_Local_Without_Connecting() var port1 = new ForwardedPortLocal("localhost", 8084, "www.renci.org", 80); client.AddForwardedPort(port1); port1.Exception += delegate (object sender, ExceptionEventArgs e) - { - Assert.Fail(e.Exception.ToString()); - }; - port1.Start(); - - System.Threading.Tasks.Parallel.For(0, 100, - - //new ParallelOptions - //{ - // MaxDegreeOfParallelism = 20, - //}, - (counter) => { - var start = DateTime.Now; - var req = HttpWebRequest.Create("http://localhost:8084"); - using (var response = req.GetResponse()) - { - var data = ReadStream(response.GetResponseStream()); - var end = DateTime.Now; + Assert.Fail(e.Exception.ToString()); + }; + port1.Start(); - Debug.WriteLine(string.Format("Request# {2}: Lenght: {0} Time: {1}", data.Length, (end - start), counter)); - } - } - ); + _ = Parallel.For(0, + 100, + counter => + { + var start = DateTime.Now; + +#if NET6_0_OR_GREATER + var httpClient = new HttpClient(); + using (var response = httpClient.GetAsync("http://localhost:8084").GetAwaiter().GetResult()) + { + var data = ReadStream(response.Content.ReadAsStream()); +#else + var request = (HttpWebRequest) WebRequest.Create("http://localhost:8084"); + using (var response = (HttpWebResponse) request.GetResponse()) + { + var data = ReadStream(response.GetResponseStream()); +#endif // NET6_0_OR_GREATER + var end = DateTime.Now; + + Debug.WriteLine(string.Format("Request# {2}: Lenght: {0} Time: {1}", data.Length, end - start, counter)); + } + }); } } @@ -236,48 +255,54 @@ public void Test_PortForwarding_Local() var port1 = new ForwardedPortLocal("localhost", 8084, "www.renci.org", 80); client.AddForwardedPort(port1); port1.Exception += delegate (object sender, ExceptionEventArgs e) - { - Assert.Fail(e.Exception.ToString()); - }; - port1.Start(); - - System.Threading.Tasks.Parallel.For(0, 100, - - //new ParallelOptions - //{ - // MaxDegreeOfParallelism = 20, - //}, - (counter) => { - var start = DateTime.Now; - var req = HttpWebRequest.Create("http://localhost:8084"); - using (var response = req.GetResponse()) - { - var data = ReadStream(response.GetResponseStream()); - var end = DateTime.Now; + Assert.Fail(e.Exception.ToString()); + }; + port1.Start(); - Debug.WriteLine(string.Format("Request# {2}: Length: {0} Time: {1}", data.Length, (end - start), counter)); - } - } - ); + _ = Parallel.For(0, + 100, + counter => + { + var start = DateTime.Now; + +#if NET6_0_OR_GREATER + var httpClient = new HttpClient(); + using (var response = httpClient.GetAsync("http://localhost:8084").GetAwaiter().GetResult()) + { + var data = ReadStream(response.Content.ReadAsStream()); +#else + var request = (HttpWebRequest) WebRequest.Create("http://localhost:8084"); + using (var response = (HttpWebResponse) request.GetResponse()) + { + var data = ReadStream(response.GetResponseStream()); +#endif // NET6_0_OR_GREATER + var end = DateTime.Now; + + Debug.WriteLine(string.Format("Request# {2}: Length: {0} Time: {1}", data.Length, end - start, counter)); + } + }); } } private static byte[] ReadStream(System.IO.Stream stream) { - byte[] buffer = new byte[1024]; + var buffer = new byte[1024]; using (var ms = new System.IO.MemoryStream()) { while (true) { - int read = stream.Read(buffer, 0, buffer.Length); + var read = stream.Read(buffer, 0, buffer.Length); if (read > 0) + { ms.Write(buffer, 0, read); + } else + { return ms.ToArray(); + } } } } -#endif // FEATURE_TPL } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortNeverStarted.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortNeverStarted.cs index 6bb32b280..c286bd88f 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortNeverStarted.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortNeverStarted.cs @@ -51,9 +51,12 @@ protected void Arrange() _sessionMock = new Mock(MockBehavior.Strict); _channelMock = new Mock(MockBehavior.Strict); - _connectionInfoMock.Setup(p => p.Timeout).Returns(TimeSpan.FromSeconds(15)); - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); + _ = _connectionInfoMock.Setup(p => p.Timeout) + .Returns(TimeSpan.FromSeconds(15)); + _ = _sessionMock.Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); _forwardedPort = new ForwardedPortLocal(_localEndpoint.Address.ToString(), (uint) _localEndpoint.Port, _remoteEndpoint.Address.ToString(), (uint) _remoteEndpoint.Port); @@ -78,14 +81,19 @@ public void ForwardedPortShouldAcceptNewConnections() { Socket handlerSocket = null; - _sessionMock.Setup(p => p.CreateChannelDirectTcpip()).Returns(_channelMock.Object); - _channelMock.Setup(p => p.Open(_forwardedPort.Host, _forwardedPort.Port, _forwardedPort, It.IsAny())).Callback((address, port, forwardedPort, socket) => handlerSocket = socket); - _channelMock.Setup(p => p.Bind()).Callback(() => - { - if (handlerSocket != null && handlerSocket.Connected) - handlerSocket.Shutdown(SocketShutdown.Both); - }); - _channelMock.Setup(p => p.Dispose()); + _ = _sessionMock.Setup(p => p.CreateChannelDirectTcpip()) + .Returns(_channelMock.Object); + _ = _channelMock.Setup(p => p.Open(_forwardedPort.Host, _forwardedPort.Port, _forwardedPort, It.IsAny())) + .Callback((address, port, forwardedPort, socket) => handlerSocket = socket); + _ = _channelMock.Setup(p => p.Bind()) + .Callback(() => + { + if (handlerSocket != null && handlerSocket.Connected) + { + handlerSocket.Shutdown(SocketShutdown.Both); + } + }); + _ = _channelMock.Setup(p => p.Dispose()); using (var client = new Socket(_localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) { diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStarted.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStarted.cs index 5980aad96..e9e07e393 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStarted.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStarted.cs @@ -2,8 +2,11 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -45,16 +48,18 @@ protected void Arrange() _closingRegister = new List(); _exceptionRegister = new List(); _localEndpoint = new IPEndPoint(IPAddress.Loopback, 8122); - _remoteEndpoint = new IPEndPoint(IPAddress.Parse("193.168.1.5"), - random.Next(IPEndPoint.MinPort, IPEndPoint.MaxPort)); + _remoteEndpoint = new IPEndPoint(IPAddress.Parse("193.168.1.5"), random.Next(IPEndPoint.MinPort, IPEndPoint.MaxPort)); _connectionInfoMock = new Mock(MockBehavior.Strict); _sessionMock = new Mock(MockBehavior.Strict); _channelMock = new Mock(MockBehavior.Strict); - _connectionInfoMock.Setup(p => p.Timeout).Returns(TimeSpan.FromSeconds(15)); - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); + _ = _connectionInfoMock.Setup(p => p.Timeout) + .Returns(TimeSpan.FromSeconds(15)); + _ = _sessionMock.Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); _forwardedPort = new ForwardedPortLocal(_localEndpoint.Address.ToString(), (uint)_localEndpoint.Port, _remoteEndpoint.Address.ToString(), (uint)_remoteEndpoint.Port); @@ -95,14 +100,19 @@ public void ForwardedPortShouldAcceptNewConnections() { Socket handlerSocket = null; - _sessionMock.Setup(p => p.CreateChannelDirectTcpip()).Returns(_channelMock.Object); - _channelMock.Setup(p => p.Open(_forwardedPort.Host, _forwardedPort.Port, _forwardedPort, It.IsAny())).Callback((address, port, forwardedPort, socket) => handlerSocket = socket); - _channelMock.Setup(p => p.Bind()).Callback(() => - { - if (handlerSocket != null && handlerSocket.Connected) - handlerSocket.Shutdown(SocketShutdown.Both); - }); - _channelMock.Setup(p => p.Dispose()); + _ = _sessionMock.Setup(p => p.CreateChannelDirectTcpip()) + .Returns(_channelMock.Object); + _ = _channelMock.Setup(p => p.Open(_forwardedPort.Host, _forwardedPort.Port, _forwardedPort, It.IsAny())) + .Callback((address, port, forwardedPort, socket) => handlerSocket = socket); + _ = _channelMock.Setup(p => p.Bind()) + .Callback(() => + { + if (handlerSocket != null && handlerSocket.Connected) + { + handlerSocket.Shutdown(SocketShutdown.Both); + } + }); + _ = _channelMock.Setup(p => p.Dispose()); using (var client = new Socket(_localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) { diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStopped.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStopped.cs index 9889af6aa..7998ea99f 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStopped.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStopped.cs @@ -2,8 +2,11 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -45,18 +48,22 @@ protected void Arrange() _exceptionRegister = new List(); _localEndpoint = new IPEndPoint(IPAddress.Loopback, 8122); _remoteEndpoint = new IPEndPoint(IPAddress.Parse("193.168.1.5"), - random.Next(IPEndPoint.MinPort, IPEndPoint.MaxPort)); + random.Next(IPEndPoint.MinPort, IPEndPoint.MaxPort)); _connectionInfoMock = new Mock(MockBehavior.Strict); _sessionMock = new Mock(MockBehavior.Strict); _channelMock = new Mock(MockBehavior.Strict); - _connectionInfoMock.Setup(p => p.Timeout).Returns(TimeSpan.FromSeconds(15)); - _sessionMock.Setup(p => p.IsConnected).Returns(true); - _sessionMock.Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); + _ = _connectionInfoMock.Setup(p => p.Timeout) + .Returns(TimeSpan.FromSeconds(15)); + _ = _sessionMock.Setup(p => p.IsConnected) + .Returns(true); + _ = _sessionMock.Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); - _forwardedPort = new ForwardedPortLocal(_localEndpoint.Address.ToString(), (uint)_localEndpoint.Port, - _remoteEndpoint.Address.ToString(), (uint)_remoteEndpoint.Port); + _forwardedPort = new ForwardedPortLocal(_localEndpoint.Address.ToString(), + (uint) _localEndpoint.Port, + _remoteEndpoint.Address.ToString(), (uint) _remoteEndpoint.Port); _forwardedPort.Closing += (sender, args) => _closingRegister.Add(args); _forwardedPort.Exception += (sender, args) => _exceptionRegister.Add(args); _forwardedPort.Session = _sessionMock.Object; @@ -82,14 +89,19 @@ public void ForwardedPortShouldAcceptNewConnections() { Socket handlerSocket = null; - _sessionMock.Setup(p => p.CreateChannelDirectTcpip()).Returns(_channelMock.Object); - _channelMock.Setup(p => p.Open(_forwardedPort.Host, _forwardedPort.Port, _forwardedPort, It.IsAny())).Callback((address, port, forwardedPort, socket) => handlerSocket = socket); - _channelMock.Setup(p => p.Bind()).Callback(() => - { - if (handlerSocket != null && handlerSocket.Connected) - handlerSocket.Shutdown(SocketShutdown.Both); - }); - _channelMock.Setup(p => p.Dispose()); + _ = _sessionMock.Setup(p => p.CreateChannelDirectTcpip()) + .Returns(_channelMock.Object); + _ = _channelMock.Setup(p => p.Open(_forwardedPort.Host, _forwardedPort.Port, _forwardedPort, It.IsAny())) + .Callback((address, port, forwardedPort, socket) => handlerSocket = socket); + _ = _channelMock.Setup(p => p.Bind()) + .Callback(() => + { + if (handlerSocket != null && handlerSocket.Connected) + { + handlerSocket.Shutdown(SocketShutdown.Both); + } + }); + _ = _channelMock.Setup(p => p.Dispose()); using (var client = new Socket(_localEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) { diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs index 3a99441d1..5f0777190 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs @@ -1,10 +1,12 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System; +using System.Net; +using System.Threading; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; -using System; -using System.Net; -using System.Threading; namespace Renci.SshNet.Tests.Classes { @@ -23,7 +25,7 @@ public void Test_AddForwardedPort_Remote_Hosts_Are_Null() using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) { client.Connect(); - var port1 = new ForwardedPortRemote((string)null, 8080, (string)null, 80); + var port1 = new ForwardedPortRemote(boundHost: null, 8080, host: null, 80); client.AddForwardedPort(port1); client.Disconnect(); } @@ -80,9 +82,9 @@ public void Test_ForwardedPortRemote() public void StopTest() { uint boundPort = 0; // TODO: Initialize to an appropriate value - string host = string.Empty; // TODO: Initialize to an appropriate value + var host = string.Empty; // TODO: Initialize to an appropriate value uint port = 0; // TODO: Initialize to an appropriate value - ForwardedPortRemote target = new ForwardedPortRemote(boundPort, host, port); // TODO: Initialize to an appropriate value + var target = new ForwardedPortRemote(boundPort, host, port); // TODO: Initialize to an appropriate value target.Stop(); Assert.Inconclusive("A method that does not return a value cannot be verified."); } @@ -91,7 +93,7 @@ public void StopTest() public void Start_NotAddedToClient() { const int boundPort = 80; - string host = string.Empty; + var host = string.Empty; const uint port = 22; var target = new ForwardedPortRemote(boundPort, host, port); @@ -115,9 +117,9 @@ public void Start_NotAddedToClient() public void DisposeTest() { uint boundPort = 0; // TODO: Initialize to an appropriate value - string host = string.Empty; // TODO: Initialize to an appropriate value + var host = string.Empty; // TODO: Initialize to an appropriate value uint port = 0; // TODO: Initialize to an appropriate value - ForwardedPortRemote target = new ForwardedPortRemote(boundPort, host, port); // TODO: Initialize to an appropriate value + var target = new ForwardedPortRemote(boundPort, host, port); // TODO: Initialize to an appropriate value target.Dispose(); Assert.Inconclusive("A method that does not return a value cannot be verified."); } @@ -129,11 +131,11 @@ public void DisposeTest() [Ignore] // placeholder public void ForwardedPortRemoteConstructorTest() { - string boundHost = string.Empty; // TODO: Initialize to an appropriate value + var boundHost = string.Empty; // TODO: Initialize to an appropriate value uint boundPort = 0; // TODO: Initialize to an appropriate value - string host = string.Empty; // TODO: Initialize to an appropriate value + var host = string.Empty; // TODO: Initialize to an appropriate value uint port = 0; // TODO: Initialize to an appropriate value - ForwardedPortRemote target = new ForwardedPortRemote(boundHost, boundPort, host, port); + var target = new ForwardedPortRemote(boundHost, boundPort, host, port); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -145,9 +147,9 @@ public void ForwardedPortRemoteConstructorTest() public void ForwardedPortRemoteConstructorTest1() { uint boundPort = 0; // TODO: Initialize to an appropriate value - string host = string.Empty; // TODO: Initialize to an appropriate value + var host = string.Empty; // TODO: Initialize to an appropriate value uint port = 0; // TODO: Initialize to an appropriate value - ForwardedPortRemote target = new ForwardedPortRemote(boundPort, host, port); + var target = new ForwardedPortRemote(boundPort, host, port); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -192,4 +194,4 @@ public void Test_PortForwarding_Remote() } #endif // FEATURE_TPL } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNotConnected.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNotConnected.cs index fc56157be..af38f057a 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNotConnected.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNotConnected.cs @@ -2,9 +2,11 @@ using System.Collections.Generic; using System.Globalization; using System.Net; -using System.Net.Sockets; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; using Renci.SshNet.Messages.Connection; @@ -35,8 +37,11 @@ public void Cleanup() { if (_forwardedPort != null) { - _sessionMock.Setup(p => p.ConnectionInfo).Returns(_connectionInfoMock.Object); - _connectionInfoMock.Setup(p => p.Timeout).Returns(TimeSpan.FromSeconds(1)); + _ = _sessionMock.Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _ = _connectionInfoMock.Setup(p => p.Timeout) + .Returns(TimeSpan.FromSeconds(1)); + _forwardedPort.Dispose(); _forwardedPort = null; } @@ -53,7 +58,8 @@ protected void Arrange() _sessionMock = new Mock(MockBehavior.Strict); _connectionInfoMock = new Mock(MockBehavior.Strict); - _sessionMock.Setup(p => p.IsConnected).Returns(false); + _ = _sessionMock.Setup(p => p.IsConnected) + .Returns(false); _forwardedPort = new ForwardedPortRemote(_bindEndpoint.Address, (uint)_bindEndpoint.Port, _remoteEndpoint.Address, (uint)_remoteEndpoint.Port); _forwardedPort.Closing += (sender, args) => _closingRegister.Add(args); @@ -90,19 +96,17 @@ public void IsStartedShouldReturnFalse() [TestMethod] public void ForwardedPortShouldIgnoreReceivedSignalForNewConnection() { - var channelNumber = (uint)new Random().Next(1001, int.MaxValue); - var initialWindowSize = (uint)new Random().Next(0, int.MaxValue); - var maximumPacketSize = (uint)new Random().Next(0, int.MaxValue); + var channelNumber = (uint) new Random().Next(1001, int.MaxValue); + var initialWindowSize = (uint) new Random().Next(0, int.MaxValue); + var maximumPacketSize = (uint) new Random().Next(0, int.MaxValue); var originatorAddress = new Random().Next().ToString(CultureInfo.InvariantCulture); - var originatorPort = (uint)new Random().Next(0, int.MaxValue); + var originatorPort = (uint) new Random().Next(0, int.MaxValue); var channelMock = new Mock(MockBehavior.Strict); - _sessionMock.Setup( - p => - p.CreateChannelForwardedTcpip(channelNumber, initialWindowSize, maximumPacketSize)).Returns(channelMock.Object); - + _ = _sessionMock.Setup(p => p.CreateChannelForwardedTcpip(channelNumber, initialWindowSize, maximumPacketSize)).Returns(channelMock.Object); + _sessionMock.Raise(p => p.ChannelOpenReceived += null, - new MessageEventArgs(new ChannelOpenMessage(channelNumber, initialWindowSize, + new MessageEventArgs(new ChannelOpenMessage(channelNumber, initialWindowSize, maximumPacketSize, new ForwardedTcpipChannelInfo(_forwardedPort.BoundHost, _forwardedPort.BoundPort, originatorAddress, originatorPort)))); diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNull.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNull.cs index 68931a0a1..9cd3a3046 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNull.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNull.cs @@ -1,13 +1,10 @@ 锘縰sing System; using System.Collections.Generic; -using System.Globalization; using System.Net; -using System.Net.Sockets; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; -using Renci.SshNet.Channels; + using Renci.SshNet.Common; -using Renci.SshNet.Messages.Connection; namespace Renci.SshNet.Tests.Classes { diff --git a/src/Renci.SshNet.Tests/Classes/MessageEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/MessageEventArgsTest.cs index 051fd6c34..da6ab8517 100644 --- a/src/Renci.SshNet.Tests/Classes/MessageEventArgsTest.cs +++ b/src/Renci.SshNet.Tests/Classes/MessageEventArgsTest.cs @@ -14,8 +14,8 @@ public class MessageEventArgsTest : TestBase /// public void MessageEventArgsConstructorTestHelper() { - T message = default(T); // TODO: Initialize to an appropriate value - MessageEventArgs target = new MessageEventArgs(message); + T message = default; // TODO: Initialize to an appropriate value + var target = new MessageEventArgs(message); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -26,4 +26,4 @@ public void MessageEventArgsConstructorTest() MessageEventArgsConstructorTestHelper(); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/FailureMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/FailureMessageTest.cs index 9f0169f02..979b1d750 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/FailureMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/FailureMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Authentication; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Messages.Authentication @@ -19,7 +19,7 @@ public class FailureMessageTest : TestBase [Ignore] // placeholder public void FailureMessageConstructorTest() { - FailureMessage target = new FailureMessage(); + var target = new FailureMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -30,7 +30,7 @@ public void FailureMessageConstructorTest() [Ignore] // placeholder public void AllowedAuthenticationsTest() { - FailureMessage target = new FailureMessage(); // TODO: Initialize to an appropriate value + var target = new FailureMessage(); // TODO: Initialize to an appropriate value string[] expected = null; // TODO: Initialize to an appropriate value string[] actual; target.AllowedAuthentications = expected; diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessagePublicKeyTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessagePublicKeyTest.cs index f09aa4a4c..fb4e36af1 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessagePublicKeyTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessagePublicKeyTest.cs @@ -1,7 +1,7 @@ -锘縰sing Renci.SshNet.Messages.Authentication; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Messages; +using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Messages.Authentication @@ -20,11 +20,11 @@ public class RequestMessagePublicKeyTest : TestBase [Ignore] // placeholder public void RequestMessagePublicKeyConstructorTest() { - ServiceName serviceName = new ServiceName(); // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string keyAlgorithmName = string.Empty; // TODO: Initialize to an appropriate value + var serviceName = new ServiceName(); // TODO: Initialize to an appropriate value + var username = string.Empty; // TODO: Initialize to an appropriate value + var keyAlgorithmName = string.Empty; // TODO: Initialize to an appropriate value byte[] keyData = null; // TODO: Initialize to an appropriate value - RequestMessagePublicKey target = new RequestMessagePublicKey(serviceName, username, keyAlgorithmName, keyData); + var target = new RequestMessagePublicKey(serviceName, username, keyAlgorithmName, keyData); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -35,12 +35,12 @@ public void RequestMessagePublicKeyConstructorTest() [Ignore] // placeholder public void RequestMessagePublicKeyConstructorTest1() { - ServiceName serviceName = new ServiceName(); // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string keyAlgorithmName = string.Empty; // TODO: Initialize to an appropriate value + var serviceName = new ServiceName(); // TODO: Initialize to an appropriate value + var username = string.Empty; // TODO: Initialize to an appropriate value + var keyAlgorithmName = string.Empty; // TODO: Initialize to an appropriate value byte[] keyData = null; // TODO: Initialize to an appropriate value byte[] signature = null; // TODO: Initialize to an appropriate value - RequestMessagePublicKey target = new RequestMessagePublicKey(serviceName, username, keyAlgorithmName, keyData, signature); + var target = new RequestMessagePublicKey(serviceName, username, keyAlgorithmName, keyData, signature); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -51,13 +51,12 @@ public void RequestMessagePublicKeyConstructorTest1() [Ignore] // placeholder public void MethodNameTest() { - ServiceName serviceName = new ServiceName(); // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string keyAlgorithmName = string.Empty; // TODO: Initialize to an appropriate value + var serviceName = new ServiceName(); // TODO: Initialize to an appropriate value + var username = string.Empty; // TODO: Initialize to an appropriate value + var keyAlgorithmName = string.Empty; // TODO: Initialize to an appropriate value byte[] keyData = null; // TODO: Initialize to an appropriate value - RequestMessagePublicKey target = new RequestMessagePublicKey(serviceName, username, keyAlgorithmName, keyData); // TODO: Initialize to an appropriate value - string actual; - actual = target.MethodName; + var target = new RequestMessagePublicKey(serviceName, username, keyAlgorithmName, keyData); // TODO: Initialize to an appropriate value + var actual = target.MethodName; Assert.Inconclusive("Verify the correctness of this test method."); } @@ -68,11 +67,11 @@ public void MethodNameTest() [Ignore] // placeholder public void SignatureTest() { - ServiceName serviceName = new ServiceName(); // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string keyAlgorithmName = string.Empty; // TODO: Initialize to an appropriate value + var serviceName = new ServiceName(); // TODO: Initialize to an appropriate value + var username = string.Empty; // TODO: Initialize to an appropriate value + var keyAlgorithmName = string.Empty; // TODO: Initialize to an appropriate value byte[] keyData = null; // TODO: Initialize to an appropriate value - RequestMessagePublicKey target = new RequestMessagePublicKey(serviceName, username, keyAlgorithmName, keyData); // TODO: Initialize to an appropriate value + var target = new RequestMessagePublicKey(serviceName, username, keyAlgorithmName, keyData); // TODO: Initialize to an appropriate value byte[] expected = null; // TODO: Initialize to an appropriate value target.Signature = expected; var actual = target.Signature; diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelCloseMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelCloseMessageTest.cs index 9d3ebc3c0..995981a60 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelCloseMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelCloseMessageTest.cs @@ -1,6 +1,5 @@ 锘縰sing Renci.SshNet.Messages.Connection; using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -19,7 +18,7 @@ public class ChannelCloseMessageTest : TestBase [Ignore] // placeholder public void ChannelCloseMessageConstructorTest() { - ChannelCloseMessage target = new ChannelCloseMessage(); + var target = new ChannelCloseMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -31,7 +30,7 @@ public void ChannelCloseMessageConstructorTest() public void ChannelCloseMessageConstructorTest1() { uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - ChannelCloseMessage target = new ChannelCloseMessage(localChannelNumber); + var target = new ChannelCloseMessage(localChannelNumber); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelEofMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelEofMessageTest.cs index a302fb6e8..ad2becd89 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelEofMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelEofMessageTest.cs @@ -1,6 +1,5 @@ 锘縰sing Renci.SshNet.Messages.Connection; using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -19,7 +18,7 @@ public class ChannelEofMessageTest : TestBase [Ignore] // placeholder public void ChannelEofMessageConstructorTest() { - ChannelEofMessage target = new ChannelEofMessage(); + var target = new ChannelEofMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -31,7 +30,7 @@ public void ChannelEofMessageConstructorTest() public void ChannelEofMessageConstructorTest1() { uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - ChannelEofMessage target = new ChannelEofMessage(localChannelNumber); + var target = new ChannelEofMessage(localChannelNumber); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelExtendedDataMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelExtendedDataMessageTest.cs index 469908ea3..65e3dbcc7 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelExtendedDataMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelExtendedDataMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -19,7 +19,7 @@ public class ChannelExtendedDataMessageTest : TestBase [Ignore] // placeholder public void ChannelExtendedDataMessageConstructorTest() { - ChannelExtendedDataMessage target = new ChannelExtendedDataMessage(); + var target = new ChannelExtendedDataMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelFailureMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelFailureMessageTest.cs index ef1fe76c4..070df2a68 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelFailureMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelFailureMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -19,7 +19,7 @@ public class ChannelFailureMessageTest : TestBase [Ignore] // placeholder public void ChannelFailureMessageConstructorTest() { - ChannelFailureMessage target = new ChannelFailureMessage(); + var target = new ChannelFailureMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -31,7 +31,7 @@ public void ChannelFailureMessageConstructorTest() public void ChannelFailureMessageConstructorTest1() { uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - ChannelFailureMessage target = new ChannelFailureMessage(localChannelNumber); + var target = new ChannelFailureMessage(localChannelNumber); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelMessageTest.cs index baa4a7fca..53c56cf7f 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -26,10 +26,9 @@ internal virtual ChannelMessage CreateChannelMessage() [TestMethod()] public void ToStringTest() { - ChannelMessage target = CreateChannelMessage(); // TODO: Initialize to an appropriate value - string expected = string.Empty; // TODO: Initialize to an appropriate value - string actual; - actual = target.ToString(); + var target = CreateChannelMessage(); // TODO: Initialize to an appropriate value + var expected = string.Empty; // TODO: Initialize to an appropriate value + var actual = target.ToString(); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs index 368f55319..1a40d8609 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs @@ -28,9 +28,9 @@ public void DefaultConstructor() Assert.IsNull(target.ChannelType); Assert.IsNull(target.Info); - Assert.AreEqual(default(uint), target.InitialWindowSize); - Assert.AreEqual(default(uint), target.LocalChannelNumber); - Assert.AreEqual(default(uint), target.MaximumPacketSize); + Assert.AreEqual(default, target.InitialWindowSize); + Assert.AreEqual(default, target.LocalChannelNumber); + Assert.AreEqual(default, target.MaximumPacketSize); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenConfirmationMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenConfirmationMessageTest.cs index ce5abb61a..3ad44b48f 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenConfirmationMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenConfirmationMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -19,7 +19,7 @@ public class ChannelOpenConfirmationMessageTest : TestBase [Ignore] // placeholder public void ChannelOpenConfirmationMessageConstructorTest() { - ChannelOpenConfirmationMessage target = new ChannelOpenConfirmationMessage(); + var target = new ChannelOpenConfirmationMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -34,7 +34,7 @@ public void ChannelOpenConfirmationMessageConstructorTest1() uint initialWindowSize = 0; // TODO: Initialize to an appropriate value uint maximumPacketSize = 0; // TODO: Initialize to an appropriate value uint remoteChannelNumber = 0; // TODO: Initialize to an appropriate value - ChannelOpenConfirmationMessage target = new ChannelOpenConfirmationMessage(localChannelNumber, initialWindowSize, maximumPacketSize, remoteChannelNumber); + var target = new ChannelOpenConfirmationMessage(localChannelNumber, initialWindowSize, maximumPacketSize, remoteChannelNumber); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenFailureMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenFailureMessageTest.cs index 3992ca491..848f81eda 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenFailureMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenFailureMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -19,7 +19,7 @@ public class ChannelOpenFailureMessageTest : TestBase [Ignore] // placeholder public void ChannelOpenFailureMessageConstructorTest() { - ChannelOpenFailureMessage target = new ChannelOpenFailureMessage(); + var target = new ChannelOpenFailureMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -31,9 +31,9 @@ public void ChannelOpenFailureMessageConstructorTest() public void ChannelOpenFailureMessageConstructorTest1() { uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - string description = string.Empty; // TODO: Initialize to an appropriate value + var description = string.Empty; // TODO: Initialize to an appropriate value uint reasonCode = 0; // TODO: Initialize to an appropriate value - ChannelOpenFailureMessage target = new ChannelOpenFailureMessage(localChannelNumber, description, reasonCode); + var target = new ChannelOpenFailureMessage(localChannelNumber, description, reasonCode); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenInfoTest.cs index 845cc8c07..a28e17ed8 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenInfoTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -26,9 +26,8 @@ internal virtual ChannelOpenInfo CreateChannelOpenInfo() [TestMethod()] public void ChannelTypeTest() { - ChannelOpenInfo target = CreateChannelOpenInfo(); // TODO: Initialize to an appropriate value - string actual; - actual = target.ChannelType; + var target = CreateChannelOpenInfo(); // TODO: Initialize to an appropriate value + var actual = target.ChannelType; Assert.Inconclusive("Verify the correctness of this test method."); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/EndOfWriteRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/EndOfWriteRequestInfoTest.cs index 68ffa7af7..0573bade7 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/EndOfWriteRequestInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/EndOfWriteRequestInfoTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -19,7 +19,7 @@ public class EndOfWriteRequestInfoTest : TestBase [Ignore] // placeholder public void EndOfWriteRequestInfoConstructorTest() { - EndOfWriteRequestInfo target = new EndOfWriteRequestInfo(); + var target = new EndOfWriteRequestInfo(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -30,9 +30,9 @@ public void EndOfWriteRequestInfoConstructorTest() [Ignore] // placeholder public void RequestNameTest() { - EndOfWriteRequestInfo target = new EndOfWriteRequestInfo(); // TODO: Initialize to an appropriate value - string actual; - actual = target.RequestName; + var target = new EndOfWriteRequestInfo(); // TODO: Initialize to an appropriate value + + var actual = target.RequestName; Assert.Inconclusive("Verify the correctness of this test method."); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/KeepAliveRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/KeepAliveRequestInfoTest.cs index 515a723a5..77b8cc927 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/KeepAliveRequestInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/KeepAliveRequestInfoTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -19,7 +19,7 @@ public class KeepAliveRequestInfoTest : TestBase [Ignore] // placeholder public void KeepAliveRequestInfoConstructorTest() { - KeepAliveRequestInfo target = new KeepAliveRequestInfo(); + var target = new KeepAliveRequestInfo(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -30,9 +30,8 @@ public void KeepAliveRequestInfoConstructorTest() [Ignore] // placeholder public void RequestNameTest() { - KeepAliveRequestInfo target = new KeepAliveRequestInfo(); // TODO: Initialize to an appropriate value - string actual; - actual = target.RequestName; + var target = new KeepAliveRequestInfo(); // TODO: Initialize to an appropriate value + var actual = target.RequestName; Assert.Inconclusive("Verify the correctness of this test method."); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/PseudoTerminalInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/PseudoTerminalInfoTest.cs index b7e3e3234..fedbdb7fc 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/PseudoTerminalInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/PseudoTerminalInfoTest.cs @@ -55,7 +55,7 @@ public void GetBytes() expectedBytesLength += 4; // PixelWidth expectedBytesLength += 4; // PixelHeight expectedBytesLength += 4; // Length of "encoded terminal modes" - expectedBytesLength += _terminalModeValues.Count*(1 + 4) + 1; // encoded terminal modes + expectedBytesLength += (_terminalModeValues.Count * (1 + 4)) + 1; // encoded terminal modes Assert.AreEqual(expectedBytesLength, bytes.Length); @@ -67,7 +67,7 @@ public void GetBytes() Assert.AreEqual(_rows, sshDataStream.ReadUInt32()); Assert.AreEqual(_width, sshDataStream.ReadUInt32()); Assert.AreEqual(_height, sshDataStream.ReadUInt32()); - Assert.AreEqual((uint) (_terminalModeValues.Count * (1 + 4) + 1), sshDataStream.ReadUInt32()); + Assert.AreEqual((uint) ((_terminalModeValues.Count * (1 + 4)) + 1), sshDataStream.ReadUInt32()); Assert.AreEqual((int) TerminalModes.CS8, sshDataStream.ReadByte()); Assert.AreEqual(_terminalModeValues[TerminalModes.CS8], sshDataStream.ReadUInt32()); Assert.AreEqual((int) TerminalModes.ECHO, sshDataStream.ReadByte()); @@ -180,4 +180,4 @@ public void NameShouldReturnPtyReq() Assert.AreEqual("pty-req", PseudoTerminalRequestInfo.Name); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelSuccessMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelSuccessMessageTest.cs index 6bfb5b0c2..68efa44c4 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelSuccessMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelSuccessMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -19,7 +19,7 @@ public class ChannelSuccessMessageTest : TestBase [Ignore] // placeholder public void ChannelSuccessMessageConstructorTest() { - ChannelSuccessMessage target = new ChannelSuccessMessage(); + var target = new ChannelSuccessMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -31,7 +31,7 @@ public void ChannelSuccessMessageConstructorTest() public void ChannelSuccessMessageConstructorTest1() { uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - ChannelSuccessMessage target = new ChannelSuccessMessage(localChannelNumber); + var target = new ChannelSuccessMessage(localChannelNumber); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelWindowAdjustMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelWindowAdjustMessageTest.cs index 131cdfda6..12d19a61c 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelWindowAdjustMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelWindowAdjustMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestInfoTest.cs index fdf6d5348..f37ecc183 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestInfoTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -26,9 +26,8 @@ internal virtual RequestInfo CreateRequestInfo() [TestMethod()] public void RequestNameTest() { - RequestInfo target = CreateRequestInfo(); // TODO: Initialize to an appropriate value - string actual; - actual = target.RequestName; + var target = CreateRequestInfo(); // TODO: Initialize to an appropriate value + var actual = target.RequestName; Assert.Inconclusive("Verify the correctness of this test method."); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestSuccessMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestSuccessMessageTest.cs index 55d7ec6db..fba922456 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestSuccessMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestSuccessMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Connection @@ -19,7 +19,7 @@ public class RequestSuccessMessageTest : TestBase [Ignore] // placeholder public void RequestSuccessMessageConstructorTest() { - RequestSuccessMessage target = new RequestSuccessMessage(); + var target = new RequestSuccessMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -31,7 +31,7 @@ public void RequestSuccessMessageConstructorTest() public void RequestSuccessMessageConstructorTest1() { uint boundPort = 0; // TODO: Initialize to an appropriate value - RequestSuccessMessage target = new RequestSuccessMessage(boundPort); + var target = new RequestSuccessMessage(boundPort); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/MessageAttributeTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/MessageAttributeTest.cs index 9c4f93cd0..eb6118d61 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/MessageAttributeTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/MessageAttributeTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages @@ -19,9 +19,9 @@ public class MessageAttributeTest : TestBase [Ignore] // placeholder public void MessageAttributeConstructorTest() { - string name = string.Empty; // TODO: Initialize to an appropriate value + var name = string.Empty; // TODO: Initialize to an appropriate value byte number = 0; // TODO: Initialize to an appropriate value - MessageAttribute target = new MessageAttribute(name, number); + var target = new MessageAttribute(name, number); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -32,10 +32,10 @@ public void MessageAttributeConstructorTest() [Ignore] // placeholder public void NameTest() { - string name = string.Empty; // TODO: Initialize to an appropriate value + var name = string.Empty; // TODO: Initialize to an appropriate value byte number = 0; // TODO: Initialize to an appropriate value - MessageAttribute target = new MessageAttribute(name, number); // TODO: Initialize to an appropriate value - string expected = string.Empty; // TODO: Initialize to an appropriate value + var target = new MessageAttribute(name, number); // TODO: Initialize to an appropriate value + var expected = string.Empty; // TODO: Initialize to an appropriate value target.Name = expected; var actual = target.Name; Assert.AreEqual(expected, actual); @@ -49,9 +49,9 @@ public void NameTest() [Ignore] // placeholder public void NumberTest() { - string name = string.Empty; // TODO: Initialize to an appropriate value + var name = string.Empty; // TODO: Initialize to an appropriate value byte number = 0; // TODO: Initialize to an appropriate value - MessageAttribute target = new MessageAttribute(name, number); // TODO: Initialize to an appropriate value + var target = new MessageAttribute(name, number); // TODO: Initialize to an appropriate value byte expected = 0; // TODO: Initialize to an appropriate value target.Number = expected; var actual = target.Number; diff --git a/src/Renci.SshNet.Tests/Classes/Messages/MessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/MessageTest.cs index 5ad0d6bfe..d3290f1f9 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/MessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/MessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages @@ -26,7 +26,7 @@ internal virtual Message CreateMessage() [TestMethod] public void GetBytesTest() { - Message target = CreateMessage(); // TODO: Initialize to an appropriate value + var target = CreateMessage(); // TODO: Initialize to an appropriate value byte[] expected = null; // TODO: Initialize to an appropriate value var actual = target.GetBytes(); Assert.AreEqual(expected, actual); @@ -39,8 +39,8 @@ public void GetBytesTest() [TestMethod] public void ToStringTest() { - Message target = CreateMessage(); // TODO: Initialize to an appropriate value - string expected = string.Empty; // TODO: Initialize to an appropriate value + var target = CreateMessage(); // TODO: Initialize to an appropriate value + var expected = string.Empty; // TODO: Initialize to an appropriate value var actual = target.ToString(); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/DisconnectMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/DisconnectMessageTest.cs index 280370364..853653826 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/DisconnectMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Transport/DisconnectMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Transport; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Transport @@ -19,7 +19,7 @@ public class DisconnectMessageTest : TestBase [Ignore] // placeholder public void DisconnectMessageConstructorTest() { - DisconnectMessage target = new DisconnectMessage(); + var target = new DisconnectMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -30,9 +30,9 @@ public void DisconnectMessageConstructorTest() [Ignore] // placeholder public void DisconnectMessageConstructorTest1() { - DisconnectReason reasonCode = new DisconnectReason(); // TODO: Initialize to an appropriate value - string message = string.Empty; // TODO: Initialize to an appropriate value - DisconnectMessage target = new DisconnectMessage(reasonCode, message); + var reasonCode = new DisconnectReason(); // TODO: Initialize to an appropriate value + var message = string.Empty; // TODO: Initialize to an appropriate value + var target = new DisconnectMessage(reasonCode, message); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupTest.cs index fc49a61d9..b5a56f48c 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Transport; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Transport @@ -19,7 +19,7 @@ public class KeyExchangeDhGroupExchangeGroupTest : TestBase [Ignore] // placeholder public void KeyExchangeDhGroupExchangeGroupConstructorTest() { - KeyExchangeDhGroupExchangeGroup target = new KeyExchangeDhGroupExchangeGroup(); + var target = new KeyExchangeDhGroupExchangeGroup(); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs index dbb5d0ede..81714f368 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs @@ -17,7 +17,10 @@ public KeyExchangeDhGroupExchangeReplyBuilder WithHostKey(string hostKeyAlgorith var sshDataStream = new SshDataStream(0); foreach (var hostKey in hostKeys) + { sshDataStream.Write(hostKey); + } + _hostKeys = sshDataStream.ToArray(); return this; diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs index ea2b7159d..0120c5550 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs @@ -1,8 +1,9 @@ 锘縰sing System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; -using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Transport { @@ -67,4 +68,4 @@ public void Load() Assert.AreEqual(_maximum, target.Maximum); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhReplyMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhReplyMessageTest.cs index 961fe4370..a0d0d2f13 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhReplyMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhReplyMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Transport; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Transport @@ -19,7 +19,7 @@ public class KeyExchangeDhReplyMessageTest : TestBase [Ignore] // placeholder public void KeyExchangeDhReplyMessageConstructorTest() { - KeyExchangeDhReplyMessage target = new KeyExchangeDhReplyMessage(); + var target = new KeyExchangeDhReplyMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/NewKeysMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/NewKeysMessageTest.cs index f1ea0398d..430c2151f 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/NewKeysMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Transport/NewKeysMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Transport; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Transport @@ -19,7 +19,7 @@ public class NewKeysMessageTest : TestBase [Ignore] // placeholder public void NewKeysMessageConstructorTest() { - NewKeysMessage target = new NewKeysMessage(); + var target = new NewKeysMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceAcceptMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceAcceptMessageTest.cs index 5c8f40912..143cd7003 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceAcceptMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceAcceptMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Transport; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Transport; namespace Renci.SshNet.Tests.Classes.Messages.Transport { @@ -18,7 +18,7 @@ public class ServiceAcceptMessageTest [Ignore] // placeholder public void ServiceAcceptMessageConstructorTest() { - ServiceAcceptMessage target = new ServiceAcceptMessage(); + var target = new ServiceAcceptMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceRequestMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceRequestMessageTest.cs index dc1db6a42..9806fb862 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceRequestMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceRequestMessageTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Messages.Transport; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Messages.Transport; using Renci.SshNet.Messages; namespace Renci.SshNet.Tests.Classes.Messages.Transport @@ -19,8 +19,8 @@ public class ServiceRequestMessageTest [Ignore] // placeholder public void ServiceRequestMessageConstructorTest() { - ServiceName serviceName = new ServiceName(); // TODO: Initialize to an appropriate value - ServiceRequestMessage target = new ServiceRequestMessage(serviceName); + var serviceName = new ServiceName(); // TODO: Initialize to an appropriate value + var target = new ServiceRequestMessage(serviceName); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/UnimplementedMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/UnimplementedMessageTest.cs index 8abdd4ad5..5e8d53add 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/UnimplementedMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Transport/UnimplementedMessageTest.cs @@ -1,6 +1,5 @@ 锘縰sing Renci.SshNet.Messages.Transport; using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Messages.Transport @@ -19,7 +18,7 @@ public class UnimplementedMessageTest : TestBase [Ignore] // placeholder public void UnimplementedMessageConstructorTest() { - UnimplementedMessage target = new UnimplementedMessage(); + var target = new UnimplementedMessage(); Assert.Inconclusive("TODO: Implement code to verify target"); } } diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTestBase.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTestBase.cs index ee8cb018b..4c6cbe7f0 100644 --- a/src/Renci.SshNet.Tests/Classes/NetConfClientTestBase.cs +++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTestBase.cs @@ -5,13 +5,13 @@ namespace Renci.SshNet.Tests.Classes { public abstract class NetConfClientTestBase : BaseClientTestBase { - internal Mock _netConfSessionMock { get; private set; } + internal Mock NetConfSessionMock { get; private set; } protected override void CreateMocks() { base.CreateMocks(); - _netConfSessionMock = new Mock(MockBehavior.Strict); + NetConfSessionMock = new Mock(MockBehavior.Strict); } } } diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs index 980c574a1..88410acc1 100644 --- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs +++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs @@ -1,10 +1,12 @@ 锘縰sing System; using System.Reflection; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; -using Renci.SshNet.NetConf; using Renci.SshNet.Security; namespace Renci.SshNet.Tests.Classes @@ -21,31 +23,31 @@ protected override void SetupData() { _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth")); _netConfSessionConnectionException = new ApplicationException(); - _netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object); + _netConfClient = new NetConfClient(_connectionInfo, false, ServiceFactoryMock.Object); } protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence) - .Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateNetConfSession(_sessionMock.Object, -1)) - .Returns(_netConfSessionMock.Object); - _netConfSessionMock.InSequence(sequence) - .Setup(p => p.Connect()) - .Throws(_netConfSessionConnectionException); - _netConfSessionMock.InSequence(sequence) + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateNetConfSession(SessionMock.Object, -1)) + .Returns(NetConfSessionMock.Object); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Connect()) + .Throws(_netConfSessionConnectionException); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _ = SessionMock.InSequence(sequence) .Setup(p => p.Dispose()); - _sessionMock.InSequence(sequence) - .Setup(p => p.Dispose()); } protected override void Act() @@ -87,7 +89,7 @@ public void ErrorOccuredOnSessionShouldNoLongerBeSignaledViaErrorOccurredOnNetCo _netConfClient.ErrorOccurred += (sender, args) => Interlocked.Increment(ref errorOccurredSignalCount); - _sessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception())); + SessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception())); Assert.AreEqual(0, errorOccurredSignalCount); } @@ -99,7 +101,7 @@ public void HostKeyReceivedOnSessionShouldNoLongerBeSignaledViaHostKeyReceivedOn _netConfClient.HostKeyReceived += (sender, args) => Interlocked.Increment(ref hostKeyReceivedSignalCount); - _sessionMock.Raise(p => p.HostKeyReceived += null, new HostKeyEventArgs(GetKeyHostAlgorithm())); + SessionMock.Raise(p => p.HostKeyReceived += null, new HostKeyEventArgs(GetKeyHostAlgorithm())); Assert.AreEqual(0, hostKeyReceivedSignalCount); } diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs index ba86a7c94..ed0103837 100644 --- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs @@ -1,7 +1,8 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.NetConf; -using System; namespace Renci.SshNet.Tests.Classes { @@ -16,35 +17,37 @@ protected override void SetupData() { _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth")); _operationTimeout = new Random().Next(1000, 10000); - _netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object); - _netConfClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout); + _netConfClient = new NetConfClient(_connectionInfo, false, ServiceFactoryMock.Object) + { + OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout) + }; } protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence) - .Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout)) - .Returns(_netConfSessionMock.Object); - _netConfSessionMock.InSequence(sequence) - .Setup(p => p.Connect()); - _sessionMock.InSequence(sequence) - .Setup(p => p.OnDisconnecting()); - _netConfSessionMock.InSequence(sequence) - .Setup(p => p.Disconnect()); - _sessionMock.InSequence(sequence) - .Setup(p => p.Dispose()); - _netConfSessionMock.InSequence(sequence) - .Setup(p => p.Dispose()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateNetConfSession(SessionMock.Object, _operationTimeout)) + .Returns(NetConfSessionMock.Object); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.OnDisconnecting()); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Disconnect()); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); } protected override void Arrange() @@ -62,50 +65,50 @@ protected override void Act() [TestMethod] public void CreateNetConfSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateNetConfSession(SessionMock.Object, _operationTimeout), Times.Once); } [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void DisconnectOnNetConfSessionShouldBeInvokedOnce() { - _netConfSessionMock.Verify(p => p.Disconnect(), Times.Once); + NetConfSessionMock.Verify(p => p.Disconnect(), Times.Once); } [TestMethod] public void DisconnectOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.Disconnect(), Times.Never); + SessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisposeOnNetConfSessionShouldBeInvokedOnce() { - _netConfSessionMock.Verify(p => p.Dispose(), Times.Once); + NetConfSessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void DisposeOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Dispose(), Times.Once); + SessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void OnDisconnectingOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.OnDisconnecting(), Times.Once); + SessionMock.Verify(p => p.OnDisconnecting(), Times.Once); } } } diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs index 8a4fbcd2e..efbfe7ff2 100644 --- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs +++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs @@ -1,6 +1,7 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.NetConf; + using System; namespace Renci.SshNet.Tests.Classes @@ -19,39 +20,43 @@ public void Setup() Act(); } - [TestCleanup] - public void Cleanup() - { - } - protected override void SetupData() { _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth")); _operationTimeout = new Random().Next(1000, 10000); - _netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object); - _netConfClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout); + _netConfClient = new NetConfClient(_connectionInfo, false, ServiceFactoryMock.Object) + { + OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout) + }; } protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout)) - .Returns(_netConfSessionMock.Object); - _netConfSessionMock.InSequence(sequence).Setup(p => p.Connect()); - _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); - _netConfSessionMock.InSequence(sequence).Setup(p => p.Disconnect()); - _sessionMock.InSequence(sequence).Setup(p => p.Dispose()); - _netConfSessionMock.InSequence(sequence).Setup(p => p.Disconnect()); - _netConfSessionMock.InSequence(sequence).Setup(p => p.Dispose()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateNetConfSession(SessionMock.Object, _operationTimeout)) + .Returns(NetConfSessionMock.Object); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.OnDisconnecting()); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Disconnect()); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Disconnect()); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); } protected override void Arrange() @@ -70,50 +75,50 @@ protected override void Act() [TestMethod] public void CreateNetConfSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateNetConfSession(SessionMock.Object, _operationTimeout), Times.Once); } [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void DisconnectOnNetConfSessionShouldBeInvokedTwice() { - _netConfSessionMock.Verify(p => p.Disconnect(), Times.Exactly(2)); + NetConfSessionMock.Verify(p => p.Disconnect(), Times.Exactly(2)); } [TestMethod] public void DisconnectOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.Disconnect(), Times.Never); + SessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisposeOnNetConfSessionShouldBeInvokedOnce() { - _netConfSessionMock.Verify(p => p.Dispose(), Times.Once); + NetConfSessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void DisposeOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Dispose(), Times.Once); + SessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void OnDisconnectingOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.OnDisconnecting(), Times.Once); + SessionMock.Verify(p => p.OnDisconnecting(), Times.Once); } } } diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs index 9ed692a30..cc5f704f4 100644 --- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs +++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs @@ -1,6 +1,7 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.NetConf; + using System; namespace Renci.SshNet.Tests.Classes @@ -16,29 +17,37 @@ protected override void SetupData() { _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth")); _operationTimeout = new Random().Next(1000, 10000); - _netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object); - _netConfClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout); + _netConfClient = new NetConfClient(_connectionInfo, false, ServiceFactoryMock.Object) + { + OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout) + }; } protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout)) - .Returns(_netConfSessionMock.Object); - _netConfSessionMock.InSequence(sequence).Setup(p => p.Connect()); - _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); - _netConfSessionMock.InSequence(sequence).Setup(p => p.Disconnect()); - _sessionMock.InSequence(sequence).Setup(p => p.Dispose()); - _netConfSessionMock.InSequence(sequence).Setup(p => p.Dispose()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateNetConfSession(SessionMock.Object, _operationTimeout)) + .Returns(NetConfSessionMock.Object); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.OnDisconnecting()); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Disconnect()); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); } protected override void Arrange() @@ -57,50 +66,50 @@ protected override void Act() [TestMethod] public void CreateNetConfSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateNetConfSession(SessionMock.Object, _operationTimeout), Times.Once); } [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void DisconnectOnNetConfSessionShouldBeInvokedOnce() { - _netConfSessionMock.Verify(p => p.Disconnect(), Times.Once); + NetConfSessionMock.Verify(p => p.Disconnect(), Times.Once); } [TestMethod] public void DisconnectOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.Disconnect(), Times.Never); + SessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisposeOnNetConfSessionShouldBeInvokedOnce() { - _netConfSessionMock.Verify(p => p.Dispose(), Times.Once); + NetConfSessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void DisposeOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Dispose(), Times.Once); + SessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void OnDisconnectingOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.OnDisconnecting(), Times.Once); + SessionMock.Verify(p => p.OnDisconnecting(), Times.Once); } } } diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs index 44761e96e..ec827b1e6 100644 --- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs @@ -16,8 +16,10 @@ protected override void SetupData() { _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth")); _operationTimeout = new Random().Next(1000, 10000); - _netConfClient = new NetConfClient(_connectionInfo, false, _serviceFactoryMock.Object); - _netConfClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout); + _netConfClient = new NetConfClient(_connectionInfo, false, ServiceFactoryMock.Object) + { + OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout) + }; _netConfClientWeakRefence = new WeakReference(_netConfClient); } @@ -25,19 +27,19 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence) - .Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateNetConfSession(_sessionMock.Object, _operationTimeout)) - .Returns(_netConfSessionMock.Object); - _netConfSessionMock.InSequence(sequence) - .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateNetConfSession(SessionMock.Object, _operationTimeout)) + .Returns(NetConfSessionMock.Object); + _ = NetConfSessionMock.InSequence(sequence) + .Setup(p => p.Connect()); } protected override void Arrange() @@ -64,7 +66,7 @@ public void DisconnectOnNetConfSessionShouldBeInvokedOnce() // Since we recreated the mocks, this test has no value // We'll leaving ths test just in case we have a solution that does not require us // to recreate the mocks - _netConfSessionMock.Verify(p => p.Disconnect(), Times.Never); + NetConfSessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] @@ -73,7 +75,7 @@ public void DisposeOnNetConfSessionShouldBeInvokedOnce() // Since we recreated the mocks, this test has no value // We'll leaving ths test just in case we have a solution that does not require us // to recreate the mocks - _netConfSessionMock.Verify(p => p.Dispose(), Times.Never); + NetConfSessionMock.Verify(p => p.Dispose(), Times.Never); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs b/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs index 52088160c..824f649f1 100644 --- a/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs @@ -97,7 +97,7 @@ public void Test_ConnectionInfo_Host_Is_Null() { try { - new PasswordConnectionInfo(null, Resources.USERNAME, Resources.PASSWORD); + _ = new PasswordConnectionInfo(null, Resources.USERNAME, Resources.PASSWORD); Assert.Fail(); } catch (ArgumentNullException ex) @@ -113,7 +113,7 @@ public void Test_ConnectionInfo_Host_Is_Null() [ExpectedException(typeof(ArgumentException))] public void Test_ConnectionInfo_Username_Is_Null() { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, null, Resources.PASSWORD); + _ = new PasswordConnectionInfo(Resources.HOST, null, Resources.PASSWORD); } [WorkItem(703), TestMethod] @@ -121,7 +121,7 @@ public void Test_ConnectionInfo_Username_Is_Null() [ExpectedException(typeof(ArgumentNullException))] public void Test_ConnectionInfo_Password_Is_Null() { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, Resources.USERNAME, (string)null); + _ = new PasswordConnectionInfo(Resources.HOST, Resources.USERNAME, (string)null); } [TestMethod] @@ -130,7 +130,7 @@ public void Test_ConnectionInfo_Password_Is_Null() [ExpectedException(typeof(ArgumentException))] public void Test_ConnectionInfo_Username_Is_Whitespace() { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, " ", Resources.PASSWORD); + _ = new PasswordConnectionInfo(Resources.HOST, " ", Resources.PASSWORD); } [WorkItem(703), TestMethod] @@ -138,7 +138,7 @@ public void Test_ConnectionInfo_Username_Is_Whitespace() [ExpectedException(typeof(ArgumentOutOfRangeException))] public void Test_ConnectionInfo_SmallPortNumber() { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, IPEndPoint.MinPort - 1, Resources.USERNAME, Resources.PASSWORD); + _ = new PasswordConnectionInfo(Resources.HOST, IPEndPoint.MinPort - 1, Resources.USERNAME, Resources.PASSWORD); } [WorkItem(703), TestMethod] @@ -146,7 +146,7 @@ public void Test_ConnectionInfo_SmallPortNumber() [ExpectedException(typeof(ArgumentOutOfRangeException))] public void Test_ConnectionInfo_BigPortNumber() { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, IPEndPoint.MaxPort + 1, Resources.USERNAME, Resources.PASSWORD); + _ = new PasswordConnectionInfo(Resources.HOST, IPEndPoint.MaxPort + 1, Resources.USERNAME, Resources.PASSWORD); } [TestMethod] @@ -209,10 +209,10 @@ public void Test_Ssh_Connect_Via_HttpProxy() [Ignore] // placeholder for actual test public void DisposeTest() { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value + var host = string.Empty; // TODO: Initialize to an appropriate value + var username = string.Empty; // TODO: Initialize to an appropriate value byte[] password = null; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, username, password); // TODO: Initialize to an appropriate value + var target = new PasswordConnectionInfo(host, username, password); // TODO: Initialize to an appropriate value target.Dispose(); Assert.Inconclusive("A method that does not return a value cannot be verified."); } @@ -478,4 +478,4 @@ public void PasswordConnectionInfoConstructorTest14() } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index d1c18eabc..4ca6e9544 100644 --- a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs @@ -24,7 +24,9 @@ public void SetUp() public void TearDown() { if (_temporaryFile != null) + { File.Delete(_temporaryFile); + } } /// @@ -36,7 +38,7 @@ public void ConstructorWithFileNameShouldThrowArgumentNullExceptionWhenFileNameI var fileName = string.Empty; try { - new PrivateKeyFile(fileName); + _ = new PrivateKeyFile(fileName); Assert.Fail(); } catch (ArgumentNullException ex) @@ -55,7 +57,7 @@ public void ConstructorWithFileNameShouldThrowArgumentNullExceptionWhenFileNameI var fileName = string.Empty; try { - new PrivateKeyFile(fileName); + _ = new PrivateKeyFile(fileName); Assert.Fail(); } catch (ArgumentNullException ex) @@ -74,7 +76,7 @@ public void ConstructorWithFileNameAndPassphraseShouldThrowArgumentNullException var fileName = string.Empty; try { - new PrivateKeyFile(fileName, "12345"); + _ = new PrivateKeyFile(fileName, "12345"); Assert.Fail(); } catch (ArgumentNullException ex) @@ -93,7 +95,7 @@ public void ConstructorWithFileNameAndPassphraseShouldThrowArgumentNullException var fileName = string.Empty; try { - new PrivateKeyFile(fileName, "12345"); + _ = new PrivateKeyFile(fileName, "12345"); Assert.Fail(); } catch (ArgumentNullException ex) @@ -109,7 +111,7 @@ public void ConstructorWithPrivateKeyShouldThrowArgumentNullExceptionWhenPrivate Stream privateKey = null; try { - new PrivateKeyFile(privateKey); + _ = new PrivateKeyFile(privateKey); Assert.Fail(); } catch (ArgumentNullException ex) @@ -125,7 +127,7 @@ public void ConstructorWithPrivateKeyAndPassphraseShouldThrowArgumentNullExcepti Stream privateKey = null; try { - new PrivateKeyFile(privateKey, "12345"); + _ = new PrivateKeyFile(privateKey, "12345"); Assert.Fail(); } catch (ArgumentNullException ex) @@ -142,7 +144,7 @@ public void Test_PrivateKey_RSA() { using (var stream = GetData("Key.RSA.txt")) { - new PrivateKeyFile(stream); + _ = new PrivateKeyFile(stream); } } @@ -153,7 +155,7 @@ public void Test_PrivateKey_SSH2_DSA() { using (var stream = GetData("Key.SSH2.DSA.txt")) { - new PrivateKeyFile(stream); + _ = new PrivateKeyFile(stream); } } @@ -164,7 +166,7 @@ public void Test_PrivateKey_SSH2_RSA() { using (var stream = GetData("Key.SSH2.RSA.txt")) { - new PrivateKeyFile(stream); + _ = new PrivateKeyFile(stream); } } @@ -175,7 +177,7 @@ public void Test_PrivateKey_SSH2_Encrypted_DSA_DES_CBC() { using (var stream = GetData("Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -186,7 +188,7 @@ public void Test_PrivateKey_SSH2_Encrypted_RSA_DES_CBC() { using (var stream = GetData("Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -199,7 +201,7 @@ public void Test_PrivateKey_SSH2_Encrypted_ShouldThrowSshExceptionWhenPassphrase { try { - new PrivateKeyFile(stream, "34567"); + _ = new PrivateKeyFile(stream, "34567"); Assert.Fail(); } catch (SshException ex) @@ -220,7 +222,7 @@ public void Test_PrivateKey_SSH2_Encrypted_ShouldThrowSshPassPhraseNullOrEmptyEx { try { - new PrivateKeyFile(stream, null); + _ = new PrivateKeyFile(stream, null); Assert.Fail(); } catch (SshPassPhraseNullOrEmptyException ex) @@ -241,7 +243,7 @@ public void Test_PrivateKey_SSH2_Encrypted_ShouldThrowSshPassPhraseNullOrEmptyEx { try { - new PrivateKeyFile(stream, string.Empty); + _ = new PrivateKeyFile(stream, string.Empty); Assert.Fail(); } catch (SshPassPhraseNullOrEmptyException ex) @@ -260,7 +262,7 @@ public void Test_PrivateKey_RSA_DES_CBC() { using (var stream = GetData("Key.RSA.Encrypted.Des.CBC.12345.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -271,7 +273,7 @@ public void Test_PrivateKey_RSA_DES_EDE3_CBC() { using (var stream = GetData("Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -282,7 +284,7 @@ public void Test_PrivateKey_RSA_AES_128_CBC() { using (var stream = GetData("Key.RSA.Encrypted.Aes.128.CBC.12345.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -293,7 +295,7 @@ public void Test_PrivateKey_RSA_AES_192_CBC() { using (var stream = GetData("Key.RSA.Encrypted.Aes.192.CBC.12345.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -304,7 +306,7 @@ public void Test_PrivateKey_RSA_AES_256_CBC() { using (var stream = GetData("Key.RSA.Encrypted.Aes.256.CBC.12345.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -315,7 +317,7 @@ public void Test_PrivateKey_RSA_DES_EDE3_CFB() { using (var stream = GetData("Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt")) { - new PrivateKeyFile(stream, "1234567890"); + _ = new PrivateKeyFile(stream, "1234567890"); } } @@ -326,7 +328,7 @@ public void Test_PrivateKey_ECDSA() { using (var stream = GetData("Key.ECDSA.txt")) { - new PrivateKeyFile(stream); + _ = new PrivateKeyFile(stream); } } @@ -337,7 +339,7 @@ public void Test_PrivateKey_ECDSA384() { using (var stream = GetData("Key.ECDSA384.txt")) { - new PrivateKeyFile(stream); + _ = new PrivateKeyFile(stream); } } @@ -348,7 +350,7 @@ public void Test_PrivateKey_ECDSA521() { using (var stream = GetData("Key.ECDSA521.txt")) { - new PrivateKeyFile(stream); + _ = new PrivateKeyFile(stream); } } @@ -359,7 +361,7 @@ public void Test_PrivateKey_ECDSA_Encrypted() { using (var stream = GetData("Key.ECDSA.Encrypted.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -370,7 +372,7 @@ public void Test_PrivateKey_ECDSA384_Encrypted() { using (var stream = GetData("Key.ECDSA384.Encrypted.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -381,7 +383,7 @@ public void Test_PrivateKey_ECDSA521_Encrypted() { using (var stream = GetData("Key.ECDSA521.Encrypted.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -446,7 +448,7 @@ public void ConstructorWithFileNameAndPassphraseShouldThrowSshPassPhraseNullOrEm try { - new PrivateKeyFile(_temporaryFile, passphrase); + _ = new PrivateKeyFile(_temporaryFile, passphrase); Assert.Fail(); } catch (SshPassPhraseNullOrEmptyException ex) @@ -471,7 +473,7 @@ public void ConstructorWithFileNameAndPassphraseShouldThrowSshPassPhraseNullOrEm try { - new PrivateKeyFile(_temporaryFile, passphrase); + _ = new PrivateKeyFile(_temporaryFile, passphrase); Assert.Fail(); } catch (SshPassPhraseNullOrEmptyException ex) @@ -552,7 +554,7 @@ public void Test_PrivateKey_OPENSSH_ED25519() { using (var stream = GetData("Key.OPENSSH.ED25519.txt")) { - new PrivateKeyFile(stream); + _ = new PrivateKeyFile(stream); } } @@ -563,7 +565,7 @@ public void Test_PrivateKey_OPENSSH_ED25519_ENCRYPTED() { using (var stream = GetData("Key.OPENSSH.ED25519.Encrypted.txt")) { - new PrivateKeyFile(stream, "password"); + _ = new PrivateKeyFile(stream, "password"); } } @@ -574,7 +576,7 @@ public void Test_PrivateKey_OPENSSH_RSA() { using (var stream = GetData("Key.OPENSSH.RSA.txt")) { - new PrivateKeyFile(stream); + _ = new PrivateKeyFile(stream); } } @@ -585,7 +587,7 @@ public void Test_PrivateKey_OPENSSH_RSA_ENCRYPTED() { using (var stream = GetData("Key.OPENSSH.RSA.Encrypted.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -596,7 +598,7 @@ public void Test_PrivateKey_OPENSSH_ECDSA() { using (var stream = GetData("Key.OPENSSH.ECDSA.txt")) { - new PrivateKeyFile(stream); + _ = new PrivateKeyFile(stream); } } @@ -607,7 +609,7 @@ public void Test_PrivateKey_OPENSSH_ECDSA_ENCRYPTED() { using (var stream = GetData("Key.OPENSSH.ECDSA.Encrypted.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -618,7 +620,7 @@ public void Test_PrivateKey_OPENSSH_ECDSA384() { using (var stream = GetData("Key.OPENSSH.ECDSA384.txt")) { - new PrivateKeyFile(stream); + _ = new PrivateKeyFile(stream); } } @@ -629,7 +631,7 @@ public void Test_PrivateKey_OPENSSH_ECDSA384_ENCRYPTED() { using (var stream = GetData("Key.OPENSSH.ECDSA384.Encrypted.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } @@ -640,7 +642,7 @@ public void Test_PrivateKey_OPENSSH_ECDSA521() { using (var stream = GetData("Key.OPENSSH.ECDSA521.txt")) { - new PrivateKeyFile(stream); + _ = new PrivateKeyFile(stream); } } @@ -651,7 +653,7 @@ public void Test_PrivateKey_OPENSSH_ECDSA521_ENCRYPTED() { using (var stream = GetData("Key.OPENSSH.ECDSA521.Encrypted.txt")) { - new PrivateKeyFile(stream, "12345"); + _ = new PrivateKeyFile(stream, "12345"); } } diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs index 038d952e0..a9af0c3dd 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs @@ -1,15 +1,15 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; -using System; +锘縰sing System; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; -#if FEATURE_TPL using System.Threading.Tasks; -#endif // FEATURE_TPL + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; +using Renci.SshNet.Tests.Properties; namespace Renci.SshNet.Tests.Classes { @@ -34,7 +34,7 @@ public void Ctor_ConnectionInfo_Null() try { - new ScpClient(connectionInfo); + _ = new ScpClient(connectionInfo); Assert.Fail(); } catch (ArgumentNullException ex) @@ -230,10 +230,10 @@ public void Test_Scp_File_Upload_Download() { scp.Connect(); - string uploadedFileName = Path.GetTempFileName(); - string downloadedFileName = Path.GetTempFileName(); + var uploadedFileName = Path.GetTempFileName(); + var downloadedFileName = Path.GetTempFileName(); - this.CreateTestFile(uploadedFileName, 1); + CreateTestFile(uploadedFileName, 1); scp.Upload(new FileInfo(uploadedFileName), Path.GetFileName(uploadedFileName)); @@ -263,10 +263,10 @@ public void Test_Scp_Stream_Upload_Download() { scp.Connect(); - string uploadedFileName = Path.GetTempFileName(); - string downloadedFileName = Path.GetTempFileName(); + var uploadedFileName = Path.GetTempFileName(); + var downloadedFileName = Path.GetTempFileName(); - this.CreateTestFile(uploadedFileName, 1); + CreateTestFile(uploadedFileName, 1); // Calculate has value using (var stream = File.OpenRead(uploadedFileName)) @@ -303,10 +303,10 @@ public void Test_Scp_10MB_File_Upload_Download() { scp.Connect(); - string uploadedFileName = Path.GetTempFileName(); - string downloadedFileName = Path.GetTempFileName(); + var uploadedFileName = Path.GetTempFileName(); + var downloadedFileName = Path.GetTempFileName(); - this.CreateTestFile(uploadedFileName, 10); + CreateTestFile(uploadedFileName, 10); scp.Upload(new FileInfo(uploadedFileName), Path.GetFileName(uploadedFileName)); @@ -336,10 +336,10 @@ public void Test_Scp_10MB_Stream_Upload_Download() { scp.Connect(); - string uploadedFileName = Path.GetTempFileName(); - string downloadedFileName = Path.GetTempFileName(); + var uploadedFileName = Path.GetTempFileName(); + var downloadedFileName = Path.GetTempFileName(); - this.CreateTestFile(uploadedFileName, 10); + CreateTestFile(uploadedFileName, 10); // Calculate has value using (var stream = File.OpenRead(uploadedFileName)) @@ -378,15 +378,16 @@ public void Test_Scp_Directory_Upload_Download() var uploadDirectory = Directory.CreateDirectory(string.Format("{0}\\{1}", Path.GetTempPath(), Path.GetRandomFileName())); - for (int i = 0; i < 3; i++) + for (var i = 0; i < 3; i++) { - var subfolder = - Directory.CreateDirectory(string.Format(@"{0}\folder_{1}", uploadDirectory.FullName, i)); - for (int j = 0; j < 5; j++) + var subfolder = Directory.CreateDirectory(string.Format(@"{0}\folder_{1}", uploadDirectory.FullName, i)); + + for (var j = 0; j < 5; j++) { - this.CreateTestFile(string.Format(@"{0}\file_{1}", subfolder.FullName, j), 1); + CreateTestFile(string.Format(@"{0}\file_{1}", subfolder.FullName, j), 1); } - this.CreateTestFile(string.Format(@"{0}\file_{1}", uploadDirectory.FullName, i), 1); + + CreateTestFile(string.Format(@"{0}\file_{1}", uploadDirectory.FullName, i), 1); } scp.Upload(uploadDirectory, "uploaded_dir"); @@ -396,8 +397,8 @@ public void Test_Scp_Directory_Upload_Download() scp.Download("uploaded_dir", downloadDirectory); - var uploadedFiles = uploadDirectory.GetFiles("*.*", System.IO.SearchOption.AllDirectories); - var downloadFiles = downloadDirectory.GetFiles("*.*", System.IO.SearchOption.AllDirectories); + var uploadedFiles = uploadDirectory.GetFiles("*.*", SearchOption.AllDirectories); + var downloadFiles = downloadDirectory.GetFiles("*.*", SearchOption.AllDirectories); var result = from f1 in uploadedFiles from f2 in downloadFiles @@ -423,11 +424,10 @@ from f2 in downloadFiles public void OperationTimeoutTest() { ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - ScpClient target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value - TimeSpan expected = new TimeSpan(); // TODO: Initialize to an appropriate value - TimeSpan actual; + var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value + var expected = new TimeSpan(); // TODO: Initialize to an appropriate value target.OperationTimeout = expected; - actual = target.OperationTimeout; + var actual = target.OperationTimeout; Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); } @@ -440,7 +440,7 @@ public void OperationTimeoutTest() public void BufferSizeTest() { ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - ScpClient target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value + var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value uint expected = 0; // TODO: Initialize to an appropriate value uint actual; target.BufferSize = expected; @@ -457,9 +457,9 @@ public void BufferSizeTest() public void UploadTest() { ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - ScpClient target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value + var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value DirectoryInfo directoryInfo = null; // TODO: Initialize to an appropriate value - string filename = string.Empty; // TODO: Initialize to an appropriate value + var filename = string.Empty; // TODO: Initialize to an appropriate value target.Upload(directoryInfo, filename); Assert.Inconclusive("A method that does not return a value cannot be verified."); } @@ -472,9 +472,9 @@ public void UploadTest() public void UploadTest1() { ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - ScpClient target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value + var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value FileInfo fileInfo = null; // TODO: Initialize to an appropriate value - string filename = string.Empty; // TODO: Initialize to an appropriate value + var filename = string.Empty; // TODO: Initialize to an appropriate value target.Upload(fileInfo, filename); Assert.Inconclusive("A method that does not return a value cannot be verified."); } @@ -487,9 +487,9 @@ public void UploadTest1() public void UploadTest2() { ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - ScpClient target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value + var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value Stream source = null; // TODO: Initialize to an appropriate value - string filename = string.Empty; // TODO: Initialize to an appropriate value + var filename = string.Empty; // TODO: Initialize to an appropriate value target.Upload(source, filename); Assert.Inconclusive("A method that does not return a value cannot be verified."); } @@ -502,8 +502,8 @@ public void UploadTest2() public void DownloadTest() { ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - ScpClient target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value - string directoryName = string.Empty; // TODO: Initialize to an appropriate value + var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value + var directoryName = string.Empty; // TODO: Initialize to an appropriate value DirectoryInfo directoryInfo = null; // TODO: Initialize to an appropriate value target.Download(directoryName, directoryInfo); Assert.Inconclusive("A method that does not return a value cannot be verified."); @@ -517,8 +517,8 @@ public void DownloadTest() public void DownloadTest1() { ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - ScpClient target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value - string filename = string.Empty; // TODO: Initialize to an appropriate value + var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value + var filename = string.Empty; // TODO: Initialize to an appropriate value FileInfo fileInfo = null; // TODO: Initialize to an appropriate value target.Download(filename, fileInfo); Assert.Inconclusive("A method that does not return a value cannot be verified."); @@ -532,14 +532,13 @@ public void DownloadTest1() public void DownloadTest2() { ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - ScpClient target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value - string filename = string.Empty; // TODO: Initialize to an appropriate value + var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value + var filename = string.Empty; // TODO: Initialize to an appropriate value Stream destination = null; // TODO: Initialize to an appropriate value target.Download(filename, destination); Assert.Inconclusive("A method that does not return a value cannot be verified."); } -#if FEATURE_TPL [TestMethod] [TestCategory("Scp")] [TestCategory("integration")] @@ -550,27 +549,25 @@ public void Test_Scp_File_20_Parallel_Upload_Download() scp.Connect(); var uploadFilenames = new string[20]; - for (int i = 0; i < uploadFilenames.Length; i++) + for (var i = 0; i < uploadFilenames.Length; i++) { uploadFilenames[i] = Path.GetTempFileName(); - this.CreateTestFile(uploadFilenames[i], 1); + CreateTestFile(uploadFilenames[i], 1); } - Parallel.ForEach(uploadFilenames, - (filename) => - { - scp.Upload(new FileInfo(filename), Path.GetFileName(filename)); - }); - - Parallel.ForEach(uploadFilenames, - (filename) => - { - scp.Download(Path.GetFileName(filename), new FileInfo(string.Format("{0}.down", filename))); - }); + _ = Parallel.ForEach(uploadFilenames, + filename => + { + scp.Upload(new FileInfo(filename), Path.GetFileName(filename)); + }); + _ = Parallel.ForEach(uploadFilenames, + filename => + { + scp.Download(Path.GetFileName(filename), new FileInfo(string.Format("{0}.down", filename))); + }); var result = from file in uploadFilenames - where - CalculateMD5(file) == CalculateMD5(string.Format("{0}.down", file)) + where CalculateMD5(file) == CalculateMD5(string.Format("{0}.down", file)) select file; scp.Disconnect(); @@ -590,13 +587,13 @@ public void Test_Scp_File_Upload_Download_Events() var uploadFilenames = new string[10]; - for (int i = 0; i < uploadFilenames.Length; i++) + for (var i = 0; i < uploadFilenames.Length; i++) { uploadFilenames[i] = Path.GetTempFileName(); - this.CreateTestFile(uploadFilenames[i], 1); + CreateTestFile(uploadFilenames[i], 1); } - var uploadedFiles = uploadFilenames.ToDictionary((filename) => Path.GetFileName(filename), (filename) => 0L); + var uploadedFiles = uploadFilenames.ToDictionary(Path.GetFileName, (filename) => 0L); var downloadedFiles = uploadFilenames.ToDictionary((filename) => string.Format("{0}.down", Path.GetFileName(filename)), (filename) => 0L); scp.Uploading += delegate (object sender, ScpUploadEventArgs e) @@ -609,23 +606,20 @@ public void Test_Scp_File_Upload_Download_Events() downloadedFiles[string.Format("{0}.down", e.Filename)] = e.Downloaded; }; - Parallel.ForEach(uploadFilenames, - (filename) => - { - scp.Upload(new FileInfo(filename), Path.GetFileName(filename)); - }); - - Parallel.ForEach(uploadFilenames, - (filename) => - { - scp.Download(Path.GetFileName(filename), new FileInfo(string.Format("{0}.down", filename))); - }); + _ = Parallel.ForEach(uploadFilenames, + filename => + { + scp.Upload(new FileInfo(filename), Path.GetFileName(filename)); + }); + _ = Parallel.ForEach(uploadFilenames, + filename => + { + scp.Download(Path.GetFileName(filename), new FileInfo(string.Format("{0}.down", filename))); + }); var result = from uf in uploadedFiles from df in downloadedFiles - where - string.Format("{0}.down", uf.Key) == df.Key - && uf.Value == df.Value + where string.Format("{0}.down", uf.Key) == df.Key && uf.Value == df.Value select uf; scp.Disconnect(); @@ -633,21 +627,31 @@ from df in downloadedFiles Assert.IsTrue(result.Count() == uploadFilenames.Length && uploadFilenames.Length == uploadedFiles.Count && uploadedFiles.Count == downloadedFiles.Count); } } -#endif // FEATURE_TPL protected static string CalculateMD5(string fileName) { using (var file = new FileStream(fileName, FileMode.Open)) { - var md5 = new MD5CryptoServiceProvider(); - byte[] retVal = md5.ComputeHash(file); +#if NET7_0_OR_GREATER + var hash = MD5.HashData(file); +#else +#if NET6_0 + var md5 = MD5.Create(); +#else + MD5 md5 = new MD5CryptoServiceProvider(); +#endif // NET6_0 + var hash = md5.ComputeHash(file); +#endif // NET7_0_OR_GREATER + file.Close(); var sb = new StringBuilder(); - for (var i = 0; i < retVal.Length; i++) + + for (var i = 0; i < hash.Length; i++) { - sb.Append(i.ToString("x2")); + _ = sb.Append(i.ToString("x2")); } + return sb.ToString(); } } @@ -657,7 +661,7 @@ private static void RemoveAllFiles() using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) { client.Connect(); - client.RunCommand("rm -rf *"); + _ = client.RunCommand("rm -rf *"); client.Disconnect(); } } @@ -678,4 +682,4 @@ private PrivateKeyFile GetDsaKey() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs index 620f3dd29..f64e039ee 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs @@ -34,18 +34,18 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateRemotePathDoubleQuoteTransformation()) .Returns(_remotePathTransformationMock.Object); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.Connect()); + ServiceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); _channelSessionMock.InSequence(sequence).Setup(p => p.Open()); _remotePathTransformationMock.InSequence(sequence) .Setup(p => p.Transform(_path)) @@ -61,7 +61,7 @@ protected override void Arrange() { base.Arrange(); - _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object); + _scpClient = new ScpClient(_connectionInfo, false, ServiceFactoryMock.Object); _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args); _scpClient.Connect(); } diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs index f0ea9758a..08eba4ff8 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs @@ -34,18 +34,18 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateRemotePathDoubleQuoteTransformation()) .Returns(_remotePathTransformationMock.Object); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.Connect()); + ServiceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); _channelSessionMock.InSequence(sequence).Setup(p => p.Open()); _remotePathTransformationMock.InSequence(sequence) .Setup(p => p.Transform(_path)) @@ -60,7 +60,7 @@ protected override void Arrange() { base.Arrange(); - _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object); + _scpClient = new ScpClient(_connectionInfo, false, ServiceFactoryMock.Object); _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args); _scpClient.Connect(); } diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs index bbb025209..143938c38 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs @@ -34,34 +34,42 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateRemotePathDoubleQuoteTransformation()) - .Returns(_remotePathTransformationMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); - _channelSessionMock.InSequence(sequence).Setup(p => p.Open()); - _remotePathTransformationMock.InSequence(sequence) - .Setup(p => p.Transform(_path)) - .Returns(_transformedPath); - _channelSessionMock.InSequence(sequence) - .Setup(p => p.SendExecRequest(string.Format("scp -f {0}", _transformedPath))) - .Returns(false); - _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); - _pipeStreamMock.InSequence(sequence).Setup(p => p.Close()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateRemotePathDoubleQuoteTransformation()) + .Returns(_remotePathTransformationMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreatePipeStream()) + .Returns(_pipeStreamMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionMock.Object); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.Open()); + _ = _remotePathTransformationMock.InSequence(sequence) + .Setup(p => p.Transform(_path)) + .Returns(_transformedPath); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendExecRequest(string.Format("scp -f {0}", _transformedPath))) + .Returns(false); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _ = _pipeStreamMock.InSequence(sequence) + .Setup(p => p.Close()); } protected override void Arrange() { base.Arrange(); - _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object); + _scpClient = new ScpClient(_connectionInfo, false, ServiceFactoryMock.Object); _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args); _scpClient.Connect(); } @@ -70,10 +78,7 @@ protected override void TearDown() { base.TearDown(); - if (_destination != null) - { - _destination.Dispose(); - } + _destination?.Dispose(); } protected override void Act() diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs index f2521136a..71c1c0cd8 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs @@ -33,18 +33,18 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateRemotePathDoubleQuoteTransformation()) .Returns(_remotePathTransformationMock.Object); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.Connect()); + ServiceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); _channelSessionMock.InSequence(sequence).Setup(p => p.Open()); _remotePathTransformationMock.InSequence(sequence) .Setup(p => p.Transform(_path)) @@ -60,7 +60,7 @@ protected override void Arrange() { base.Arrange(); - _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object); + _scpClient = new ScpClient(_connectionInfo, false, ServiceFactoryMock.Object); _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args); _scpClient.Connect(); } diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs index 782ffe977..288790d22 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs @@ -39,18 +39,18 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateRemotePathDoubleQuoteTransformation()) .Returns(_remotePathTransformationMock.Object); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.Connect()); + ServiceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); _channelSessionMock.InSequence(sequence).Setup(p => p.Open()); _remotePathTransformationMock.InSequence(sequence) .Setup(p => p.Transform(_remoteDirectory)) @@ -66,7 +66,7 @@ protected override void Arrange() { base.Arrange(); - _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object); + _scpClient = new ScpClient(_connectionInfo, false, ServiceFactoryMock.Object); _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args); _scpClient.Connect(); } diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs index 6e31f4e2a..1df8d6ac2 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs @@ -46,52 +46,64 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateRemotePathDoubleQuoteTransformation()) - .Returns(_remotePathTransformationMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); - _channelSessionMock.InSequence(sequence).Setup(p => p.Open()); - _remotePathTransformationMock.InSequence(sequence) - .Setup(p => p.Transform(_remoteDirectory)) - .Returns(_transformedPath); - _channelSessionMock.InSequence(sequence) - .Setup(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath))) - .Returns(true); - _pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0); - _channelSessionMock.InSequence(sequence).Setup(p => p.SendData(It.IsAny())); - _pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0); - _channelSessionMock.InSequence(sequence) - .Setup(p => p.SendData(It.Is(b => b.SequenceEqual( - CreateData(string.Format("C0644 {0} {1}\n", _fileInfo.Length, _remoteFile), - _connectionInfo.Encoding))))); - _pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0); - _channelSessionMock.InSequence(sequence) - .Setup( - p => p.SendData(It.Is(b => b.SequenceEqual(_fileContent.Take(_bufferSize))), 0, _bufferSize)); - _channelSessionMock.InSequence(sequence) - .Setup( - p => p.SendData(It.Is(b => b.Take(0, _fileContent.Length - _bufferSize).SequenceEqual(_fileContent.Take(_bufferSize, _fileContent.Length - _bufferSize))), 0, _fileContent.Length - _bufferSize)); - _channelSessionMock.InSequence(sequence) - .Setup( - p => p.SendData(It.Is(b => b.SequenceEqual(new byte[] {0})))); - _pipeStreamMock.InSequence(sequence).Setup(p => p.ReadByte()).Returns(0); - _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); - _pipeStreamMock.InSequence(sequence).Setup(p => p.Close()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateRemotePathDoubleQuoteTransformation()) + .Returns(_remotePathTransformationMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreatePipeStream()) + .Returns(_pipeStreamMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionMock.Object); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.Open()); + _ = _remotePathTransformationMock.InSequence(sequence) + .Setup(p => p.Transform(_remoteDirectory)) + .Returns(_transformedPath); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath))) + .Returns(true); + _ = _pipeStreamMock.InSequence(sequence) + .Setup(p => p.ReadByte()) + .Returns(0); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendData(It.IsAny())); + _ = _pipeStreamMock.InSequence(sequence) + .Setup(p => p.ReadByte()) + .Returns(0); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendData(It.Is(b => b.SequenceEqual(CreateData(string.Format("C0644 {0} {1}\n", _fileInfo.Length, _remoteFile), _connectionInfo.Encoding))))); + _ = _pipeStreamMock.InSequence(sequence) + .Setup(p => p.ReadByte()) + .Returns(0); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendData(It.Is(b => b.SequenceEqual(_fileContent.Take(_bufferSize))), 0, _bufferSize)); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendData(It.Is(b => b.Take(0, _fileContent.Length - _bufferSize).SequenceEqual(_fileContent.Take(_bufferSize, _fileContent.Length - _bufferSize))), 0, _fileContent.Length - _bufferSize)); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendData(It.Is(b => b.SequenceEqual(new byte[] {0})))); + _ = _pipeStreamMock.InSequence(sequence) + .Setup(p => p.ReadByte()) + .Returns(0); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _ = _pipeStreamMock.InSequence(sequence) + .Setup(p => p.Close()); } protected override void Arrange() { base.Arrange(); - _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object) + _scpClient = new ScpClient(_connectionInfo, false, ServiceFactoryMock.Object) { BufferSize = (uint) _bufferSize }; @@ -162,7 +174,10 @@ private static byte[] CreateContent(int length) var content = new byte[length]; for (var i = 0; i < length; i++) + { content[i] = (byte) random.Next(byte.MinValue, byte.MaxValue); + } + return content; } diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs index f253a8da2..64fd8bc24 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs @@ -1,8 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes @@ -37,34 +40,42 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateRemotePathDoubleQuoteTransformation()) - .Returns(_remotePathTransformationMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence).Setup(p => p.CreatePipeStream()).Returns(_pipeStreamMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); - _channelSessionMock.InSequence(sequence).Setup(p => p.Open()); - _remotePathTransformationMock.InSequence(sequence) - .Setup(p => p.Transform(_remoteDirectory)) - .Returns(_transformedPath); - _channelSessionMock.InSequence(sequence) - .Setup(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath))) - .Returns(false); - _channelSessionMock.InSequence(sequence).Setup(p => p.Dispose()); - _pipeStreamMock.InSequence(sequence).Setup(p => p.Close()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateRemotePathDoubleQuoteTransformation()) + .Returns(_remotePathTransformationMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreatePipeStream()) + .Returns(_pipeStreamMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionMock.Object); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.Open()); + _ = _remotePathTransformationMock.InSequence(sequence) + .Setup(p => p.Transform(_remoteDirectory)) + .Returns(_transformedPath); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendExecRequest(string.Format("scp -t -d {0}", _transformedPath))) + .Returns(false); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _ = _pipeStreamMock.InSequence(sequence) + .Setup(p => p.Close()); } protected override void Arrange() { base.Arrange(); - _scpClient = new ScpClient(_connectionInfo, false, _serviceFactoryMock.Object); + _scpClient = new ScpClient(_connectionInfo, false, ServiceFactoryMock.Object); _scpClient.Uploading += (sender, args) => _uploadingRegister.Add(args); _scpClient.Connect(); } @@ -73,10 +84,7 @@ protected override void TearDown() { base.TearDown(); - if (_source != null) - { - _source.Dispose(); - } + _source?.Dispose(); } protected override void Act() diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs index 1fd7b7d11..1c2d0aec8 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs @@ -20,11 +20,13 @@ public void Test_Cipher_Blowfish_128_CBC() var key = new byte[] { 0xe4, 0x94, 0xf9, 0xb1, 0x00, 0x4f, 0x16, 0x2a, 0x80, 0x11, 0xea, 0x73, 0x0d, 0xb9, 0xbf, 0x64 }; var iv = new byte[] { 0x74, 0x8b, 0x4f, 0xe6, 0xc1, 0x29, 0xb3, 0x54, 0xec, 0x77, 0x92, 0xf3, 0x15, 0xa0, 0x41, 0xa8 }; var output = new byte[] { 0x50, 0x49, 0xe0, 0xce, 0x98, 0x93, 0x8b, 0xec, 0x82, 0x7d, 0x14, 0x1b, 0x3e, 0xdc, 0xca, 0x63, 0xef, 0x36, 0x20, 0x67, 0x58, 0x63, 0x1f, 0x9c, 0xd2, 0x12, 0x6b, 0xca, 0xea, 0xd0, 0x78, 0x8b, 0x61, 0x50, 0x4f, 0xc4, 0x5b, 0x32, 0x91, 0xd6, 0x65, 0xcb, 0x74, 0xe5, 0x6e, 0xf5, 0xde, 0x14 }; - var testCipher = new Renci.SshNet.Security.Cryptography.Ciphers.BlowfishCipher(key, new Renci.SshNet.Security.Cryptography.Ciphers.Modes.CbcCipherMode(iv), null); + var testCipher = new BlowfishCipher(key, new CbcCipherMode(iv), null); var r = testCipher.Encrypt(input); if (!r.SequenceEqual(output)) + { Assert.Fail("Invalid encryption"); + } } [TestMethod] @@ -54,7 +56,7 @@ public void BlowfishCipherConstructorTest() byte[] key = null; // TODO: Initialize to an appropriate value CipherMode mode = null; // TODO: Initialize to an appropriate value CipherPadding padding = null; // TODO: Initialize to an appropriate value - BlowfishCipher target = new BlowfishCipher(key, mode, padding); + var target = new BlowfishCipher(key, mode, padding); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -68,15 +70,14 @@ public void DecryptBlockTest() byte[] key = null; // TODO: Initialize to an appropriate value CipherMode mode = null; // TODO: Initialize to an appropriate value CipherPadding padding = null; // TODO: Initialize to an appropriate value - BlowfishCipher target = new BlowfishCipher(key, mode, padding); // TODO: Initialize to an appropriate value + var target = new BlowfishCipher(key, mode, padding); // TODO: Initialize to an appropriate value byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value + var inputOffset = 0; // TODO: Initialize to an appropriate value + var inputCount = 0; // TODO: Initialize to an appropriate value byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); + var outputOffset = 0; // TODO: Initialize to an appropriate value + var expected = 0; // TODO: Initialize to an appropriate value + var actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); } @@ -91,18 +92,17 @@ public void EncryptBlockTest() byte[] key = null; // TODO: Initialize to an appropriate value CipherMode mode = null; // TODO: Initialize to an appropriate value CipherPadding padding = null; // TODO: Initialize to an appropriate value - BlowfishCipher target = new BlowfishCipher(key, mode, padding); // TODO: Initialize to an appropriate value + var target = new BlowfishCipher(key, mode, padding); // TODO: Initialize to an appropriate value byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value + var inputOffset = 0; // TODO: Initialize to an appropriate value + var inputCount = 0; // TODO: Initialize to an appropriate value byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); + var outputOffset = 0; // TODO: Initialize to an appropriate value + var expected = 0; // TODO: Initialize to an appropriate value + var actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs index f791c9df5..5b4f97bac 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs @@ -1,9 +1,12 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System.Linq; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Security.Cryptography.Ciphers; using Renci.SshNet.Security.Cryptography.Ciphers.Modes; using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; -using System.Linq; + namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers { @@ -24,7 +27,9 @@ public void Test_Cipher_3DES_CBC() var r = testCipher.Encrypt(input); if (!r.SequenceEqual(output)) + { Assert.Fail("Invalid encryption"); + } } [TestMethod] @@ -103,4 +108,4 @@ public void EncryptBlockTest() Assert.Inconclusive("Verify the correctness of this test method."); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DsaDigitalSignatureTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DsaDigitalSignatureTest.cs index 0d3423c95..947ec9c76 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DsaDigitalSignatureTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DsaDigitalSignatureTest.cs @@ -19,7 +19,7 @@ public class DsaDigitalSignatureTest : TestBase public void DsaDigitalSignatureConstructorTest() { DsaKey key = null; // TODO: Initialize to an appropriate value - DsaDigitalSignature target = new DsaDigitalSignature(key); + var target = new DsaDigitalSignature(key); Assert.Inconclusive("TODO: Implement code to verify target"); } @@ -31,7 +31,7 @@ public void DsaDigitalSignatureConstructorTest() public void DisposeTest() { DsaKey key = null; // TODO: Initialize to an appropriate value - DsaDigitalSignature target = new DsaDigitalSignature(key); // TODO: Initialize to an appropriate value + var target = new DsaDigitalSignature(key); // TODO: Initialize to an appropriate value target.Dispose(); Assert.Inconclusive("A method that does not return a value cannot be verified."); } @@ -44,11 +44,10 @@ public void DisposeTest() public void SignTest() { DsaKey key = null; // TODO: Initialize to an appropriate value - DsaDigitalSignature target = new DsaDigitalSignature(key); // TODO: Initialize to an appropriate value + var target = new DsaDigitalSignature(key); // TODO: Initialize to an appropriate value byte[] input = null; // TODO: Initialize to an appropriate value byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Sign(input); + var actual = target.Sign(input); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); } @@ -61,14 +60,13 @@ public void SignTest() public void VerifyTest() { DsaKey key = null; // TODO: Initialize to an appropriate value - DsaDigitalSignature target = new DsaDigitalSignature(key); // TODO: Initialize to an appropriate value + var target = new DsaDigitalSignature(key); // TODO: Initialize to an appropriate value byte[] input = null; // TODO: Initialize to an appropriate value byte[] signature = null; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - actual = target.Verify(input, signature); + var expected = false; // TODO: Initialize to an appropriate value + var actual = target.Verify(input, signature); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/SymmetricCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/SymmetricCipherTest.cs index 8dce88815..92f9da374 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/SymmetricCipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/SymmetricCipherTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Security.Cryptography; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Security.Cryptography; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests @@ -26,15 +26,14 @@ internal virtual SymmetricCipher CreateSymmetricCipher() [Ignore] // placeholder for actual test public void DecryptBlockTest() { - SymmetricCipher target = CreateSymmetricCipher(); // TODO: Initialize to an appropriate value + var target = CreateSymmetricCipher(); // TODO: Initialize to an appropriate value byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value + var inputOffset = 0; // TODO: Initialize to an appropriate value + var inputCount = 0; // TODO: Initialize to an appropriate value byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); + var outputOffset = 0; // TODO: Initialize to an appropriate value + var expected = 0; // TODO: Initialize to an appropriate value + var actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); } @@ -46,15 +45,14 @@ public void DecryptBlockTest() [Ignore] // placeholder for actual test public void EncryptBlockTest() { - SymmetricCipher target = CreateSymmetricCipher(); // TODO: Initialize to an appropriate value + var target = CreateSymmetricCipher(); // TODO: Initialize to an appropriate value byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value + var inputOffset = 0; // TODO: Initialize to an appropriate value + var inputCount = 0; // TODO: Initialize to an appropriate value byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); + var outputOffset = 0; // TODO: Initialize to an appropriate value + var expected = 0; // TODO: Initialize to an appropriate value + var actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); } diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs index 744a434ff..915e4b8f7 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs @@ -1,8 +1,8 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Security; using Renci.SshNet.Tests.Common; -using System.Text; namespace Renci.SshNet.Tests.Classes.Security { @@ -58,4 +58,4 @@ public void NameShouldBeDiffieHellmanGroup14Sha256() Assert.AreEqual("diffie-hellman-group14-sha256", _group14.Name); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeTest.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeTest.cs index 839394e6e..a288292ee 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeTest.cs @@ -1,6 +1,6 @@ -锘縰sing Renci.SshNet.Security; +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Tests.Common; -using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Renci.SshNet.Tests { diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest.HttpProxy.cs b/src/Renci.SshNet.Tests/Classes/SessionTest.HttpProxy.cs deleted file mode 100644 index 03ce2491c..000000000 --- a/src/Renci.SshNet.Tests/Classes/SessionTest.HttpProxy.cs +++ /dev/null @@ -1,36 +0,0 @@ -锘縰sing System; -using System.Net; -using System.Linq; -using System.Text; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; -using Renci.SshNet.Connection; - -namespace Renci.SshNet.Tests.Classes -{ - public partial class SessionTest - { - private static ConnectionInfo CreateConnectionInfoWithHttpProxy(IPEndPoint proxyEndPoint, IPEndPoint serverEndPoint, string proxyUserName) - { - return new ConnectionInfo( - serverEndPoint.Address.ToString(), - serverEndPoint.Port, - "eric", - ProxyTypes.Http, - proxyEndPoint.Address.ToString(), - proxyEndPoint.Port, - proxyUserName, - "proxypwd", - new NoneAuthenticationMethod("eric")); - } - - private static string CreateProxyAuthorizationHeader(ConnectionInfo connectionInfo) - { - return string.Format("Proxy-Authorization: Basic {0}", - Convert.ToBase64String( - Encoding.ASCII.GetBytes(string.Format("{0}:{1}", connectionInfo.ProxyUsername, - connectionInfo.ProxyPassword)))); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest.cs b/src/Renci.SshNet.Tests/Classes/SessionTest.cs index 972757e40..bfb9a4288 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest.cs @@ -1,7 +1,10 @@ 锘縰sing System; using System.Net; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; @@ -15,8 +18,6 @@ public partial class SessionTest : TestBase { private Mock _serviceFactoryMock; private Mock _socketFactoryMock; - private Mock _connectorMock; - private Mock _protocolVersionExchangeMock; protected override void OnInit() { @@ -24,8 +25,6 @@ protected override void OnInit() _serviceFactoryMock = new Mock(MockBehavior.Strict); _socketFactoryMock = new Mock(MockBehavior.Strict); - _connectorMock = new Mock(MockBehavior.Strict); - _protocolVersionExchangeMock = new Mock(MockBehavior.Strict); } [TestMethod] @@ -35,7 +34,7 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenConnectionInfoIsNull( try { - new Session(connectionInfo, _serviceFactoryMock.Object, _socketFactoryMock.Object); + _ = new Session(connectionInfo, _serviceFactoryMock.Object, _socketFactoryMock.Object); Assert.Fail(); } catch (ArgumentNullException ex) @@ -54,7 +53,7 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenServiceFactoryIsNull( try { - new Session(connectionInfo, serviceFactory, _socketFactoryMock.Object); + _ = new Session(connectionInfo, serviceFactory, _socketFactoryMock.Object); Assert.Fail(); } catch (ArgumentNullException ex) @@ -73,7 +72,7 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenSocketFactoryIsNull() try { - new Session(connectionInfo, _serviceFactoryMock.Object, socketFactory); + _ = new Session(connectionInfo, _serviceFactoryMock.Object, socketFactory); Assert.Fail(); } catch (ArgumentNullException ex) @@ -85,13 +84,10 @@ public void ConstructorShouldThrowArgumentNullExceptionWhenSocketFactoryIsNull() private static ConnectionInfo CreateConnectionInfo(IPEndPoint serverEndPoint, TimeSpan timeout) { - var connectionInfo = new ConnectionInfo( - serverEndPoint.Address.ToString(), - serverEndPoint.Port, - "eric", - new NoneAuthenticationMethod("eric")); - connectionInfo.Timeout = timeout; - return connectionInfo; + return new ConnectionInfo(serverEndPoint.Address.ToString(), serverEndPoint.Port, "eric", new NoneAuthenticationMethod("eric")) + { + Timeout = timeout + }; } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTestBase.cs b/src/Renci.SshNet.Tests/Classes/SessionTestBase.cs index cbe69e2af..8b3cce37f 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTestBase.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTestBase.cs @@ -6,15 +6,15 @@ namespace Renci.SshNet.Tests.Classes { public abstract class SessionTestBase : TripleATestBase { - internal Mock _serviceFactoryMock { get; private set; } - internal Mock _socketFactoryMock { get; private set; } - internal Mock _connectorMock { get; private set; } + internal Mock ServiceFactoryMock { get; private set; } + internal Mock SocketFactoryMock { get; private set; } + internal Mock ConnectorMock { get; private set; } protected virtual void CreateMocks() { - _serviceFactoryMock = new Mock(MockBehavior.Strict); - _socketFactoryMock = new Mock(MockBehavior.Strict); - _connectorMock = new Mock(MockBehavior.Strict); + ServiceFactoryMock = new Mock(MockBehavior.Strict); + SocketFactoryMock = new Mock(MockBehavior.Strict); + ConnectorMock = new Mock(MockBehavior.Strict); } protected virtual void SetupData() diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectToServerFails.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectToServerFails.cs index df19c8ec8..16cfbb1ed 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectToServerFails.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectToServerFails.cs @@ -1,7 +1,9 @@ 锘縰sing System; using System.Net; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; @@ -21,7 +23,7 @@ protected override void SetupData() var serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122); _connectionInfo = CreateConnectionInfo(serverEndPoint, TimeSpan.FromSeconds(5)); - _session = new Session(_connectionInfo, _serviceFactoryMock.Object, _socketFactoryMock.Object); + _session = new Session(_connectionInfo, ServiceFactoryMock.Object, SocketFactoryMock.Object); _connectException = new SshConnectionException(); } @@ -29,10 +31,10 @@ protected override void SetupMocks() { base.SetupMocks(); - _serviceFactoryMock.Setup(p => p.CreateConnector(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_connectorMock.Object); - _connectorMock.Setup(p => p.Connect(_connectionInfo)) - .Throws(_connectException); + _ = ServiceFactoryMock.Setup(p => p.CreateConnector(_connectionInfo, SocketFactoryMock.Object)) + .Returns(ConnectorMock.Object); + _ = ConnectorMock.Setup(p => p.Connect(_connectionInfo)) + .Throws(_connectException); } protected override void Act() @@ -163,9 +165,8 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDiscon { var session = (ISession)_session; var waitHandle = new ManualResetEvent(false); - Exception exception; - var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out var exception); Assert.AreEqual(WaitResult.Disconnected, result); Assert.IsNull(exception); @@ -253,13 +254,10 @@ public void ISession_WaitOnHandle_WaitHandleAndTimeout_ShouldThrowArgumentNullEx private static ConnectionInfo CreateConnectionInfo(IPEndPoint serverEndPoint, TimeSpan timeout) { - var connectionInfo = new ConnectionInfo( - serverEndPoint.Address.ToString(), - serverEndPoint.Port, - "eric", - new NoneAuthenticationMethod("eric")); - connectionInfo.Timeout = timeout; - return connectionInfo; + return new ConnectionInfo(serverEndPoint.Address.ToString(), serverEndPoint.Port, "eric", new NoneAuthenticationMethod("eric")) + { + Timeout = timeout + }; } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs index fa36aed5e..f841926b4 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs @@ -197,7 +197,7 @@ public void ISession_TryWait_WaitHandleAndTimeout_ShouldThrowArgumentNullExcepti try { - session.TryWait(waitHandle, Session.InfiniteTimeSpan); + _ = session.TryWait(waitHandle, Session.InfiniteTimeSpan); Assert.Fail(); } catch (ArgumentNullException ex) @@ -212,9 +212,8 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnSucces { var session = (ISession) Session; var waitHandle = new ManualResetEvent(true); - Exception exception; - var result = session.TryWait(waitHandle, TimeSpan.FromMilliseconds(0), out exception); + var result = session.TryWait(waitHandle, TimeSpan.FromMilliseconds(0), out var exception); Assert.AreEqual(WaitResult.Success, result); Assert.IsNull(exception); @@ -225,9 +224,8 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnTimedO { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); - Exception exception; - var result = session.TryWait(waitHandle, TimeSpan.FromMilliseconds(0), out exception); + var result = session.TryWait(waitHandle, TimeSpan.FromMilliseconds(0), out var exception); Assert.AreEqual(WaitResult.TimedOut, result); Assert.IsNull(exception); @@ -272,4 +270,4 @@ public void ConnectorOnConnectorShouldHaveBeenInvokedOnce() ConnectorMock.Verify(p => p.Connect(ConnectionInfo), Times.Once()); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs index a920b1906..8f4bed7c0 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs @@ -4,9 +4,11 @@ using System.Net; using System.Net.Sockets; using System.Security.Cryptography; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Compression; using Renci.SshNet.Connection; @@ -111,11 +113,13 @@ protected virtual void SetupData() { var newKeysMessage = new NewKeysMessage(); var newKeys = newKeysMessage.GetPacket(8, null); - ServerSocket.Send(newKeys, 4, newKeys.Length - 4, SocketFlags.None); + _ = ServerSocket.Send(newKeys, 4, newKeys.Length - 4, SocketFlags.None); }; - ServerListener = new AsyncSocketListener(_serverEndPoint); - ServerListener.ShutdownRemoteCommunicationSocket = false; + ServerListener = new AsyncSocketListener(_serverEndPoint) + { + ShutdownRemoteCommunicationSocket = false + }; ServerListener.Connected += socket => { ServerSocket = socket; @@ -137,7 +141,7 @@ protected virtual void SetupData() ServerHostKeyAlgorithms = new string[0] }; var keyExchangeInit = keyExchangeInitMessage.GetPacket(8, null); - ServerSocket.Send(keyExchangeInit, 4, keyExchangeInit.Length - 4, SocketFlags.None); + _ = ServerSocket.Send(keyExchangeInit, 4, keyExchangeInit.Length - 4, SocketFlags.None); }; ServerListener.BytesReceived += (received, socket) => { @@ -147,7 +151,7 @@ protected virtual void SetupData() { var serviceAcceptMessage = ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication) .Build(); - ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None); + _ = ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None); _authenticationStarted = true; } @@ -169,32 +173,37 @@ private void CreateMocks() private void SetupMocks() { - ServiceFactoryMock.Setup(p => p.CreateConnector(ConnectionInfo, SocketFactoryMock.Object)) - .Returns(ConnectorMock.Object); - ConnectorMock.Setup(p => p.Connect(ConnectionInfo)) - .Returns(ClientSocket); - ServiceFactoryMock.Setup(p => p.CreateProtocolVersionExchange()) - .Returns(_protocolVersionExchangeMock.Object); - _protocolVersionExchangeMock.Setup(p => p.Start(Session.ClientVersion, ClientSocket, ConnectionInfo.Timeout)) - .Returns(ServerIdentification); - - ServiceFactoryMock.Setup( - p => - p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, new[] { _keyExchangeAlgorithm })).Returns(_keyExchangeMock.Object); - _keyExchangeMock.Setup(p => p.Name).Returns(_keyExchangeAlgorithm); - _keyExchangeMock.Setup(p => p.Start(Session, It.IsAny())); - _keyExchangeMock.Setup(p => p.ExchangeHash).Returns(SessionId); - _keyExchangeMock.Setup(p => p.CreateServerCipher()).Returns((Cipher) null); - _keyExchangeMock.Setup(p => p.CreateClientCipher()).Returns((Cipher) null); - _keyExchangeMock.Setup(p => p.CreateServerHash()).Returns((HashAlgorithm) null); - _keyExchangeMock.Setup(p => p.CreateClientHash()).Returns((HashAlgorithm) null); - _keyExchangeMock.Setup(p => p.CreateCompressor()).Returns((Compressor) null); - _keyExchangeMock.Setup(p => p.CreateDecompressor()).Returns((Compressor) null); - _keyExchangeMock.Setup(p => p.Dispose()); - ServiceFactoryMock.Setup(p => p.CreateClientAuthentication()) - .Callback(ClientAuthentication_Callback) - .Returns(_clientAuthenticationMock.Object); - _clientAuthenticationMock.Setup(p => p.Authenticate(ConnectionInfo, Session)); + _ = ServiceFactoryMock.Setup(p => p.CreateConnector(ConnectionInfo, SocketFactoryMock.Object)) + .Returns(ConnectorMock.Object); + _ = ConnectorMock.Setup(p => p.Connect(ConnectionInfo)) + .Returns(ClientSocket); + _ = ServiceFactoryMock.Setup(p => p.CreateProtocolVersionExchange()) + .Returns(_protocolVersionExchangeMock.Object); + _ = _protocolVersionExchangeMock.Setup(p => p.Start(Session.ClientVersion, ClientSocket, ConnectionInfo.Timeout)) + .Returns(ServerIdentification); + _ = ServiceFactoryMock.Setup(p => p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, new[] { _keyExchangeAlgorithm })).Returns(_keyExchangeMock.Object); + _ = _keyExchangeMock.Setup(p => p.Name) + .Returns(_keyExchangeAlgorithm); + _ = _keyExchangeMock.Setup(p => p.Start(Session, It.IsAny())); + _ = _keyExchangeMock.Setup(p => p.ExchangeHash) + .Returns(SessionId); + _ = _keyExchangeMock.Setup(p => p.CreateServerCipher()) + .Returns((Cipher) null); + _ = _keyExchangeMock.Setup(p => p.CreateClientCipher()) + .Returns((Cipher) null); + _ = _keyExchangeMock.Setup(p => p.CreateServerHash()) + .Returns((HashAlgorithm) null); + _ = _keyExchangeMock.Setup(p => p.CreateClientHash()) + .Returns((HashAlgorithm) null); + _ = _keyExchangeMock.Setup(p => p.CreateCompressor()) + .Returns((Compressor) null); + _ = _keyExchangeMock.Setup(p => p.CreateDecompressor()) + .Returns((Compressor) null); + _ = _keyExchangeMock.Setup(p => p.Dispose()); + _ = ServiceFactoryMock.Setup(p => p.CreateClientAuthentication()) + .Callback(ClientAuthentication_Callback) + .Returns(_clientAuthenticationMock.Object); + _ = _clientAuthenticationMock.Setup(p => p.Authenticate(ConnectionInfo, Session)); } protected void Arrange() diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs index f17209beb..fb49e66e8 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs @@ -1,8 +1,8 @@ -锘縰sing System; -using System.Diagnostics; -using System.Net.Sockets; +锘縰sing System.Diagnostics; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; @@ -187,12 +187,11 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDiscon { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); - Exception exception; - var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out var exception); Assert.AreEqual(WaitResult.Disconnected, result); Assert.IsNull(exception); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs index eacb27c39..3b0c9b554 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs @@ -1,8 +1,9 @@ -锘縰sing System; -using System.Diagnostics; +锘縰sing System.Diagnostics; using System.Net.Sockets; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; @@ -100,7 +101,7 @@ public void ISession_MessageListenerCompletedShouldBeSignaled() Assert.IsTrue(session.MessageListenerCompleted.WaitOne()); } - [TestMethodAttribute] + [TestMethod] public void ISession_SendMessageShouldThrowSshConnectionException() { var session = (ISession) Session; @@ -182,9 +183,8 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDiscon { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); - Exception exception; - var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out var exception); Assert.AreEqual(WaitResult.Disconnected, result); Assert.IsNull(exception); @@ -197,4 +197,4 @@ public void ClientSocketShouldNotBeConnected() Assert.IsFalse(ClientSocket.Connected); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs index 68bcbdaac..b565fe1fb 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs @@ -47,15 +47,8 @@ public class SessionTest_Connected_ServerAndClientDisconnectRace private void TearDown() { - if (ServerListener != null) - { - ServerListener.Dispose(); - } - - if (Session != null) - { - Session.Dispose(); - } + ServerListener?.Dispose(); + Session?.Dispose(); if (ClientSocket != null && ClientSocket.Connected) { @@ -95,7 +88,7 @@ protected virtual void SetupData() { var newKeysMessage = new NewKeysMessage(); var newKeys = newKeysMessage.GetPacket(8, null); - ServerSocket.Send(newKeys, 4, newKeys.Length - 4, SocketFlags.None); + _ = ServerSocket.Send(newKeys, 4, newKeys.Length - 4, SocketFlags.None); }; ServerListener = new AsyncSocketListener(_serverEndPoint); @@ -120,7 +113,7 @@ protected virtual void SetupData() ServerHostKeyAlgorithms = new string[0] }; var keyExchangeInit = keyExchangeInitMessage.GetPacket(8, null); - ServerSocket.Send(keyExchangeInit, 4, keyExchangeInit.Length - 4, SocketFlags.None); + _ = ServerSocket.Send(keyExchangeInit, 4, keyExchangeInit.Length - 4, SocketFlags.None); }; ServerListener.BytesReceived += (received, socket) => { @@ -129,7 +122,7 @@ protected virtual void SetupData() if (!_authenticationStarted) { var serviceAcceptMessage =ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication).Build(); - ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None); + _ = ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None); _authenticationStarted = true; } }; @@ -151,29 +144,37 @@ private void CreateMocks() private void SetupMocks() { - _serviceFactoryMock.Setup(p => p.CreateConnector(ConnectionInfo, _socketFactoryMock.Object)) - .Returns(_connectorMock.Object); - _connectorMock.Setup(p => p.Connect(ConnectionInfo)) - .Returns(ClientSocket); - _serviceFactoryMock.Setup(p => p.CreateProtocolVersionExchange()) - .Returns(_protocolVersionExchangeMock.Object); - _protocolVersionExchangeMock.Setup(p => p.Start(Session.ClientVersion, ClientSocket, ConnectionInfo.Timeout)) - .Returns(ServerIdentification); - _serviceFactoryMock.Setup( - p => - p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, new[] { _keyExchangeAlgorithm })).Returns(_keyExchangeMock.Object); - _keyExchangeMock.Setup(p => p.Name).Returns(_keyExchangeAlgorithm); - _keyExchangeMock.Setup(p => p.Start(Session, It.IsAny())); - _keyExchangeMock.Setup(p => p.ExchangeHash).Returns(SessionId); - _keyExchangeMock.Setup(p => p.CreateServerCipher()).Returns((Cipher)null); - _keyExchangeMock.Setup(p => p.CreateClientCipher()).Returns((Cipher)null); - _keyExchangeMock.Setup(p => p.CreateServerHash()).Returns((HashAlgorithm)null); - _keyExchangeMock.Setup(p => p.CreateClientHash()).Returns((HashAlgorithm)null); - _keyExchangeMock.Setup(p => p.CreateCompressor()).Returns((Compressor)null); - _keyExchangeMock.Setup(p => p.CreateDecompressor()).Returns((Compressor)null); - _keyExchangeMock.Setup(p => p.Dispose()); - _serviceFactoryMock.Setup(p => p.CreateClientAuthentication()).Returns(_clientAuthenticationMock.Object); - _clientAuthenticationMock.Setup(p => p.Authenticate(ConnectionInfo, Session)); + _ = _serviceFactoryMock.Setup(p => p.CreateConnector(ConnectionInfo, _socketFactoryMock.Object)) + .Returns(_connectorMock.Object); + _ = _connectorMock.Setup(p => p.Connect(ConnectionInfo)) + .Returns(ClientSocket); + _ = _serviceFactoryMock.Setup(p => p.CreateProtocolVersionExchange()) + .Returns(_protocolVersionExchangeMock.Object); + _ = _protocolVersionExchangeMock.Setup(p => p.Start(Session.ClientVersion, ClientSocket, ConnectionInfo.Timeout)) + .Returns(ServerIdentification); + _ = _serviceFactoryMock.Setup(p => p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, new[] { _keyExchangeAlgorithm })) + .Returns(_keyExchangeMock.Object); + _ = _keyExchangeMock.Setup(p => p.Name) + .Returns(_keyExchangeAlgorithm); + _ = _keyExchangeMock.Setup(p => p.Start(Session, It.IsAny())); + _ = _keyExchangeMock.Setup(p => p.ExchangeHash) + .Returns(SessionId); + _ = _keyExchangeMock.Setup(p => p.CreateServerCipher()) + .Returns((Cipher) null); + _ = _keyExchangeMock.Setup(p => p.CreateClientCipher()) + .Returns((Cipher) null); + _ = _keyExchangeMock.Setup(p => p.CreateServerHash()) + .Returns((HashAlgorithm) null); + _ = _keyExchangeMock.Setup(p => p.CreateClientHash()) + .Returns((HashAlgorithm) null); + _ = _keyExchangeMock.Setup(p => p.CreateCompressor()) + .Returns((Compressor) null); + _ = _keyExchangeMock.Setup(p => p.CreateDecompressor()) + .Returns((Compressor) null); + _ = _keyExchangeMock.Setup(p => p.Dispose()); + _ = _serviceFactoryMock.Setup(p => p.CreateClientAuthentication()) + .Returns(_clientAuthenticationMock.Object); + _ = _clientAuthenticationMock.Setup(p => p.Authenticate(ConnectionInfo, Session)); } protected virtual void Arrange() @@ -194,7 +195,7 @@ public void Act() try { var disconnect = _disconnectMessage.GetPacket(8, null); - ServerSocket.Send(disconnect, 4, disconnect.Length - 4, SocketFlags.None); + _ = ServerSocket.Send(disconnect, 4, disconnect.Length - 4, SocketFlags.None); Session.Disconnect(); } finally diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs index df9790f93..c1f0fb5b2 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs @@ -1,8 +1,9 @@ -锘縰sing System; -using System.Diagnostics; +锘縰sing System.Diagnostics; using System.Net.Sockets; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; @@ -23,7 +24,7 @@ protected override void SetupData() protected override void Act() { - ServerSocket.Send(_packet, 0, _packet.Length, SocketFlags.None); + _ = ServerSocket.Send(_packet, 0, _packet.Length, SocketFlags.None); // give session some time to process packet Thread.Sleep(200); @@ -124,7 +125,7 @@ public void ISession_MessageListenerCompletedShouldBeSignaled() Assert.IsTrue(session.MessageListenerCompleted.WaitOne()); } - [TestMethodAttribute] + [TestMethod] public void ISession_SendMessageShouldThrowSshConnectionException() { var session = (ISession) Session; @@ -206,12 +207,11 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDiscon { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); - Exception exception; - var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out var exception); Assert.AreEqual(WaitResult.Disconnected, result); Assert.IsNull(exception); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs index 36a73d822..7000a2233 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs @@ -1,9 +1,10 @@ -锘縰sing System; -using System.Diagnostics; +锘縰sing System.Diagnostics; using System.Globalization; using System.Net.Sockets; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; @@ -26,7 +27,7 @@ protected override void SetupData() protected override void Act() { - ServerSocket.Send(_packet, 4, _packet.Length - 4, SocketFlags.None); + _ = ServerSocket.Send(_packet, 4, _packet.Length - 4, SocketFlags.None); // give session some time to process packet Thread.Sleep(200); @@ -121,7 +122,7 @@ public void ISession_MessageListenerCompletedShouldBeSignaled() Assert.IsTrue(session.MessageListenerCompleted.WaitOne()); } - [TestMethodAttribute] + [TestMethod] public void ISession_SendMessageShouldThrowSshConnectionException() { var session = (ISession) Session; @@ -211,12 +212,11 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDiscon { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); - Exception exception; - var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out var exception); Assert.AreEqual(WaitResult.Disconnected, result); Assert.IsNull(exception); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs index f3bb98773..b91832a40 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs @@ -1,9 +1,10 @@ -锘縰sing System; -using System.Diagnostics; +锘縰sing System.Diagnostics; using System.Globalization; using System.Net.Sockets; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; @@ -26,7 +27,8 @@ protected override void Act() { // server sends SSH_MSG_DISCONNECT var disconnect = _disconnectMessage.GetPacket(8, null); - ServerSocket.Send(disconnect, 4, disconnect.Length - 4, SocketFlags.None); + + _ = ServerSocket.Send(disconnect, 4, disconnect.Length - 4, SocketFlags.None); // server shuts down the socket ServerSocket.Shutdown(SocketShutdown.Send); @@ -124,7 +126,7 @@ public void ISession_MessageListenerCompletedShouldBeSignaled() Assert.IsTrue(session.MessageListenerCompleted.WaitOne()); } - [TestMethodAttribute] + [TestMethod] public void ISession_SendMessageShouldThrowSshConnectionException() { var session = (ISession) Session; @@ -191,12 +193,11 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDiscon { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); - Exception exception; - var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out var exception); Assert.AreEqual(WaitResult.Disconnected, result); Assert.IsNull(exception); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs index a40f6e031..a748eae43 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs @@ -1,8 +1,9 @@ -锘縰sing System; -using System.Diagnostics; +锘縰sing System.Diagnostics; using System.Net.Sockets; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; @@ -28,7 +29,7 @@ protected override void SetupData() protected override void Act() { - ServerSocket.Send(_packet, 0, _packet.Length, SocketFlags.None); + _ = ServerSocket.Send(_packet, 0, _packet.Length, SocketFlags.None); // give session some time to process packet Thread.Sleep(200); @@ -101,7 +102,7 @@ public void ReceiveOnServerSocketShouldTimeout() ServerSocket.ReceiveTimeout = 500; try { - ServerSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None); + _ = ServerSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None); Assert.Fail(); } catch (SocketException ex) @@ -134,7 +135,7 @@ public void ISession_MessageListenerCompletedShouldBeSignaled() Assert.IsTrue(session.MessageListenerCompleted.WaitOne()); } - [TestMethodAttribute] + [TestMethod] public void ISession_SendMessageShouldSendMessageToServer() { var session = (ISession) Session; @@ -204,9 +205,8 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnFailed { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); - Exception exception; - var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out var exception); Assert.AreEqual(WaitResult.Failed, result); Assert.IsNotNull(exception); @@ -234,4 +234,4 @@ private static byte[] CreatePacketForUnsupportedMessageType() return sshDataStream.ToArray(); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs index 5fbfb8a2a..23db91667 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs @@ -1,8 +1,9 @@ -锘縰sing System; -using System.Diagnostics; +锘縰sing System.Diagnostics; using System.Net.Sockets; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; using Renci.SshNet.Tests.Common; @@ -15,7 +16,8 @@ public class SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePack protected override void Act() { var incompletePacket = new byte[] {0x0a, 0x05, 0x05}; - ServerSocket.Send(incompletePacket, 0, incompletePacket.Length, SocketFlags.None); + + _ = ServerSocket.Send(incompletePacket, 0, incompletePacket.Length, SocketFlags.None); // give session some time to start reading packet Thread.Sleep(100); @@ -199,12 +201,11 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDiscon { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); - Exception exception; - var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out var exception); Assert.AreEqual(WaitResult.Disconnected, result); Assert.IsNull(exception); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs index 02d1f4c7f..00a8cd546 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs @@ -114,7 +114,7 @@ public void ISession_MessageListenerCompletedShouldBeSignaled() Assert.IsTrue(session.MessageListenerCompleted.WaitOne()); } - [TestMethodAttribute] + [TestMethod] public void ISession_SendMessageShouldThrowSshConnectionException() { var session = (ISession) Session; @@ -197,7 +197,7 @@ public void ISession_TryWait_WaitHandleAndTimeout_ShouldThrowArgumentNullExcepti try { - session.TryWait(waitHandle, timeout); + _ = session.TryWait(waitHandle, timeout); Assert.Fail(); } catch (ArgumentNullException ex) @@ -212,9 +212,8 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDiscon { var session = (ISession) Session; var waitHandle = new ManualResetEvent(false); - Exception exception; - var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out var exception); Assert.AreEqual(WaitResult.Disconnected, result); Assert.IsNull(exception); @@ -230,7 +229,7 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldThrowArgumen try { - session.TryWait(waitHandle, timeout, out exception); + _ = session.TryWait(waitHandle, timeout, out exception); Assert.Fail(); } catch (ArgumentNullException ex) @@ -242,4 +241,4 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldThrowArgumen Assert.IsNull(exception); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs index 97a49a0ec..04491fbc7 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs @@ -1,12 +1,11 @@ 锘縰sing System; using System.Net; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; -using Moq; + using Renci.SshNet.Common; -using Renci.SshNet.Connection; using Renci.SshNet.Messages.Transport; -using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes { @@ -24,7 +23,7 @@ protected override void SetupData() protected override void Act() { - _session = new Session(_connectionInfo, _serviceFactoryMock.Object, _socketFactoryMock.Object); + _session = new Session(_connectionInfo, ServiceFactoryMock.Object, SocketFactoryMock.Object); } [TestMethod] @@ -136,9 +135,8 @@ public void ISession_TryWait_WaitHandleAndTimeoutAndException_ShouldReturnDiscon { var session = (ISession) _session; var waitHandle = new ManualResetEvent(false); - Exception exception; - var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out exception); + var result = session.TryWait(waitHandle, Session.InfiniteTimeSpan, out var exception); Assert.AreEqual(WaitResult.Disconnected, result); Assert.IsNull(exception); @@ -226,13 +224,10 @@ public void ISession_WaitOnHandle_WaitHandleAndTimeout_ShouldThrowArgumentNullEx private static ConnectionInfo CreateConnectionInfo(IPEndPoint serverEndPoint, TimeSpan timeout) { - var connectionInfo = new ConnectionInfo( - serverEndPoint.Address.ToString(), - serverEndPoint.Port, - "eric", - new NoneAuthenticationMethod("eric")); - connectionInfo.Timeout = timeout; - return connectionInfo; + return new ConnectionInfo(serverEndPoint.Address.ToString(), serverEndPoint.Port, "eric", new NoneAuthenticationMethod("eric")) + { + Timeout = timeout + }; } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs b/src/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs index f5fb4d79a..a077c774f 100644 --- a/src/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs +++ b/src/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs @@ -1,8 +1,11 @@ 锘縰sing System; using System.Net; using System.Net.Sockets; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Connection; using Renci.SshNet.Messages.Transport; @@ -36,10 +39,7 @@ public void Setup() [TestCleanup] public void TearDown() { - if (_serverListener != null) - { - _serverListener.Dispose(); - } + _serverListener?.Dispose(); } protected void CreateMocks() @@ -53,12 +53,10 @@ protected void CreateMocks() protected void SetupData() { _serverEndPoint = new IPEndPoint(IPAddress.Loopback, 8122); - _connectionInfo = new ConnectionInfo( - _serverEndPoint.Address.ToString(), - _serverEndPoint.Port, - "user", - new PasswordAuthenticationMethod("user", "password")); - _connectionInfo.Timeout = TimeSpan.FromMilliseconds(200); + _connectionInfo = new ConnectionInfo(_serverEndPoint.Address.ToString(), _serverEndPoint.Port, "user", new PasswordAuthenticationMethod("user", "password")) + { + Timeout = TimeSpan.FromMilliseconds(200) + }; _actualException = null; _socketFactory = new SocketFactory(); @@ -71,7 +69,9 @@ protected void SetupData() // packet upon establishing the connection var badPacket = new byte[] { 0x0a, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05 }; - _serverSocket.Send(badPacket, 0, badPacket.Length, SocketFlags.None); + + _ = _serverSocket.Send(badPacket, 0, badPacket.Length, SocketFlags.None); + _serverSocket.Shutdown(SocketShutdown.Send); }; _serverListener.Start(); @@ -83,14 +83,14 @@ protected void SetupData() protected void SetupMocks() { - _serviceFactoryMock.Setup(p => p.CreateConnector(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_connectorMock.Object); - _connectorMock.Setup(p => p.Connect(_connectionInfo)) - .Returns(_clientSocket); - _serviceFactoryMock.Setup(p => p.CreateProtocolVersionExchange()) - .Returns(_protocolVersionExchangeMock.Object); - _protocolVersionExchangeMock.Setup(p => p.Start(_session.ClientVersion, _clientSocket, _connectionInfo.Timeout)) - .Returns(new SshIdentification("2.0", "XXX")); + _ = _serviceFactoryMock.Setup(p => p.CreateConnector(_connectionInfo, _socketFactoryMock.Object)) + .Returns(_connectorMock.Object); + _ = _connectorMock.Setup(p => p.Connect(_connectionInfo)) + .Returns(_clientSocket); + _ = _serviceFactoryMock.Setup(p => p.CreateProtocolVersionExchange()) + .Returns(_protocolVersionExchangeMock.Object); + _ = _protocolVersionExchangeMock.Setup(p => p.Start(_session.ClientVersion, _clientSocket, _connectionInfo.Timeout)) + .Returns(new SshIdentification("2.0", "XXX")); } protected void Arrange() @@ -104,10 +104,8 @@ protected virtual void Act() { try { - - { - _session.Connect(); - } + _session.Connect(); + Assert.Fail(); } catch (SshConnectionException ex) { diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRmDirRequestTest.cs b/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRmDirRequestTest.cs index bd7f12c3c..f171a1278 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRmDirRequestTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRmDirRequestTest.cs @@ -3,12 +3,13 @@ using System.Globalization; using System.Linq; using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Sftp; using Renci.SshNet.Sftp.Requests; using Renci.SshNet.Sftp.Responses; -using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Sftp.Requests { @@ -87,10 +88,10 @@ public void GetBytes() Assert.AreEqual((uint) _pathBytes.Length, sshDataStream.ReadUInt32()); var actualPath = new byte[_pathBytes.Length]; - sshDataStream.Read(actualPath, 0, actualPath.Length); + _ = sshDataStream.Read(actualPath, 0, actualPath.Length); Assert.IsTrue(_pathBytes.SequenceEqual(actualPath)); Assert.IsTrue(sshDataStream.IsEndOfData); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpUnblockRequestTest.cs b/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpUnblockRequestTest.cs index 40ea7c3dc..aabd4d857 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpUnblockRequestTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpUnblockRequestTest.cs @@ -1,12 +1,13 @@ 锘縰sing System; using System.Collections.Generic; using System.Linq; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Sftp; using Renci.SshNet.Sftp.Requests; using Renci.SshNet.Sftp.Responses; -using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Sftp.Requests { @@ -84,7 +85,7 @@ public void GetBytes() Assert.AreEqual((uint) _handle.Length, sshDataStream.ReadUInt32()); var actualHandle = new byte[_handle.Length]; - sshDataStream.Read(actualHandle, 0, actualHandle.Length); + _ = sshDataStream.Read(actualHandle, 0, actualHandle.Length); Assert.IsTrue(_handle.SequenceEqual(actualHandle)); Assert.AreEqual(_offset, sshDataStream.ReadUInt64()); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Responses/ExtendedReplies/StatVfsReplyInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Sftp/Responses/ExtendedReplies/StatVfsReplyInfoTest.cs index d2b4f6c83..4ea375652 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/Responses/ExtendedReplies/StatVfsReplyInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/Responses/ExtendedReplies/StatVfsReplyInfoTest.cs @@ -1,5 +1,7 @@ 锘縰sing System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Sftp; using Renci.SshNet.Sftp.Responses; @@ -88,4 +90,4 @@ public void Load() Assert.AreEqual(_files, information.TotalNodes); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpExtendedReplyResponseTest.cs b/src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpExtendedReplyResponseTest.cs index 6596459be..ff5f9ac39 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpExtendedReplyResponseTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpExtendedReplyResponseTest.cs @@ -1,5 +1,7 @@ 锘縰sing System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; using Renci.SshNet.Sftp; using Renci.SshNet.Sftp.Responses; @@ -60,8 +62,10 @@ public void GetReply_StatVfsReplyInfo() var sid = (ulong) _random.Next(0, int.MaxValue); var namemax = (ulong) _random.Next(0, int.MaxValue); - var sshDataStream = new SshDataStream(4 + 1 + 4 + 88); - sshDataStream.Position = 4; // skip 4 bytes for SSH packet length + var sshDataStream = new SshDataStream(4 + 1 + 4 + 88) + { + Position = 4 // skip 4 bytes for SSH packet length + }; sshDataStream.WriteByte((byte)SftpMessageTypes.Attrs); sshDataStream.Write(_responseId); sshDataStream.Write(bsize); @@ -100,4 +104,4 @@ public void GetReply_StatVfsReplyInfo() Assert.AreEqual(files, information.TotalNodes); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs index 2f2f1bbf0..0e952d337 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs @@ -38,8 +38,8 @@ public void SetUp() protected static SftpFileAttributes CreateSftpFileAttributes(long size) { - var utcDefault = DateTime.SpecifyKind(default(DateTime), DateTimeKind.Utc); - return new SftpFileAttributes(utcDefault, utcDefault, size, default(int), default(int), default(uint), null); + var utcDefault = DateTime.SpecifyKind(default, DateTimeKind.Utc); + return new SftpFileAttributes(utcDefault, utcDefault, size, default, default, default, null); } protected static byte[] CreateByteArray(Random random, int length) @@ -54,7 +54,10 @@ protected static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout) var result = WaitHandle.WaitAny(waitHandles, millisecondsTimeout); if (result == WaitHandle.WaitTimeout) + { throw new SshOperationTimeoutException(); + } + return result; } } diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs index 2e90f9ce3..b49de6e34 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs @@ -1,13 +1,14 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System; +using System.Diagnostics; +using System.Threading; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -#if !FEATURE_EVENTWAITHANDLE_DISPOSE -using Renci.SshNet.Common; -#endif // !FEATURE_EVENTWAITHANDLE_DISPOSE + using Renci.SshNet.Abstractions; using Renci.SshNet.Sftp; -using System; -using System.Diagnostics; -using System.Threading; + using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead; namespace Renci.SshNet.Tests.Classes.Sftp @@ -31,10 +32,7 @@ public class SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead : SftpFileR [TestCleanup] public void TearDown() { - if (_disposeCompleted != null) - { - _disposeCompleted.Dispose(); - } + _disposeCompleted?.Dispose(); } protected override void SetupData() @@ -54,39 +52,41 @@ protected override void SetupMocks() { _seq = new MockSequence(); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) - .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => - { - _waitHandleArray[0] = disposingWaitHandle; - _waitHandleArray[1] = semaphoreAvailableWaitHandle; - return _waitHandleArray; - }); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.OperationTimeout) - .Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) - .Returns((handle, offset, length, callback, state) => - { - _readAsyncCallback = callback; - return null; - }); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginClose(_handle, null, null)) - .Returns(_closeAsyncResult); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.EndClose(_closeAsyncResult)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) + .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => + { + _waitHandleArray[0] = disposingWaitHandle; + _waitHandleArray[1] = semaphoreAvailableWaitHandle; + return _waitHandleArray; + }); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) + .Returns((handle, offset, length, callback, state) => + { + _readAsyncCallback = callback; + return null; + }); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginClose(_handle, null, null)) + .Returns(_closeAsyncResult); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.EndClose(_closeAsyncResult)); } protected override void Arrange() @@ -99,15 +99,15 @@ protected override void Arrange() protected override void Act() { ThreadAbstraction.ExecuteThread(() => - { - Thread.Sleep(500); - _reader.Dispose(); - _disposeCompleted.Set(); - }); + { + Thread.Sleep(500); + _reader.Dispose(); + _ = _disposeCompleted.Set(); + }); try { - _reader.Read(); + _ = _reader.Read(); Assert.Fail(); } catch (ObjectDisposedException ex) @@ -117,7 +117,7 @@ protected override void Act() // Dispose may unblock Read() before the dispose has fully completed, so // let's wait until it has completed - _disposeCompleted.WaitOne(500); + _ = _disposeCompleted.WaitOne(500); } [TestMethod] @@ -132,7 +132,7 @@ public void ReadAfterDisposeShouldThrowObjectDisposedException() { try { - _reader.Read(); + _ = _reader.Read(); Assert.Fail(); } catch (ObjectDisposedException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsNotOpen.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsNotOpen.cs index 7c2d87ce8..6b8612ab7 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsNotOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsNotOpen.cs @@ -1,11 +1,12 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System; +using System.Threading; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -#if !FEATURE_EVENTWAITHANDLE_DISPOSE -using Renci.SshNet.Common; -#endif // !FEATURE_EVENTWAITHANDLE_DISPOSE + using Renci.SshNet.Sftp; -using System; -using System.Threading; + using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead; namespace Renci.SshNet.Tests.Classes.Sftp @@ -28,15 +29,8 @@ public class SftpFileReaderTest_Dispose_SftpSessionIsNotOpen : SftpFileReaderTes [TestCleanup] public void TearDown() { - if (_beginReadInvoked != null) - { - _beginReadInvoked.Dispose(); - } - - if (_disposeCompleted != null) - { - _disposeCompleted.Dispose(); - } + _beginReadInvoked?.Dispose(); + _disposeCompleted?.Dispose(); } protected override void SetupData() @@ -56,41 +50,41 @@ protected override void SetupMocks() { _seq = new MockSequence(); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) - .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => - { - _waitHandleArray[0] = disposingWaitHandle; - _waitHandleArray[1] = semaphoreAvailableWaitHandle; - return _waitHandleArray; - }); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.OperationTimeout) - .Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback(() => - { - // harden test by making sure that we've invoked BeginRead before Dispose is invoked - _beginReadInvoked.Set(); - }) - .Returns((handle, offset, length, callback, state) => - { - _readAsyncCallback = callback; - return null; - }) - .Callback(() => - { - // wait until Dispose has been invoked on reader to allow us to harden test, and - // verify whether Dispose will prevent us from entering the read-ahead loop again - _waitHandleArray[0].WaitOne(); - }); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.IsOpen) - .Returns(false); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) + .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => + { + _waitHandleArray[0] = disposingWaitHandle; + _waitHandleArray[1] = semaphoreAvailableWaitHandle; + return _waitHandleArray; + }); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback(() => + { + // harden test by making sure that we've invoked BeginRead before Dispose is invoked + _ = _beginReadInvoked.Set(); + }) + .Returns((handle, offset, length, callback, state) => + { + _readAsyncCallback = callback; + return null; + }) + .Callback(() => + { + // wait until Dispose has been invoked on reader to allow us to harden test, and + // verify whether Dispose will prevent us from entering the read-ahead loop again + _ = _waitHandleArray[0].WaitOne(); + }); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.IsOpen) + .Returns(false); } protected override void Arrange() @@ -111,7 +105,7 @@ public void ReadAfterDisposeShouldThrowObjectDisposedException() { try { - _reader.Read(); + _ = _reader.Read(); Assert.Fail(); } catch (ObjectDisposedException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs index 015aba53e..a678dfffb 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs @@ -1,11 +1,13 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System; +using System.Threading; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -#if !FEATURE_EVENTWAITHANDLE_DISPOSE + using Renci.SshNet.Common; -#endif // !FEATURE_EVENTWAITHANDLE_DISPOSE using Renci.SshNet.Sftp; -using System; -using System.Threading; + using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead; namespace Renci.SshNet.Tests.Classes.Sftp @@ -28,15 +30,8 @@ public class SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsExcept [TestCleanup] public void TearDown() { - if (_beginReadInvoked != null) - { - _beginReadInvoked.Dispose(); - } - - if (_disposeCompleted != null) - { - _disposeCompleted.Dispose(); - } + _beginReadInvoked?.Dispose(); + _disposeCompleted?.Dispose(); } protected override void SetupData() @@ -56,44 +51,44 @@ protected override void SetupMocks() { _seq = new MockSequence(); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) - .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => - { - _waitHandleArray[0] = disposingWaitHandle; - _waitHandleArray[1] = semaphoreAvailableWaitHandle; - return _waitHandleArray; - }); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.OperationTimeout) - .Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback(() => - { - // harden test by making sure that we've invoked BeginRead before Dispose is invoked - _beginReadInvoked.Set(); - }) - .Returns((handle, offset, length, callback, state) => - { - _readAsyncCallback = callback; - return null; - }) - .Callback(() => - { - // wait until Dispose has been invoked on reader to allow us to harden test, and - // verify whether Dispose will prevent us from entering the read-ahead loop again - _waitHandleArray[0].WaitOne(); - }); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginClose(_handle, null, null)) - .Throws(new SshException()); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) + .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => + { + _waitHandleArray[0] = disposingWaitHandle; + _waitHandleArray[1] = semaphoreAvailableWaitHandle; + return _waitHandleArray; + }); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback(() => + { + // harden test by making sure that we've invoked BeginRead before Dispose is invoked + _ = _beginReadInvoked.Set(); + }) + .Returns((handle, offset, length, callback, state) => + { + _readAsyncCallback = callback; + return null; + }) + .Callback(() => + { + // wait until Dispose has been invoked on reader to allow us to harden test, and + // verify whether Dispose will prevent us from entering the read-ahead loop again + _ = _waitHandleArray[0].WaitOne(); + }); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginClose(_handle, null, null)) + .Throws(new SshException()); } protected override void Arrange() @@ -114,7 +109,7 @@ public void ReadAfterDisposeShouldThrowObjectDisposedException() { try { - _reader.Read(); + _ = _reader.Read(); Assert.Fail(); } catch (ObjectDisposedException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs index 4a175648e..6f6002e3e 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs @@ -1,11 +1,15 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System; +using System.Threading; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + #if !FEATURE_EVENTWAITHANDLE_DISPOSE using Renci.SshNet.Common; #endif // !FEATURE_EVENTWAITHANDLE_DISPOSE using Renci.SshNet.Sftp; -using System; -using System.Threading; + using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead; namespace Renci.SshNet.Tests.Classes.Sftp @@ -29,15 +33,8 @@ public class SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsExceptio [TestCleanup] public void TearDown() { - if (_beginReadInvoked != null) - { - _beginReadInvoked.Dispose(); - } - - if (_disposeCompleted != null) - { - _disposeCompleted.Dispose(); - } + _beginReadInvoked?.Dispose(); + _disposeCompleted?.Dispose(); } protected override void SetupData() @@ -58,47 +55,47 @@ protected override void SetupMocks() { _seq = new MockSequence(); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) - .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => - { - _waitHandleArray[0] = disposingWaitHandle; - _waitHandleArray[1] = semaphoreAvailableWaitHandle; - return _waitHandleArray; - }); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.OperationTimeout) - .Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback(() => - { - // harden test by making sure that we've invoked BeginRead before Dispose is invoked - _beginReadInvoked.Set(); - }) - .Returns((handle, offset, length, callback, state) => - { - _readAsyncCallback = callback; - return null; - }) - .Callback(() => - { - // wait until Dispose has been invoked on reader to allow us to harden test, and - // verify whether Dispose will prevent us from entering the read-ahead loop again - _waitHandleArray[0].WaitOne(); - }); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginClose(_handle, null, null)) - .Returns(_closeAsyncResult); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.EndClose(_closeAsyncResult)) - .Throws(new SshException()); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) + .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => + { + _waitHandleArray[0] = disposingWaitHandle; + _waitHandleArray[1] = semaphoreAvailableWaitHandle; + return _waitHandleArray; + }); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback(() => + { + // harden test by making sure that we've invoked BeginRead before Dispose is invoked + _ = _beginReadInvoked.Set(); + }) + .Returns((handle, offset, length, callback, state) => + { + _readAsyncCallback = callback; + return null; + }) + .Callback(() => + { + // wait until Dispose has been invoked on reader to allow us to harden test, and + // verify whether Dispose will prevent us from entering the read-ahead loop again + _ = _waitHandleArray[0].WaitOne(); + }); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginClose(_handle, null, null)) + .Returns(_closeAsyncResult); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.EndClose(_closeAsyncResult)) + .Throws(new SshException()); } protected override void Arrange() @@ -119,7 +116,7 @@ public void ReadAfterDisposeShouldThrowObjectDisposedException() { try { - _reader.Read(); + _ = _reader.Read(); Assert.Fail(); } catch (ObjectDisposedException ex) diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs index 8c38a000f..cedcff5cb 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs @@ -75,99 +75,111 @@ protected override void SetupMocks() { _seq = new MockSequence(); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) - .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => - { - _waitHandleArray[0] = disposingWaitHandle; - _waitHandleArray[1] = semaphoreAvailableWaitHandle; - return _waitHandleArray; - }); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback((handle, offset, length, callback, state) => - { - _chunk1BeginRead.Set(); - var asyncResult = new SftpReadAsyncResult(callback, state); - asyncResult.SetAsCompleted(_chunk1, false); - }) - .Returns((SftpReadAsyncResult)null); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback((handle, offset, length, callback, state) => - { - _chunk2BeginRead.Set(); - var asyncResult = new SftpReadAsyncResult(callback, state); - asyncResult.SetAsCompleted(_chunk2, false); - }) - .Returns((SftpReadAsyncResult)null); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback((handle, offset, length, callback, state) => - { - _chunk3BeginRead.Set(); - var asyncResult = new SftpReadAsyncResult(callback, state); - asyncResult.SetAsCompleted(_chunk3, false); - }) - .Returns((SftpReadAsyncResult)null); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, 3 * ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback((handle, offset, length, callback, state) => - { - _chunk4BeginRead.Set(); - var asyncResult = new SftpReadAsyncResult(callback, state); - asyncResult.SetAsCompleted(_chunk4, false); - }) - .Returns((SftpReadAsyncResult)null); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, 4 * ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback((handle, offset, length, callback, state) => - { - _chunk5BeginRead.Set(); - var asyncResult = new SftpReadAsyncResult(callback, state); - asyncResult.SetAsCompleted(_chunk5, false); - }) - .Returns((SftpReadAsyncResult)null); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Callback(() => _waitBeforeChunk6.Set()) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.RequestRead(_handle, 2 * ChunkLength - 17, 17)) - .Returns(_chunk2CatchUp1); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.RequestRead(_handle, 2 * ChunkLength - 7, 7)) - .Returns(_chunk2CatchUp2); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, 5 * ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback((handle, offset, length, callback, state) => - { - _chunk6BeginRead.Set(); - var asyncResult = new SftpReadAsyncResult(callback, state); - asyncResult.SetAsCompleted(_chunk6, false); - }) - .Returns((SftpReadAsyncResult)null); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) + .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => + { + _waitHandleArray[0] = disposingWaitHandle; + _waitHandleArray[1] = semaphoreAvailableWaitHandle; + return _waitHandleArray; + }); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback((handle, offset, length, callback, state) => + { + _ = _chunk1BeginRead.Set(); + var asyncResult = new SftpReadAsyncResult(callback, state); + asyncResult.SetAsCompleted(_chunk1, false); + }) + .Returns((SftpReadAsyncResult)null); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback((handle, offset, length, callback, state) => + { + _ = _chunk2BeginRead.Set(); + var asyncResult = new SftpReadAsyncResult(callback, state); + asyncResult.SetAsCompleted(_chunk2, false); + }) + .Returns((SftpReadAsyncResult) null); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback((handle, offset, length, callback, state) => + { + _ = _chunk3BeginRead.Set(); + var asyncResult = new SftpReadAsyncResult(callback, state); + asyncResult.SetAsCompleted(_chunk3, false); + }) + .Returns((SftpReadAsyncResult) null); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, 3 * ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback((handle, offset, length, callback, state) => + { + _ = _chunk4BeginRead.Set(); + var asyncResult = new SftpReadAsyncResult(callback, state); + asyncResult.SetAsCompleted(_chunk4, false); + }) + .Returns((SftpReadAsyncResult) null); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, 4 * ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback((handle, offset, length, callback, state) => + { + _ = _chunk5BeginRead.Set(); + var asyncResult = new SftpReadAsyncResult(callback, state); + asyncResult.SetAsCompleted(_chunk5, false); + }) + .Returns((SftpReadAsyncResult) null); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Callback(() => _waitBeforeChunk6.Set()) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.RequestRead(_handle, (2 * ChunkLength) - 17, 17)) + .Returns(_chunk2CatchUp1); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.RequestRead(_handle, (2 * ChunkLength) - 7, 7)) + .Returns(_chunk2CatchUp2); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, 5 * ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback((handle, offset, length, callback, state) => + { + _ = _chunk6BeginRead.Set(); + var asyncResult = new SftpReadAsyncResult(callback, state); + asyncResult.SetAsCompleted(_chunk6, false); + }) + .Returns((SftpReadAsyncResult) null); } protected override void Arrange() @@ -271,7 +283,7 @@ public void ReadAfterEndOfFileShouldThrowSshException() { try { - _reader.Read(); + _ = _reader.Read(); Assert.Fail(); } catch (SshException ex) @@ -284,9 +296,14 @@ public void ReadAfterEndOfFileShouldThrowSshException() [TestMethod] public void DisposeShouldCloseHandleAndCompleteImmediately() { - SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult); - SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginClose(_handle, null, null)) + .Returns(_closeAsyncResult); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.EndClose(_closeAsyncResult)); var stopwatch = Stopwatch.StartNew(); _reader.Dispose(); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs index 2b5cc0f2e..5d2ed04f3 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs @@ -55,56 +55,62 @@ protected override void SetupMocks() { _seq = new MockSequence(); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) - .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => - { - _waitHandleArray[0] = disposingWaitHandle; - _waitHandleArray[1] = semaphoreAvailableWaitHandle; - return _waitHandleArray; - }); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback((handle, offset, length, callback, state) => - { - _chunk1BeginRead.Set(); - var asyncResult = new SftpReadAsyncResult(callback, state); - asyncResult.SetAsCompleted(_chunk1, false); - }) - .Returns((SftpReadAsyncResult)null); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback((handle, offset, length, callback, state) => - { - _chunk2BeginRead.Set(); - var asyncResult = new SftpReadAsyncResult(callback, state); - asyncResult.SetAsCompleted(_chunk2, false); - }) - .Returns((SftpReadAsyncResult)null); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback((handle, offset, length, callback, state) => - { - _chunk3BeginRead.Set(); - var asyncResult = new SftpReadAsyncResult(callback, state); - asyncResult.SetAsCompleted(_chunk3, false); - }) - .Returns((SftpReadAsyncResult)null); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.RequestRead(_handle, 2 * ChunkLength - 10, 10)) - .Returns(_chunk2CatchUp); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) + .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => + { + _waitHandleArray[0] = disposingWaitHandle; + _waitHandleArray[1] = semaphoreAvailableWaitHandle; + return _waitHandleArray; + }); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback((handle, offset, length, callback, state) => + { + _ = _chunk1BeginRead.Set(); + var asyncResult = new SftpReadAsyncResult(callback, state); + asyncResult.SetAsCompleted(_chunk1, false); + }) + .Returns((SftpReadAsyncResult) null); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback((handle, offset, length, callback, state) => + { + _ = _chunk2BeginRead.Set(); + var asyncResult = new SftpReadAsyncResult(callback, state); + asyncResult.SetAsCompleted(_chunk2, false); + }) + .Returns((SftpReadAsyncResult) null); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, 2 * ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback((handle, offset, length, callback, state) => + { + _ = _chunk3BeginRead.Set(); + var asyncResult = new SftpReadAsyncResult(callback, state); + asyncResult.SetAsCompleted(_chunk3, false); + }) + .Returns((SftpReadAsyncResult) null); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.RequestRead(_handle, (2 * ChunkLength) - 10, 10)) + .Returns(_chunk2CatchUp); } protected override void Arrange() @@ -161,7 +167,7 @@ public void ReadAfterEndOfFileShouldThrowSshException() { try { - _reader.Read(); + _ = _reader.Read(); Assert.Fail(); } catch (SshException ex) @@ -174,9 +180,14 @@ public void ReadAfterEndOfFileShouldThrowSshException() [TestMethod] public void DisposeShouldCloseHandleAndCompleteImmediately() { - SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult); - SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginClose(_handle, null, null)) + .Returns(_closeAsyncResult); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.EndClose(_closeAsyncResult)); var stopwatch = Stopwatch.StartNew(); _reader.Dispose(); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs index 0e4e65eaf..06f2c5433 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs @@ -1,11 +1,15 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System; +using System.Diagnostics; +using System.Threading; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Sftp; -using System; -using System.Diagnostics; -using System.Threading; + using BufferedRead = Renci.SshNet.Sftp.SftpFileReader.BufferedRead; namespace Renci.SshNet.Tests.Classes.Sftp @@ -22,7 +26,6 @@ public class SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadA private int _operationTimeout; private SftpCloseAsyncResult _closeAsyncResult; private byte[] _chunk1; - private byte[] _chunk3; private SftpFileReader _reader; private ManualResetEvent _readAheadChunk2; private ManualResetEvent _readChunk2; @@ -35,7 +38,6 @@ protected override void SetupData() _handle = CreateByteArray(random, 5); _chunk1 = CreateByteArray(random, ChunkLength); - _chunk3 = CreateByteArray(random, ChunkLength); _fileSize = 3 * _chunk1.Length; _waitHandleArray = new WaitHandle[2]; _operationTimeout = random.Next(10000, 20000); @@ -51,52 +53,58 @@ protected override void SetupMocks() { _seq = new MockSequence(); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) - .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => - { - _waitHandleArray[0] = disposingWaitHandle; - _waitHandleArray[1] = semaphoreAvailableWaitHandle; - return _waitHandleArray; - }); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback((handle, offset, length, callback, state) => - { - var asyncResult = new SftpReadAsyncResult(callback, state); - asyncResult.SetAsCompleted(_chunk1, false); - }) - .Returns((SftpReadAsyncResult)null); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) - .Callback((handle, offset, length, callback, state) => - { - ThreadAbstraction.ExecuteThread(() => - { - // signal that we're in the read-ahead for chunk2 - _readAheadChunk2.Set(); - // wait for client to start reading this chunk - _readChunk2.WaitOne(TimeSpan.FromSeconds(5)); - // sleep a short time to make sure the client is in the blocking wait - Thread.Sleep(500); - // complete async read of chunk2 with exception - var asyncResult = new SftpReadAsyncResult(callback, state); - asyncResult.SetAsCompleted(_exception, false); - }); - }) - .Returns((SftpReadAsyncResult)null); - SftpSessionMock.InSequence(_seq).Setup(p => p.OperationTimeout).Returns(_operationTimeout); - SftpSessionMock.InSequence(_seq) - .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) - .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.CreateWaitHandleArray(It.IsNotNull(), It.IsNotNull())) + .Returns((disposingWaitHandle, semaphoreAvailableWaitHandle) => + { + _waitHandleArray[0] = disposingWaitHandle; + _waitHandleArray[1] = semaphoreAvailableWaitHandle; + return _waitHandleArray; + }); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, 0, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback((handle, offset, length, callback, state) => + { + var asyncResult = new SftpReadAsyncResult(callback, state); + asyncResult.SetAsCompleted(_chunk1, false); + }) + .Returns((SftpReadAsyncResult) null); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginRead(_handle, ChunkLength, ChunkLength, It.IsNotNull(), It.IsAny())) + .Callback((handle, offset, length, callback, state) => + { + ThreadAbstraction.ExecuteThread(() => + { + // signal that we're in the read-ahead for chunk2 + _ = _readAheadChunk2.Set(); + // wait for client to start reading this chunk + _ = _readChunk2.WaitOne(TimeSpan.FromSeconds(5)); + // sleep a short time to make sure the client is in the blocking wait + Thread.Sleep(500); + // complete async read of chunk2 with exception + var asyncResult = new SftpReadAsyncResult(callback, state); + asyncResult.SetAsCompleted(_exception, false); + }); + }) + .Returns((SftpReadAsyncResult)null); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.OperationTimeout) + .Returns(_operationTimeout); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.WaitAny(_waitHandleArray, _operationTimeout)) + .Returns(() => WaitAny(_waitHandleArray, _operationTimeout)); } protected override void Arrange() @@ -110,16 +118,16 @@ protected override void Arrange() protected override void Act() { - _reader.Read(); + _ = _reader.Read(); // wait until SftpFileReader has starting reading ahead chunk 2 Assert.IsTrue(_readAheadChunk2.WaitOne(TimeSpan.FromSeconds(5))); // signal that we are about to read chunk 2 - _readChunk2.Set(); + _ = _readChunk2.Set(); try { - _reader.Read(); + _ = _reader.Read(); Assert.Fail(); } catch (SshException ex) @@ -140,7 +148,7 @@ public void ReadAfterReadAheadExceptionShouldRethrowExceptionThatOccurredInReadA { try { - _reader.Read(); + _ = _reader.Read(); Assert.Fail(); } catch (SshException ex) @@ -152,9 +160,14 @@ public void ReadAfterReadAheadExceptionShouldRethrowExceptionThatOccurredInReadA [TestMethod] public void DisposeShouldCloseHandleAndCompleteImmediately() { - SftpSessionMock.InSequence(_seq).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(_seq).Setup(p => p.BeginClose(_handle, null, null)).Returns(_closeAsyncResult); - SftpSessionMock.InSequence(_seq).Setup(p => p.EndClose(_closeAsyncResult)); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.BeginClose(_handle, null, null)) + .Returns(_closeAsyncResult); + _ = SftpSessionMock.InSequence(_seq) + .Setup(p => p.EndClose(_closeAsyncResult)); var stopwatch = Stopwatch.StartNew(); _reader.Dispose(); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackBeginReadException.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackBeginReadException.cs index f00a0273a..a89d4c977 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackBeginReadException.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackBeginReadException.cs @@ -1,9 +1,4 @@ -锘縰sing System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Renci.SshNet.Tests.Classes.Sftp +锘縩amespace Renci.SshNet.Tests.Classes.Sftp { class SftpFileReaderTest_ReadBackBeginReadException { diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackEndInvokeException.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackEndInvokeException.cs index 19c816fc8..324dbd3d4 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackEndInvokeException.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackEndInvokeException.cs @@ -1,9 +1,4 @@ -锘縰sing System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Renci.SshNet.Tests.Classes.Sftp +锘縩amespace Renci.SshNet.Tests.Classes.Sftp { class SftpFileReaderTest_ReadBackEndInvokeException { diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs index 1d8c3393c..4474cafdf 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs @@ -31,17 +31,20 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Write, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) - .Returns(_writeBufferSize); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle)); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Write, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestClose(_handle)); } protected override void Arrange() diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Closed.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Closed.cs index 760b65eae..b52537fb8 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Closed.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Closed.cs @@ -1,8 +1,11 @@ 锘縰sing System; using System.Globalization; using System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes.Sftp @@ -37,20 +40,21 @@ protected void Arrange() _sftpSessionMock = new Mock(MockBehavior.Strict); var sequence = new MockSequence(); - _sftpSessionMock.InSequence(sequence) - .Setup(p => p.RequestOpen(_path, Flags.Read, false)) - .Returns(_handle); - _sftpSessionMock.InSequence(sequence) - .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) - .Returns(_readBufferSize); - _sftpSessionMock.InSequence(sequence) - .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) - .Returns(_writeBufferSize); - _sftpSessionMock.InSequence(sequence) - .Setup(p => p.IsOpen) - .Returns(true); - _sftpSessionMock.InSequence(sequence) - .Setup(p => p.RequestClose(_handle)); + + _ = _sftpSessionMock.InSequence(sequence) + .Setup(p => p.RequestOpen(_path, Flags.Read, false)) + .Returns(_handle); + _ = _sftpSessionMock.InSequence(sequence) + .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) + .Returns(_readBufferSize); + _ = _sftpSessionMock.InSequence(sequence) + .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = _sftpSessionMock.InSequence(sequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = _sftpSessionMock.InSequence(sequence) + .Setup(p => p.RequestClose(_handle)); _sftpFileStream = new SftpFileStream(_sftpSessionMock.Object, _path, FileMode.Open, FileAccess.Read, (int)_bufferSize); _sftpFileStream.Close(); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs index 08a3399ea..59a6357b5 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs @@ -30,17 +30,20 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Read, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) - .Returns(_writeBufferSize); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle)); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Read, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestClose(_handle)); } protected override void Arrange() diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs index c2ec5c4c1..8ad19bce6 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs @@ -1,8 +1,10 @@ 锘縰sing System; -using System.Globalization; using System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes.Sftp @@ -31,20 +33,20 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Read, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) - .Returns(_writeBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestClose(_handle)); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Read, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestClose(_handle)); } protected override void Arrange() diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs index 871830670..25171b9f3 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs @@ -45,18 +45,18 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Append | Flags.CreateNewOrOpen, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) - .Returns(_writeBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestFStat(_handle, false)) - .Returns(_fileAttributes); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Append | Flags.CreateNewOrOpen, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestFStat(_handle, false)) + .Returns(_fileAttributes); } protected override void Act() @@ -95,7 +95,9 @@ public void CanTimeoutShouldReturnTrue() [TestMethod] public void PositionShouldReturnSizeOfFile() { - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); var actual = _target.Position; @@ -109,11 +111,13 @@ public void ReadShouldThrowNotSupportedException() { var buffer = new byte[_readBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); try { - _target.Read(buffer, 0, buffer.Length); + _ = _target.Read(buffer, 0, buffer.Length); Assert.Fail(); } catch (NotSupportedException ex) @@ -128,11 +132,13 @@ public void ReadShouldThrowNotSupportedException() [TestMethod] public void ReadByteShouldThrowNotSupportedException() { - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); try { - _target.ReadByte(); + _ = _target.ReadByte(); Assert.Fail(); } catch (NotSupportedException ex) @@ -149,8 +155,11 @@ public void WriteShouldStartWritingAtEndOfFile() { var buffer = new byte[_writeBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, (ulong) _fileAttributes.Size, buffer, 0, buffer.Length, It.IsNotNull(), null)); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestWrite(_handle, (ulong) _fileAttributes.Size, buffer, 0, buffer.Length, It.IsNotNull(), null)); _target.Write(buffer, 0, buffer.Length); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs index bce4afba1..47cabd2a6 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs @@ -1,6 +1,8 @@ 锘縰sing System; using System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes.Sftp @@ -34,7 +36,7 @@ protected override void Act() { try { - new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize); + _ = new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize); Assert.Fail(); } catch (ArgumentException ex) @@ -48,7 +50,7 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", typeof(FileMode).Name, _fileMode, typeof(FileAccess).Name, _fileAccess), _actualException.Message); + Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException.Message); Assert.IsNull(_actualException.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs index c6a87ce12..c8e46a2b2 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs @@ -37,15 +37,15 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.CreateNew, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) - .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.CreateNew, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) + .Returns(_writeBufferSize); } protected override void Act() @@ -84,7 +84,9 @@ public void CanTimeoutShouldReturnTrue() [TestMethod] public void PositionShouldReturnZero() { - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); var actual = _target.Position; @@ -100,8 +102,12 @@ public void ReadShouldStartReadingAtBeginningOfFile() var data = new byte[] { 5, 4, 3, 2, 1 }; var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 }; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)).Returns(data); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) + .Returns(data); var actual = _target.Read(buffer, 1, data.Length); @@ -117,9 +123,12 @@ public void ReadByteShouldStartReadingAtBeginningOfFile() { var data = GenerateRandom(5, _random); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) - .Returns(data); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) + .Returns(data); var actual = _target.ReadByte(); @@ -134,8 +143,11 @@ public void WriteShouldStartWritingAtBeginningOfFile() { var buffer = new byte[_writeBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull(), null)); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull(), null)); _target.Write(buffer, 0, buffer.Length); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs index 493e48192..29e4956ac 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs @@ -1,6 +1,8 @@ 锘縰sing System; using System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes.Sftp @@ -34,7 +36,7 @@ protected override void Act() { try { - new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize); + _ =new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize); Assert.Fail(); } catch (ArgumentException ex) @@ -48,7 +50,7 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", typeof(FileMode).Name, _fileMode, typeof(FileAccess).Name, _fileAccess), _actualException.Message); + Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException.Message); Assert.IsNull(_actualException.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs index 8b8f50fba..73052060a 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs @@ -37,18 +37,18 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, true)) - .Returns((byte[]) null); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.CreateNew, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) - .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, true)) + .Returns((byte[]) null); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.CreateNew, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) + .Returns(_writeBufferSize); } protected override void Act() @@ -87,7 +87,9 @@ public void CanTimeoutShouldReturnTrue() [TestMethod] public void PositionShouldReturnZero() { - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); var actual = _target.Position; @@ -103,8 +105,12 @@ public void ReadShouldStartReadingAtBeginningOfFile() var data = new byte[] { 5, 4, 3, 2, 1 }; var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 }; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)).Returns(data); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) + .Returns(data); var actual = _target.Read(buffer, 1, data.Length); @@ -120,9 +126,12 @@ public void ReadByteShouldStartReadingAtBeginningOfFile() { var data = GenerateRandom(5, _random); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) - .Returns(data); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) + .Returns(data); var actual = _target.ReadByte(); @@ -137,8 +146,11 @@ public void WriteShouldStartWritingAtBeginningOfFile() { var buffer = new byte[_writeBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull(), null)); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull(), null)); _target.Write(buffer, 0, buffer.Length); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs index c0a216671..2ed977784 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs @@ -34,7 +34,7 @@ protected override void Act() { try { - new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize); + _ = new SftpFileStream(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize); Assert.Fail(); } catch (ArgumentException ex) @@ -48,7 +48,7 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", typeof(FileMode).Name, _fileMode, typeof(FileAccess).Name, _fileAccess), _actualException.Message); + Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException.Message); Assert.IsNull(_actualException.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs index db3d9b997..59e669c55 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs @@ -1,8 +1,11 @@ 锘縰sing System; using System.IO; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Sftp; @@ -37,15 +40,15 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) - .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.Truncate, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) + .Returns(_writeBufferSize); } protected override void Act() @@ -84,7 +87,9 @@ public void CanTimeoutShouldReturnTrue() [TestMethod] public void PositionShouldReturnZero() { - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); var actual = _target.Position; @@ -100,8 +105,12 @@ public void ReadShouldStartReadingAtBeginningOfFile() var data = new byte[] { 5, 4, 3, 2, 1 }; var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 }; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)).Returns(data); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) + .Returns(data); var actual = _target.Read(buffer, 1, data.Length); @@ -117,9 +126,12 @@ public void ReadByteShouldStartReadingAtBeginningOfFile() { var data = GenerateRandom(5, _random); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) - .Returns(data); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) + .Returns(data); var actual = _target.ReadByte(); @@ -134,8 +146,11 @@ public void WriteShouldStartWritingAtBeginningOfFile() { var buffer = new byte[_writeBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull(), null)); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestWrite(_handle, 0UL, buffer, 0, buffer.Length, It.IsNotNull(), null)); _target.Write(buffer, 0, buffer.Length); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs index 2bfe54285..0c6986242 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs @@ -1,7 +1,10 @@ 锘縰sing System; using System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes.Sftp @@ -30,17 +33,20 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Read, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) - .Returns(_writeBufferSize); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle)); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Read, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestClose(_handle)); } protected override void Arrange() diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs index d340b4034..e1aae67bc 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs @@ -1,7 +1,10 @@ 锘縰sing System; using System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes.Sftp @@ -30,17 +33,20 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.CreateNew, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) - .Returns(_writeBufferSize); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(false); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle)); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.CreateNew, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(false); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestClose(_handle)); } protected override void Arrange() diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs index 35563fcc1..9429579f0 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs @@ -1,8 +1,11 @@ 锘縰sing System; using System.Globalization; using System.IO; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes.Sftp @@ -31,17 +34,19 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) - .Returns(_writeBufferSize); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle)); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Write | Flags.Truncate, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestClose(_handle)); } protected override void Arrange() diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs index 41312f668..7ea748873 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs @@ -10,7 +10,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp [TestClass] public class SftpFileStreamTest_Finalize_SessionOpen : SftpFileStreamTestBase { - private SftpFileStream _target; + private WeakReference _target; private string _path; private byte[] _handle; private uint _bufferSize; @@ -31,29 +31,27 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.CreateNewOrOpen, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) - .Returns(_writeBufferSize); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestClose(_handle)); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write | Flags.CreateNewOrOpen, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestClose(_handle)); } protected override void Arrange() { base.Arrange(); - _target = new SftpFileStream(SftpSessionMock.Object, - _path, - FileMode.OpenOrCreate, - FileAccess.ReadWrite, - (int) _bufferSize); - _target = null; + _target = CreateWeakSftpFileStream(); } protected override void Act() @@ -62,6 +60,12 @@ protected override void Act() GC.WaitForPendingFinalizers(); } + [TestMethod] + public void SftpFileStreamShouldHaveBeenFinalized() + { + Assert.IsFalse(_target.TryGetTarget(out _)); + } + [TestMethod] public void IsOpenOnSftpSessionShouldNeverBeInvoked() { @@ -73,5 +77,15 @@ public void RequestCloseOnSftpSessionShouldNeverBeInvoked() { SftpSessionMock.Verify(p => p.RequestClose(_handle), Times.Never); } + + private WeakReference CreateWeakSftpFileStream() + { + var sftpFileStream = new SftpFileStream(SftpSessionMock.Object, + _path, + FileMode.OpenOrCreate, + FileAccess.ReadWrite, + (int) _bufferSize); + return new WeakReference(sftpFileStream); + } } } diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs index ee44c62f7..9795c514a 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs @@ -1,10 +1,13 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System; +using System.IO; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Sftp; using Renci.SshNet.Tests.Common; -using System; -using System.IO; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -36,24 +39,24 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Read, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) - .Returns(_writeBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) - .Returns(_serverBytes); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Read, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) + .Returns(_serverBytes); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); } protected override void Arrange() @@ -65,7 +68,7 @@ protected override void Arrange() FileMode.Open, FileAccess.Read, (int)_bufferSize); - _target.Read(_readBytes, 0, _readBytes.Length); + _ = _target.Read(_readBytes, 0, _readBytes.Length); } protected override void Act() @@ -76,9 +79,9 @@ protected override void Act() [TestMethod] public void PositionShouldReturnSameValueAsBeforeFlush() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); Assert.AreEqual(_readBytes.Length, _target.Position); @@ -94,12 +97,12 @@ public void ReadShouldReadFromServer() .Add(serverBytes2.Take(0, 3)) .Build(); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestRead(_handle, (ulong)_readBytes.Length, _readBufferSize)) - .Returns(serverBytes2); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, (ulong)_readBytes.Length, _readBufferSize)) + .Returns(serverBytes2); var bytesRead = _target.Read(readBytes2, 2, 3); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs index f5b25be48..d873f3209 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs @@ -26,6 +26,7 @@ protected override void SetupData() base.SetupData(); var random = new Random(); + _path = random.Next().ToString(); _handle = GenerateRandom(5, random); _bufferSize = (uint)random.Next(1, 1000); @@ -38,27 +39,27 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Read, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) - .Returns(_writeBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) - .Returns(_serverBytes); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Read, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) + .Returns(_serverBytes); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); } protected override void Arrange() @@ -70,8 +71,8 @@ protected override void Arrange() FileMode.Open, FileAccess.Read, (int)_bufferSize); - _target.Read(_readBytes1, 0, _readBytes1.Length); - _target.Read(_readBytes2, 0, _readBytes2.Length); + _ = _target.Read(_readBytes1, 0, _readBytes1.Length); + _ = _target.Read(_readBytes2, 0, _readBytes2.Length); } protected override void Act() @@ -82,9 +83,9 @@ protected override void Act() [TestMethod] public void PositionShouldReturnSameValueAsBeforeFlush() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); Assert.AreEqual(_readBytes1.Length + _readBytes2.Length, _target.Position); @@ -100,12 +101,12 @@ public void ReadShouldReadFromServer() .Add(serverBytes3.Take(0, 2)) .Build(); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestRead(_handle, (ulong) (_readBytes1.Length + _readBytes2.Length), _readBufferSize)) - .Returns(serverBytes3); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, (ulong) (_readBytes1.Length + _readBytes2.Length), _readBufferSize)) + .Returns(serverBytes3); var bytesRead = _target.Read(readBytes3, 1, 2); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs index 41ba6f439..5388971e6 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs @@ -1,10 +1,13 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System; +using System.IO; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Sftp; using Renci.SshNet.Tests.Common; -using System; -using System.IO; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -36,24 +39,24 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Read, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) - .Returns(_writeBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) - .Returns(_serverBytes); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Read, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, 0UL, _readBufferSize)) + .Returns(_serverBytes); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); } protected override void Arrange() @@ -65,7 +68,7 @@ protected override void Arrange() FileMode.Open, FileAccess.Read, (int) _bufferSize); - _target.Read(_readBytes, 0, _readBytes.Length); + _ = _target.Read(_readBytes, 0, _readBytes.Length); } protected override void Act() @@ -76,9 +79,9 @@ protected override void Act() [TestMethod] public void PositionShouldReturnSameValueAsBeforeFlush() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); Assert.AreEqual(_readBytes.Length, _target.Position); @@ -94,12 +97,12 @@ public void ReadShouldReadFromServer() .Add(serverBytes2.Take(0, 3)) .Build(); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestRead(_handle, (ulong) _readBytes.Length, _readBufferSize)) - .Returns(serverBytes2); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, (ulong) _readBytes.Length, _readBufferSize)) + .Returns(serverBytes2); var bytesRead = _target.Read(readBytes2, 2, 3); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs index 8dbc7066a..2bf5c2c67 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs @@ -1,12 +1,15 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System; +using System.IO; +using System.Threading; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Sftp; using Renci.SshNet.Sftp.Responses; using Renci.SshNet.Tests.Common; -using System; -using System.IO; -using System.Threading; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -29,6 +32,7 @@ protected override void SetupData() base.SetupData(); var random = new Random(); + _path = random.Next().ToString(); _handle = GenerateRandom(5, random); _bufferSize = (uint)random.Next(1, 1000); @@ -42,42 +46,40 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write, false)) - .Returns(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) - .Returns(_writeBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestWrite(_handle, 0UL, It.IsAny(), 0, _writeBytes1.Length, It.IsAny(), null)) - .Callback>((handle, serverOffset, data, offset, length, wait, writeCompleted) - => - { - wait.Set(); - }); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestWrite(_handle, (ulong) _writeBytes1.Length, It.IsAny(), 0, _writeBytes2.Length + _writeBytes3.Length, It.IsAny(), null)) - .Callback>((handle, serverOffset, data, offset, length, wait, writeCompleted) - => - { - _flushedBytes = data.Take(offset, length); - wait.Set(); - }); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpen(_path, Flags.Read | Flags.Write, false)) + .Returns(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength(_bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength(_bufferSize, _handle)) + .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestWrite(_handle, 0UL, It.IsAny(), 0, _writeBytes1.Length, It.IsAny(), null)) + .Callback>((handle, serverOffset, data, offset, length, wait, writeCompleted) => + { + _ = wait.Set(); + }); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestWrite(_handle, (ulong) _writeBytes1.Length, It.IsAny(), 0, _writeBytes2.Length + _writeBytes3.Length, It.IsAny(), null)) + .Callback>((handle, serverOffset, data, offset, length, wait, writeCompleted) => + { + _flushedBytes = data.Take(offset, length); + _ = wait.Set(); + }); } protected override void Arrange() @@ -102,9 +104,9 @@ protected override void Act() [TestMethod] public void PositionShouldReturnSameValueAsBeforeFlush() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); Assert.AreEqual(_writeBytes1.Length + _writeBytes2.Length + _writeBytes3.Length, _target.Position); @@ -131,12 +133,12 @@ public void ReadShouldReadFromServer() .Add(serverBytes.Take(0, 3)) .Build(); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.IsOpen) - .Returns(true); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestRead(_handle, (ulong) (_writeBytes1.Length + _writeBytes2.Length + _writeBytes3.Length), _readBufferSize)) - .Returns(serverBytes); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestRead(_handle, (ulong) (_writeBytes1.Length + _writeBytes2.Length + _writeBytes3.Length), _readBufferSize)) + .Returns(serverBytes); var bytesRead = _target.Read(readBytes, 2, 3); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs index a95be4233..14cce04e4 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs @@ -2,8 +2,11 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Sftp; using Renci.SshNet.Tests.Common; @@ -48,18 +51,18 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpenAsync(_path, Flags.Write | Flags.Append | Flags.CreateNewOrOpen, _cancellationToken)) - .ReturnsAsync(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestFStatAsync(_handle, _cancellationToken)) - .ReturnsAsync(_fileAttributes); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength((uint)_bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength((uint)_bufferSize, _handle)) - .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpenAsync(_path, Flags.Write | Flags.Append | Flags.CreateNewOrOpen, _cancellationToken)) + .ReturnsAsync(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestFStatAsync(_handle, _cancellationToken)) + .ReturnsAsync(_fileAttributes); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength((uint)_bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength((uint)_bufferSize, _handle)) + .Returns(_writeBufferSize); } protected override async Task ActAsync() @@ -95,7 +98,9 @@ public void CanTimeoutShouldReturnTrue() [TestMethod] public void PositionShouldReturnSizeOfFile() { - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); var actual = _target.Position; @@ -109,11 +114,13 @@ public async Task ReadShouldThrowNotSupportedException() { var buffer = new byte[_readBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); try { - await _target.ReadAsync(buffer, 0, buffer.Length, _cancellationToken); + _ = await _target.ReadAsync(buffer, 0, buffer.Length, _cancellationToken); Assert.Fail(); } catch (NotSupportedException ex) @@ -129,8 +136,12 @@ public async Task WriteShouldStartWritingAtEndOfFile() { var buffer = new byte[_writeBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWriteAsync(_handle, (ulong)_fileAttributes.Size, buffer, 0, buffer.Length, _cancellationToken)).Returns(Task.CompletedTask); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestWriteAsync(_handle, (ulong)_fileAttributes.Size, buffer, 0, buffer.Length, _cancellationToken)) + .Returns(Task.CompletedTask); await _target.WriteAsync(buffer, 0, buffer.Length, _cancellationToken); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs index a697a3c53..1d8b792dd 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs @@ -1,7 +1,9 @@ 锘縰sing System; using System.IO; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes.Sftp @@ -35,7 +37,7 @@ protected override async Task ActAsync() { try { - await SftpFileStream.OpenAsync(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize, default); + _ = await SftpFileStream.OpenAsync(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize, default); Assert.Fail(); } catch (ArgumentException ex) @@ -49,7 +51,7 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", typeof(FileMode).Name, _fileMode, typeof(FileAccess).Name, _fileAccess), _actualException.Message); + Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException.Message); Assert.IsNull(_actualException.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs index b6c6487df..98ba5c91f 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs @@ -2,8 +2,11 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes.Sftp @@ -39,15 +42,15 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpenAsync(_path, Flags.Write | Flags.CreateNew, _cancellationToken)) - .ReturnsAsync(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) - .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpenAsync(_path, Flags.Write | Flags.CreateNew, _cancellationToken)) + .ReturnsAsync(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) + .Returns(_writeBufferSize); } protected override async Task ActAsync() @@ -82,7 +85,9 @@ public void CanTimeoutShouldReturnTrue() [TestMethod] public void PositionShouldReturnZero() { - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); var actual = _target.Position; @@ -96,11 +101,13 @@ public async Task ReadShouldThrowNotSupportedException() { var buffer = new byte[_readBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); try { - await _target.ReadAsync(buffer, 0, buffer.Length); + _ = await _target.ReadAsync(buffer, 0, buffer.Length); Assert.Fail(); } catch (NotSupportedException ex) @@ -116,8 +123,12 @@ public async Task WriteShouldStartWritingAtBeginningOfFile() { var buffer = new byte[_writeBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWriteAsync(_handle, 0UL, buffer, 0, buffer.Length, _cancellationToken)).Returns(Task.CompletedTask); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestWriteAsync(_handle, 0UL, buffer, 0, buffer.Length, _cancellationToken)) + .Returns(Task.CompletedTask); await _target.WriteAsync(buffer, 0, buffer.Length); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs index 460081fca..d253c30e4 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs @@ -1,7 +1,9 @@ 锘縰sing System; using System.IO; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes.Sftp @@ -35,7 +37,7 @@ protected override async Task ActAsync() { try { - await SftpFileStream.OpenAsync(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize, default); + _ = await SftpFileStream.OpenAsync(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize, default); Assert.Fail(); } catch (ArgumentException ex) @@ -49,7 +51,7 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", typeof(FileMode).Name, _fileMode, typeof(FileAccess).Name, _fileAccess), _actualException.Message); + Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException.Message); Assert.IsNull(_actualException.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs index 9563b9fcd..100f08ac4 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs @@ -2,8 +2,11 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Sftp; @@ -40,15 +43,15 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpenAsync(_path, Flags.Read | Flags.Write | Flags.CreateNewOrOpen | Flags.Truncate, _cancellationToken)) - .ReturnsAsync(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) - .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpenAsync(_path, Flags.Read | Flags.Write | Flags.CreateNewOrOpen | Flags.Truncate, _cancellationToken)) + .ReturnsAsync(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) + .Returns(_writeBufferSize); } protected override async Task ActAsync() @@ -83,7 +86,9 @@ public void CanTimeoutShouldReturnTrue() [TestMethod] public void PositionShouldReturnZero() { - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); var actual = _target.Position; @@ -99,8 +104,12 @@ public async Task ReadShouldStartReadingAtBeginningOfFile() var data = new byte[] { 5, 4, 3, 2, 1 }; var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 }; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestReadAsync(_handle, 0UL, _readBufferSize, _cancellationToken)).ReturnsAsync(data); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestReadAsync(_handle, 0UL, _readBufferSize, _cancellationToken)) + .ReturnsAsync(data); var actual = await _target.ReadAsync(buffer, 1, data.Length); @@ -116,8 +125,12 @@ public async Task WriteShouldStartWritingAtBeginningOfFile() { var buffer = new byte[_writeBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWriteAsync(_handle, 0UL, buffer, 0, buffer.Length, _cancellationToken)).Returns(Task.CompletedTask); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestWriteAsync(_handle, 0UL, buffer, 0, buffer.Length, _cancellationToken)) + .Returns(Task.CompletedTask); await _target.WriteAsync(buffer, 0, buffer.Length); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs index ed001ab2a..ceb387637 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs @@ -2,8 +2,11 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes.Sftp @@ -39,15 +42,15 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpenAsync(_path, Flags.Write | Flags.CreateNewOrOpen | Flags.Truncate, _cancellationToken)) - .ReturnsAsync(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) - .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpenAsync(_path, Flags.Write | Flags.CreateNewOrOpen | Flags.Truncate, _cancellationToken)) + .ReturnsAsync(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) + .Returns(_writeBufferSize); } protected override async Task ActAsync() @@ -82,7 +85,9 @@ public void CanTimeoutShouldReturnTrue() [TestMethod] public void PositionShouldReturnZero() { - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); var actual = _target.Position; @@ -96,11 +101,13 @@ public async Task ReadShouldThrowNotSupportedException() { var buffer = new byte[_readBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); try { - await _target.ReadAsync(buffer, 0, buffer.Length); + _ = await _target.ReadAsync(buffer, 0, buffer.Length); Assert.Fail(); } catch (NotSupportedException ex) @@ -116,8 +123,12 @@ public async Task WriteShouldStartWritingAtBeginningOfFile() { var buffer = new byte[_writeBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWriteAsync(_handle, 0UL, buffer, 0, buffer.Length, _cancellationToken)).Returns(Task.CompletedTask); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestWriteAsync(_handle, 0UL, buffer, 0, buffer.Length, _cancellationToken)) + .Returns(Task.CompletedTask); await _target.WriteAsync(buffer, 0, buffer.Length); @@ -131,4 +142,4 @@ public void RequestOpenOnSftpSessionShouldBeInvokedOnce() SftpSessionMock.Verify(p => p.RequestOpenAsync(_path, Flags.Write | Flags.CreateNewOrOpen | Flags.Truncate, _cancellationToken), Times.Once); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs index c7cd5d4a4..5803444e4 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs @@ -2,8 +2,11 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Sftp; @@ -40,15 +43,15 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpenAsync(_path, Flags.Read | Flags.Write | Flags.CreateNewOrOpen, _cancellationToken)) - .ReturnsAsync(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) - .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpenAsync(_path, Flags.Read | Flags.Write | Flags.CreateNewOrOpen, _cancellationToken)) + .ReturnsAsync(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) + .Returns(_writeBufferSize); } protected override async Task ActAsync() @@ -83,7 +86,9 @@ public void CanTimeoutShouldReturnTrue() [TestMethod] public void PositionShouldReturnZero() { - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); var actual = _target.Position; @@ -99,8 +104,12 @@ public async Task ReadShouldStartReadingAtBeginningOfFile() var data = new byte[] { 5, 4, 3, 2, 1 }; var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 }; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestReadAsync(_handle, 0UL, _readBufferSize, _cancellationToken)).ReturnsAsync(data); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestReadAsync(_handle, 0UL, _readBufferSize, _cancellationToken)) + .ReturnsAsync(data); var actual = await _target.ReadAsync(buffer, 1, data.Length); @@ -116,8 +125,12 @@ public async Task WriteShouldStartWritingAtBeginningOfFile() { var buffer = new byte[_writeBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWriteAsync(_handle, 0UL, buffer, 0, buffer.Length, _cancellationToken)).Returns(Task.CompletedTask); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestWriteAsync(_handle, 0UL, buffer, 0, buffer.Length, _cancellationToken)) + .Returns(Task.CompletedTask); await _target.WriteAsync(buffer, 0, buffer.Length); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs index 56589f668..7a653cb29 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs @@ -2,8 +2,11 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Sftp; @@ -40,15 +43,15 @@ protected override void SetupData() protected override void SetupMocks() { - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.RequestOpenAsync(_path, Flags.Read | Flags.Write, _cancellationToken)) - .ReturnsAsync(_handle); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) - .Returns(_readBufferSize); - SftpSessionMock.InSequence(MockSequence) - .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) - .Returns(_writeBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestOpenAsync(_path, Flags.Read | Flags.Write, _cancellationToken)) + .ReturnsAsync(_handle); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalReadLength((uint) _bufferSize)) + .Returns(_readBufferSize); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.CalculateOptimalWriteLength((uint) _bufferSize, _handle)) + .Returns(_writeBufferSize); } protected override async Task ActAsync() @@ -83,7 +86,9 @@ public void CanTimeoutShouldReturnTrue() [TestMethod] public void PositionShouldReturnZero() { - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); var actual = _target.Position; @@ -99,8 +104,12 @@ public async Task ReadShouldStartReadingAtBeginningOfFile() var data = new byte[] { 5, 4, 3, 2, 1 }; var expected = new byte[] { 0, 5, 4, 3, 2, 1, 0, 0 }; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestReadAsync(_handle, 0UL, _readBufferSize, _cancellationToken)).ReturnsAsync(data); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestReadAsync(_handle, 0UL, _readBufferSize, _cancellationToken)) + .ReturnsAsync(data); var actual = await _target.ReadAsync(buffer, 1, data.Length); @@ -116,8 +125,12 @@ public async Task WriteShouldStartWritingAtBeginningOfFile() { var buffer = new byte[_writeBufferSize]; - SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestWriteAsync(_handle, 0UL, buffer, 0, buffer.Length, _cancellationToken)).Returns(Task.CompletedTask); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = SftpSessionMock.InSequence(MockSequence) + .Setup(p => p.RequestWriteAsync(_handle, 0UL, buffer, 0, buffer.Length, _cancellationToken)) + .Returns(Task.CompletedTask); await _target.WriteAsync(buffer, 0, buffer.Length); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs index 9247274e8..660bd1a1f 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs @@ -1,8 +1,9 @@ 锘縰sing System; using System.IO; -using System.Threading; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes.Sftp @@ -36,7 +37,7 @@ protected override async Task ActAsync() { try { - await SftpFileStream.OpenAsync(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize, default); + _ = await SftpFileStream.OpenAsync(SftpSessionMock.Object, _path, _fileMode, _fileAccess, _bufferSize, default); Assert.Fail(); } catch (ArgumentException ex) @@ -50,7 +51,7 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", typeof(FileMode).Name, _fileMode, typeof(FileAccess).Name, _fileAccess), _actualException.Message); + Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException.Message); Assert.IsNull(_actualException.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs index a9f4587b0..8fb74b436 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs @@ -3,11 +3,13 @@ using System.IO; using System.Threading; using System.Threading.Tasks; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; using Renci.SshNet.Sftp; -using Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Tests.Classes.Sftp { diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpHandleResponseBuilder.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpHandleResponseBuilder.cs index 4477e2fb0..d9f67f61d 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpHandleResponseBuilder.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpHandleResponseBuilder.cs @@ -1,7 +1,4 @@ -锘縰sing Renci.SshNet.Sftp; -using Renci.SshNet.Sftp.Responses; -using System.Collections.Generic; -using System.Text; +锘縰sing Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -32,10 +29,10 @@ public SftpHandleResponseBuilder WithHandle(byte[] handle) public SftpHandleResponse Build() { var sftpHandleResponse = new SftpHandleResponse(_protocolVersion) - { - ResponseId = _responseId, - Handle = _handle - }; + { + ResponseId = _responseId, + Handle = _handle + }; return sftpHandleResponse; } } diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpNameResponseBuilder.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpNameResponseBuilder.cs index e0dc9ae5d..268f1c5c5 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpNameResponseBuilder.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpNameResponseBuilder.cs @@ -10,7 +10,7 @@ internal class SftpNameResponseBuilder private uint _responseId; private uint _protocolVersion; private Encoding _encoding; - private List> _files; + private readonly List> _files; public SftpNameResponseBuilder() { @@ -32,7 +32,10 @@ public SftpNameResponseBuilder WithResponseId(uint responseId) public SftpNameResponseBuilder WithFiles(params KeyValuePair[] files) { for (var i = 0; i < files.Length; i++) + { _files.Add(files[i]); + } + return this; } diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpOpenRequestBuilder.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpOpenRequestBuilder.cs index 00c0efa36..49f785d0d 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpOpenRequestBuilder.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpOpenRequestBuilder.cs @@ -1,10 +1,9 @@ -锘縰sing Renci.SshNet.Sftp; +锘縰sing System; +using System.Text; + +using Renci.SshNet.Sftp; using Renci.SshNet.Sftp.Requests; using Renci.SshNet.Sftp.Responses; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace Renci.SshNet.Tests.Classes.Sftp { diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsRequestBuilder.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsRequestBuilder.cs index 71e37bd12..d52b208a4 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsRequestBuilder.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsRequestBuilder.cs @@ -1,5 +1,6 @@ 锘縰sing Renci.SshNet.Sftp.Requests; using Renci.SshNet.Sftp.Responses; + using System; using System.Text; diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs index 6dc110f74..b3735b91d 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs @@ -88,9 +88,13 @@ public SftpStatVfsResponseBuilder WithSid(ulong sid) public SftpStatVfsResponseBuilder WithIsReadOnly(bool isReadOnly) { if (isReadOnly) + { _flag &= SftpFileSytemInformation.SSH_FXE_STATVFS_ST_RDONLY; + } else + { _flag |= SftpFileSytemInformation.SSH_FXE_STATVFS_ST_RDONLY; + } return this; } @@ -98,9 +102,13 @@ public SftpStatVfsResponseBuilder WithIsReadOnly(bool isReadOnly) public SftpStatVfsResponseBuilder WithSupportsSetUid(bool supportsSetUid) { if (supportsSetUid) + { _flag |= SftpFileSytemInformation.SSH_FXE_STATVFS_ST_NOSUID; + } else + { _flag &= SftpFileSytemInformation.SSH_FXE_STATVFS_ST_NOSUID; + } return this; } diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpVersionResponseBuilder.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpVersionResponseBuilder.cs index 85f33cc1d..1e4d55efd 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpVersionResponseBuilder.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpVersionResponseBuilder.cs @@ -6,7 +6,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp internal class SftpVersionResponseBuilder { private uint _version; - private IDictionary _extensions; + private readonly IDictionary _extensions; public SftpVersionResponseBuilder() { diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.CreateDirectory.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.CreateDirectory.cs index 2c6284a6a..73e5f3c83 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.CreateDirectory.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.CreateDirectory.cs @@ -43,7 +43,9 @@ public void Test_Sftp_CreateDirectory_In_Current_Location() public void Test_Sftp_CreateDirectory_In_Forbidden_Directory() { if (Resources.USERNAME == "root") + { Assert.Fail("Must not run this test as root!"); + } using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) { @@ -101,4 +103,4 @@ public void Test_Sftp_CreateDirectory_Null() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs index 5e981afc0..0964d4690 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs @@ -44,7 +44,9 @@ public void Test_Sftp_DeleteDirectory_Which_Doesnt_Exists() public void Test_Sftp_DeleteDirectory_Which_No_Permissions() { if (Resources.USERNAME == "root") + { Assert.Fail("Must not run this test as root!"); + } using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) { @@ -89,4 +91,4 @@ public void Test_Sftp_DeleteDirectory_Null() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Download.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.Download.cs index 85a2d7ecd..41dbdf33f 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Download.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.Download.cs @@ -18,7 +18,9 @@ public partial class SftpClientTest public void Test_Sftp_Download_Forbidden() { if (Resources.USERNAME == "root") + { Assert.Fail("Must not run this test as root!"); + } using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) { @@ -118,4 +120,4 @@ public void Test_Sftp_EndDownloadFile_Invalid_Async_Handle() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Upload.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.Upload.cs index aa70e232d..2018c9f0d 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Upload.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.Upload.cs @@ -1,12 +1,14 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Sftp; -using Renci.SshNet.Tests.Properties; -using System; +锘縰sing System; using System.Collections.Generic; using System.IO; using System.Threading; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Common; +using Renci.SshNet.Sftp; +using Renci.SshNet.Tests.Properties; + namespace Renci.SshNet.Tests.Classes { /// @@ -25,10 +27,10 @@ public void Test_Sftp_Upload_And_Download_1MB_File() { sftp.Connect(); - string uploadedFileName = Path.GetTempFileName(); - string remoteFileName = Path.GetRandomFileName(); + var uploadedFileName = Path.GetTempFileName(); + var remoteFileName = Path.GetRandomFileName(); - this.CreateTestFile(uploadedFileName, 1); + CreateTestFile(uploadedFileName, 1); // Calculate has value var uploadedHash = CalculateMD5(uploadedFileName); @@ -38,7 +40,7 @@ public void Test_Sftp_Upload_And_Download_1MB_File() sftp.UploadFile(file, remoteFileName); } - string downloadedFileName = Path.GetTempFileName(); + var downloadedFileName = Path.GetTempFileName(); using (var file = File.OpenWrite(downloadedFileName)) { @@ -68,10 +70,10 @@ public void Test_Sftp_Upload_Forbidden() { sftp.Connect(); - string uploadedFileName = Path.GetTempFileName(); - string remoteFileName = "/root/1"; + var uploadedFileName = Path.GetTempFileName(); + var remoteFileName = "/root/1"; - this.CreateTestFile(uploadedFileName, 1); + CreateTestFile(uploadedFileName, 1); using (var file = File.OpenRead(uploadedFileName)) { @@ -98,14 +100,16 @@ public void Test_Sftp_Multiple_Async_Upload_And_Download_10Files_5MB_Each() var testInfoList = new Dictionary(); - for (int i = 0; i < maxFiles; i++) + for (var i = 0; i < maxFiles; i++) { - var testInfo = new TestInfo(); - testInfo.UploadedFileName = Path.GetTempFileName(); - testInfo.DownloadedFileName = Path.GetTempFileName(); - testInfo.RemoteFileName = Path.GetRandomFileName(); + var testInfo = new TestInfo + { + UploadedFileName = Path.GetTempFileName(), + DownloadedFileName = Path.GetTempFileName(), + RemoteFileName = Path.GetRandomFileName() + }; - this.CreateTestFile(testInfo.UploadedFileName, maxSize); + CreateTestFile(testInfo.UploadedFileName, maxSize); // Calculate hash value testInfo.UploadedHash = CalculateMD5(testInfo.UploadedFileName); @@ -130,7 +134,7 @@ public void Test_Sftp_Multiple_Async_Upload_And_Download_10Files_5MB_Each() } // Wait for upload to finish - bool uploadCompleted = false; + var uploadCompleted = false; while (!uploadCompleted) { // Assume upload completed @@ -174,7 +178,7 @@ public void Test_Sftp_Multiple_Async_Upload_And_Download_10Files_5MB_Each() } // Wait for download to finish - bool downloadCompleted = false; + var downloadCompleted = false; while (!downloadCompleted) { // Assume download completed @@ -248,11 +252,11 @@ public void Test_Sftp_Ensure_Async_Delegates_Called_For_BeginFileUpload_BeginFil { sftp.Connect(); - string remoteFileName = Path.GetRandomFileName(); - string localFileName = Path.GetRandomFileName(); - bool uploadDelegateCalled = false; - bool downloadDelegateCalled = false; - bool listDirectoryDelegateCalled = false; + var remoteFileName = Path.GetRandomFileName(); + var localFileName = Path.GetRandomFileName(); + var uploadDelegateCalled = false; + var downloadDelegateCalled = false; + var listDirectoryDelegateCalled = false; IAsyncResult asyncResult; // Test for BeginUploadFile. @@ -261,11 +265,14 @@ public void Test_Sftp_Ensure_Async_Delegates_Called_For_BeginFileUpload_BeginFil using (var fileStream = File.OpenRead(localFileName)) { - asyncResult = sftp.BeginUploadFile(fileStream, remoteFileName, delegate(IAsyncResult ar) - { - sftp.EndUploadFile(ar); - uploadDelegateCalled = true; - }, null); + asyncResult = sftp.BeginUploadFile(fileStream, + remoteFileName, + delegate(IAsyncResult ar) + { + sftp.EndUploadFile(ar); + uploadDelegateCalled = true; + }, + null); while (!asyncResult.IsCompleted) { @@ -282,11 +289,14 @@ public void Test_Sftp_Ensure_Async_Delegates_Called_For_BeginFileUpload_BeginFil asyncResult = null; using (var fileStream = File.OpenWrite(localFileName)) { - asyncResult = sftp.BeginDownloadFile(remoteFileName, fileStream, delegate(IAsyncResult ar) - { - sftp.EndDownloadFile(ar); - downloadDelegateCalled = true; - }, null); + asyncResult = sftp.BeginDownloadFile(remoteFileName, + fileStream, + delegate(IAsyncResult ar) + { + sftp.EndDownloadFile(ar); + downloadDelegateCalled = true; + }, + null); while (!asyncResult.IsCompleted) { @@ -301,11 +311,13 @@ public void Test_Sftp_Ensure_Async_Delegates_Called_For_BeginFileUpload_BeginFil // Test for BeginListDirectory. asyncResult = null; - asyncResult = sftp.BeginListDirectory(sftp.WorkingDirectory, delegate(IAsyncResult ar) - { - sftp.EndListDirectory(ar); - listDirectoryDelegateCalled = true; - }, null); + asyncResult = sftp.BeginListDirectory(sftp.WorkingDirectory, + delegate(IAsyncResult ar) + { + _ = sftp.EndListDirectory(ar); + listDirectoryDelegateCalled = true; + }, + null); while (!asyncResult.IsCompleted) { @@ -326,7 +338,7 @@ public void Test_Sftp_BeginUploadFile_StreamIsNull() using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) { sftp.Connect(); - sftp.BeginUploadFile(null, "aaaaa", null, null); + _ = sftp.BeginUploadFile(null, "aaaaa", null, null); sftp.Disconnect(); } } @@ -341,7 +353,7 @@ public void Test_Sftp_BeginUploadFile_FileNameIsWhiteSpace() using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) { sftp.Connect(); - sftp.BeginUploadFile(new MemoryStream(), " ", null, null); + _ = sftp.BeginUploadFile(new MemoryStream(), " ", null, null); sftp.Disconnect(); } } @@ -356,7 +368,7 @@ public void Test_Sftp_BeginUploadFile_FileNameIsNull() using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) { sftp.Connect(); - sftp.BeginUploadFile(new MemoryStream(), null, null, null); + _ = sftp.BeginUploadFile(new MemoryStream(), null, null, null); sftp.Disconnect(); } } @@ -372,10 +384,10 @@ public void Test_Sftp_EndUploadFile_Invalid_Async_Handle() sftp.Connect(); var async1 = sftp.BeginListDirectory("/", null, null); var filename = Path.GetTempFileName(); - this.CreateTestFile(filename, 100); + CreateTestFile(filename, 100); var async2 = sftp.BeginUploadFile(File.OpenRead(filename), "test", null, null); sftp.EndUploadFile(async1); } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs index a66e49312..200abae89 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs @@ -1360,14 +1360,23 @@ protected static string CalculateMD5(string fileName) { using (FileStream file = new FileStream(fileName, FileMode.Open)) { +#if NET7_0_OR_GREATER + var hash = MD5.HashData(file); +#else +#if NET6_0 + var md5 = MD5.Create(); +#else MD5 md5 = new MD5CryptoServiceProvider(); - byte[] retVal = md5.ComputeHash(file); +#endif // NET6_0 + var hash = md5.ComputeHash(file); +#endif // NET7_0_OR_GREATER + file.Close(); StringBuilder sb = new StringBuilder(); - for (int i = 0; i < retVal.Length; i++) + for (var i = 0; i < hash.Length; i++) { - sb.Append(retVal[i].ToString("x2")); + sb.Append(hash[i].ToString("x2")); } return sb.ToString(); } diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTestBase.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTestBase.cs index 11657962c..e0ca2c91c 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTestBase.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTestBase.cs @@ -5,15 +5,15 @@ namespace Renci.SshNet.Tests.Classes { public abstract class SftpClientTestBase : BaseClientTestBase { - internal Mock _sftpResponseFactoryMock { get; private set; } - internal Mock _sftpSessionMock { get; private set; } + internal Mock SftpResponseFactoryMock { get; private set; } + internal Mock SftpSessionMock { get; private set; } protected override void CreateMocks() { base.CreateMocks(); - _sftpResponseFactoryMock = new Mock(MockBehavior.Strict); - _sftpSessionMock = new Mock(MockBehavior.Strict); + SftpResponseFactoryMock = new Mock(MockBehavior.Strict); + SftpSessionMock = new Mock(MockBehavior.Strict); } } } diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs index b3bcb8e81..6f9650487 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs @@ -1,12 +1,13 @@ 锘縰sing System; using System.Reflection; using System.Threading; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; -using Renci.SshNet.Connection; using Renci.SshNet.Security; -using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes { @@ -28,34 +29,34 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence) - .Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSftpResponseFactory()) - .Returns(_sftpResponseFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSftpSession(_sessionMock.Object, -1, _connectionInfo.Encoding, _sftpResponseFactoryMock.Object)) - .Returns(_sftpSessionMock.Object); - _sftpSessionMock.InSequence(sequence) - .Setup(p => p.Connect()) - .Throws(_sftpSessionConnectionException); - _sftpSessionMock.InSequence(sequence) + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSftpResponseFactory()) + .Returns(SftpResponseFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSftpSession(SessionMock.Object, -1, _connectionInfo.Encoding, SftpResponseFactoryMock.Object)) + .Returns(SftpSessionMock.Object); + _ = SftpSessionMock.InSequence(sequence) + .Setup(p => p.Connect()) + .Throws(_sftpSessionConnectionException); + _ = SftpSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _ = SessionMock.InSequence(sequence) .Setup(p => p.Dispose()); - _sessionMock.InSequence(sequence) - .Setup(p => p.Dispose()); } protected override void Arrange() { base.Arrange(); - _sftpClient = new SftpClient(_connectionInfo, false, _serviceFactoryMock.Object); + _sftpClient = new SftpClient(_connectionInfo, false, ServiceFactoryMock.Object); } protected override void Act() @@ -97,7 +98,7 @@ public void ErrorOccuredOnSessionShouldNoLongerBeSignaledViaErrorOccurredOnSftpC _sftpClient.ErrorOccurred += (sender, args) => Interlocked.Increment(ref errorOccurredSignalCount); - _sessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception())); + SessionMock.Raise(p => p.ErrorOccured += null, new ExceptionEventArgs(new Exception())); Assert.AreEqual(0, errorOccurredSignalCount); } @@ -109,7 +110,7 @@ public void HostKeyReceivedOnSessionShouldNoLongerBeSignaledViaHostKeyReceivedOn _sftpClient.HostKeyReceived += (sender, args) => Interlocked.Increment(ref hostKeyReceivedSignalCount); - _sessionMock.Raise(p => p.HostKeyReceived += null, new HostKeyEventArgs(GetKeyHostAlgorithm())); + SessionMock.Raise(p => p.HostKeyReceived += null, new HostKeyEventArgs(GetKeyHostAlgorithm())); Assert.AreEqual(0, hostKeyReceivedSignalCount); } diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs index 239c84931..fe8ef9f63 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs @@ -1,7 +1,8 @@ 锘縰sing System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes { @@ -16,31 +17,38 @@ protected override void SetupData() { _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth")); _operationTimeout = new Random().Next(1000, 10000); - _sftpClient = new SftpClient(_connectionInfo, false, _serviceFactoryMock.Object); - _sftpClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout); + _sftpClient = new SftpClient(_connectionInfo, false, ServiceFactoryMock.Object) + { + OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout) + }; } protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSftpResponseFactory()) - .Returns(_sftpResponseFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSftpSession(_sessionMock.Object, _operationTimeout, _connectionInfo.Encoding, _sftpResponseFactoryMock.Object)) - .Returns(_sftpSessionMock.Object); - _sftpSessionMock.InSequence(sequence).Setup(p => p.Connect()); - _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); - _sftpSessionMock.InSequence(sequence).Setup(p => p.Dispose()); - _sessionMock.InSequence(sequence).Setup(p => p.Dispose()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSftpResponseFactory()) + .Returns(SftpResponseFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSftpSession(SessionMock.Object, _operationTimeout, _connectionInfo.Encoding, SftpResponseFactoryMock.Object)) + .Returns(SftpSessionMock.Object); + _ = SftpSessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.OnDisconnecting()); + _ = SftpSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); } protected override void Arrange() @@ -58,58 +66,58 @@ protected override void Act() [TestMethod] public void CreateSftpMessageFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSftpResponseFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSftpResponseFactory(), Times.Once); } [TestMethod] public void CreateSftpSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify( - p => p.CreateSftpSession(_sessionMock.Object, _operationTimeout, _connectionInfo.Encoding, _sftpResponseFactoryMock.Object), + ServiceFactoryMock.Verify( + p => p.CreateSftpSession(SessionMock.Object, _operationTimeout, _connectionInfo.Encoding, SftpResponseFactoryMock.Object), Times.Once); } [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void DisconnectOnNetConfSessionShouldNeverBeInvoked() { - _sftpSessionMock.Verify(p => p.Disconnect(), Times.Never); + SftpSessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisconnectOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.Disconnect(), Times.Never); + SessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisposeOnNetConfSessionShouldBeInvokedOnce() { - _sftpSessionMock.Verify(p => p.Dispose(), Times.Once); + SftpSessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void DisposeOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Dispose(), Times.Once); + SessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void OnDisconnectingOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.OnDisconnecting(), Times.Once); + SessionMock.Verify(p => p.OnDisconnecting(), Times.Once); } } } diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs index 192c5e957..0f8d0a469 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs @@ -1,7 +1,8 @@ 锘縰sing System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes { @@ -17,31 +18,38 @@ protected override void SetupData() { _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth")); _operationTimeout = new Random().Next(1000, 10000); - _sftpClient = new SftpClient(_connectionInfo, false, _serviceFactoryMock.Object); - _sftpClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout); + _sftpClient = new SftpClient(_connectionInfo, false, ServiceFactoryMock.Object) + { + OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout) + }; } protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSftpResponseFactory()) - .Returns(_sftpResponseFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSftpSession(_sessionMock.Object, _operationTimeout, _connectionInfo.Encoding, _sftpResponseFactoryMock.Object)) - .Returns(_sftpSessionMock.Object); - _sftpSessionMock.InSequence(sequence).Setup(p => p.Connect()); - _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); - _sftpSessionMock.InSequence(sequence).Setup(p => p.Dispose()); - _sessionMock.InSequence(sequence).Setup(p => p.Dispose()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSftpResponseFactory()) + .Returns(SftpResponseFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSftpSession(SessionMock.Object, _operationTimeout, _connectionInfo.Encoding, SftpResponseFactoryMock.Object)) + .Returns(SftpSessionMock.Object); + _ = SftpSessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.OnDisconnecting()); + _ = SftpSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); } protected override void Arrange() @@ -60,58 +68,58 @@ protected override void Act() [TestMethod] public void CreateSftpMessageFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSftpResponseFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSftpResponseFactory(), Times.Once); } [TestMethod] public void CreateSftpSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify( - p => p.CreateSftpSession(_sessionMock.Object, _operationTimeout, _connectionInfo.Encoding, _sftpResponseFactoryMock.Object), + ServiceFactoryMock.Verify( + p => p.CreateSftpSession(SessionMock.Object, _operationTimeout, _connectionInfo.Encoding, SftpResponseFactoryMock.Object), Times.Once); } [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void DisconnectOnNetConfSessionShouldNeverBeInvoked() { - _sftpSessionMock.Verify(p => p.Disconnect(), Times.Never); + SftpSessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisconnectOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.Disconnect(), Times.Never); + SessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisposeOnNetConfSessionShouldBeInvokedOnce() { - _sftpSessionMock.Verify(p => p.Dispose(), Times.Once); + SftpSessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void DisposeOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Dispose(), Times.Once); + SessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void OnDisconnectingOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.OnDisconnecting(), Times.Once); + SessionMock.Verify(p => p.OnDisconnecting(), Times.Once); } } } diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs index 11e00ad03..09208b8bc 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs @@ -1,7 +1,8 @@ 锘縰sing System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes { @@ -16,31 +17,38 @@ protected override void SetupData() { _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth")); _operationTimeout = new Random().Next(1000, 10000); - _sftpClient = new SftpClient(_connectionInfo, false, _serviceFactoryMock.Object); - _sftpClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout); + _sftpClient = new SftpClient(_connectionInfo, false, ServiceFactoryMock.Object) + { + OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout) + }; } protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSftpResponseFactory()) - .Returns(_sftpResponseFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSftpSession(_sessionMock.Object, _operationTimeout, _connectionInfo.Encoding, _sftpResponseFactoryMock.Object)) - .Returns(_sftpSessionMock.Object); - _sftpSessionMock.InSequence(sequence).Setup(p => p.Connect()); - _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); - _sftpSessionMock.InSequence(sequence).Setup(p => p.Dispose()); - _sessionMock.InSequence(sequence).Setup(p => p.Dispose()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSftpResponseFactory()) + .Returns(SftpResponseFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSftpSession(SessionMock.Object, _operationTimeout, _connectionInfo.Encoding, SftpResponseFactoryMock.Object)) + .Returns(SftpSessionMock.Object); + _ = SftpSessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.OnDisconnecting()); + _ = SftpSessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Dispose()); } protected override void Arrange() @@ -59,58 +67,58 @@ protected override void Act() [TestMethod] public void CreateSftpMessageFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSftpResponseFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSftpResponseFactory(), Times.Once); } [TestMethod] public void CreateSftpSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify( - p => p.CreateSftpSession(_sessionMock.Object, _operationTimeout, _connectionInfo.Encoding, _sftpResponseFactoryMock.Object), + ServiceFactoryMock.Verify( + p => p.CreateSftpSession(SessionMock.Object, _operationTimeout, _connectionInfo.Encoding, SftpResponseFactoryMock.Object), Times.Once); } [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void DisconnectOnNetConfSessionShouldNeverBeInvoked() { - _sftpSessionMock.Verify(p => p.Disconnect(), Times.Never); + SftpSessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisconnectOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.Disconnect(), Times.Never); + SessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisposeOnNetConfSessionShouldBeInvokedOnce() { - _sftpSessionMock.Verify(p => p.Dispose(), Times.Once); + SftpSessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void DisposeOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Dispose(), Times.Once); + SessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void OnDisconnectingOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.OnDisconnecting(), Times.Once); + SessionMock.Verify(p => p.OnDisconnecting(), Times.Once); } } } diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Finalize_Connected.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Finalize_Connected.cs index 033f0ea07..f98f6dad2 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Finalize_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Finalize_Connected.cs @@ -1,7 +1,8 @@ 锘縰sing System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.Sftp; namespace Renci.SshNet.Tests.Classes { @@ -17,23 +18,25 @@ protected override void SetupData() { _connectionInfo = new ConnectionInfo("host", "user", new NoneAuthenticationMethod("userauth")); _operationTimeout = new Random().Next(1000, 10000); - _sftpClient = new SftpClient(_connectionInfo, false, _serviceFactoryMock.Object); - _sftpClient.OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout); + _sftpClient = new SftpClient(_connectionInfo, false, ServiceFactoryMock.Object) + { + OperationTimeout = TimeSpan.FromMilliseconds(_operationTimeout) + }; _sftpClientWeakRefence = new WeakReference(_sftpClient); } protected override void SetupMocks() { - _serviceFactoryMock.Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.Setup(p => p.Connect()); - _serviceFactoryMock.Setup(p => p.CreateSftpResponseFactory()) - .Returns(_sftpResponseFactoryMock.Object); - _serviceFactoryMock.Setup(p => p.CreateSftpSession(_sessionMock.Object, _operationTimeout, _connectionInfo.Encoding, _sftpResponseFactoryMock.Object)) - .Returns(_sftpSessionMock.Object); - _sftpSessionMock.Setup(p => p.Connect()); + _ = ServiceFactoryMock.Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.Setup(p => p.Connect()); + _ = ServiceFactoryMock.Setup(p => p.CreateSftpResponseFactory()) + .Returns(SftpResponseFactoryMock.Object); + _ = ServiceFactoryMock.Setup(p => p.CreateSftpSession(SessionMock.Object, _operationTimeout, _connectionInfo.Encoding, SftpResponseFactoryMock.Object)) + .Returns(SftpSessionMock.Object); + _ = SftpSessionMock.Setup(p => p.Connect()); } protected override void Arrange() @@ -60,7 +63,7 @@ public void DisconnectOnSftpSessionShouldNeverBeInvoked() // Since we recreated the mocks, this test has no value // We'll leaving ths test just in case we have a solution that does not require us // to recreate the mocks - _sftpSessionMock.Verify(p => p.Disconnect(), Times.Never); + SftpSessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] @@ -69,7 +72,7 @@ public void DisposeOnSftpSessionShouldNeverBeInvoked() // Since we recreated the mocks, this test has no value // We'll leaving ths test just in case we have a solution that does not require us // to recreate the mocks - _sftpSessionMock.Verify(p => p.Dispose(), Times.Never); + SftpSessionMock.Verify(p => p.Dispose(), Times.Never); } [TestMethod] diff --git a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs b/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs index 4f1fa8692..941c3f7bb 100644 --- a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs +++ b/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs @@ -51,7 +51,7 @@ private void SetupData() _terminalModes = new Dictionary(); _bufferSize = random.Next(100, 1000); - _data = CryptoAbstraction.GenerateRandom(_bufferSize * 2 + 10); + _data = CryptoAbstraction.GenerateRandom((_bufferSize * 2) + 10); _offset = 0; _count = _data.Length; @@ -70,32 +70,32 @@ private void SetupMocks() { _mockSequence = new MockSequence(); - _sessionMock.InSequence(_mockSequence) - .Setup(p => p.ConnectionInfo) - .Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_mockSequence) - .Setup(p => p.Encoding) - .Returns(new UTF8Encoding()); - _sessionMock.InSequence(_mockSequence) - .Setup(p => p.CreateChannelSession()) - .Returns(_channelSessionMock.Object); - _channelSessionMock.InSequence(_mockSequence) - .Setup(p => p.Open()); - _channelSessionMock.InSequence(_mockSequence) - .Setup(p => p.SendPseudoTerminalRequest(_terminalName, - _widthColumns, - _heightRows, - _widthPixels, - _heightPixels, - _terminalModes)) - .Returns(true); - _channelSessionMock.InSequence(_mockSequence) - .Setup(p => p.SendShellRequest()) - .Returns(true); - _channelSessionMock.InSequence(_mockSequence) - .Setup(p => p.SendData(_expectedBytesSent1)); - _channelSessionMock.InSequence(_mockSequence) - .Setup(p => p.SendData(_expectedBytesSent2)); + _ = _sessionMock.InSequence(_mockSequence) + .Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _ = _connectionInfoMock.InSequence(_mockSequence) + .Setup(p => p.Encoding) + .Returns(new UTF8Encoding()); + _ = _sessionMock.InSequence(_mockSequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionMock.Object); + _ = _channelSessionMock.InSequence(_mockSequence) + .Setup(p => p.Open()); + _ = _channelSessionMock.InSequence(_mockSequence) + .Setup(p => p.SendPseudoTerminalRequest(_terminalName, + _widthColumns, + _heightRows, + _widthPixels, + _heightPixels, + _terminalModes)) + .Returns(true); + _ = _channelSessionMock.InSequence(_mockSequence) + .Setup(p => p.SendShellRequest()) + .Returns(true); + _ = _channelSessionMock.InSequence(_mockSequence) + .Setup(p => p.SendData(_expectedBytesSent1)); + _ = _channelSessionMock.InSequence(_mockSequence) + .Setup(p => p.SendData(_expectedBytesSent2)); } private void Arrange() @@ -129,14 +129,14 @@ public void BufferShouldHaveBeenFlushedTwice() [TestMethod] public void FlushShouldSendRemaningBytesToServer() { - var expectedBytesSent = _data.Take(_bufferSize * 2, _data.Length - _bufferSize * 2); + var expectedBytesSent = _data.Take(_bufferSize * 2, _data.Length - (_bufferSize * 2)); - _channelSessionMock.InSequence(_mockSequence) - .Setup(p => p.SendData(expectedBytesSent)); + _ = _channelSessionMock.InSequence(_mockSequence) + .Setup(p => p.SendData(expectedBytesSent)); _shellStream.Flush(); _channelSessionMock.Verify(p => p.SendData(expectedBytesSent), Times.Once); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs b/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs index 05e63a19f..94d55ca87 100644 --- a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs +++ b/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs @@ -1,9 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.Abstractions; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -64,28 +66,28 @@ private void SetupMocks() { _mockSequence = new MockSequence(); - _sessionMock.InSequence(_mockSequence) - .Setup(p => p.ConnectionInfo) - .Returns(_connectionInfoMock.Object); - _connectionInfoMock.InSequence(_mockSequence) - .Setup(p => p.Encoding) - .Returns(new UTF8Encoding()); - _sessionMock.InSequence(_mockSequence) - .Setup(p => p.CreateChannelSession()) - .Returns(_channelSessionMock.Object); - _channelSessionMock.InSequence(_mockSequence) - .Setup(p => p.Open()); - _channelSessionMock.InSequence(_mockSequence) - .Setup(p => p.SendPseudoTerminalRequest(_terminalName, - _widthColumns, - _heightRows, - _widthPixels, - _heightPixels, - _terminalModes)) - .Returns(true); - _channelSessionMock.InSequence(_mockSequence) - .Setup(p => p.SendShellRequest()) - .Returns(true); + _ = _sessionMock.InSequence(_mockSequence) + .Setup(p => p.ConnectionInfo) + .Returns(_connectionInfoMock.Object); + _ = _connectionInfoMock.InSequence(_mockSequence) + .Setup(p => p.Encoding) + .Returns(new UTF8Encoding()); + _ = _sessionMock.InSequence(_mockSequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionMock.Object); + _ = _channelSessionMock.InSequence(_mockSequence) + .Setup(p => p.Open()); + _ = _channelSessionMock.InSequence(_mockSequence) + .Setup(p => p.SendPseudoTerminalRequest(_terminalName, + _widthColumns, + _heightRows, + _widthPixels, + _heightPixels, + _terminalModes)) + .Returns(true); + _ = _channelSessionMock.InSequence(_mockSequence) + .Setup(p => p.SendShellRequest()) + .Returns(true); } private void Arrange() @@ -123,4 +125,4 @@ public void FlushShouldSendNoBytesToServer() _channelSessionMock.Verify(p => p.SendData(It.IsAny()), Times.Never); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest.cs b/src/Renci.SshNet.Tests/Classes/SshClientTest.cs index 78f1db6c4..1eabcae20 100644 --- a/src/Renci.SshNet.Tests/Classes/SshClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SshClientTest.cs @@ -80,9 +80,11 @@ public void Test_Connect_Timeout() var password = Resources.PASSWORD; #region Example SshClient Connect Timeout - var connectionInfo = new PasswordConnectionInfo(host, username, password); - connectionInfo.Timeout = TimeSpan.FromSeconds(30); + var connectionInfo = new PasswordConnectionInfo(host, username, password) + { + Timeout = TimeSpan.FromSeconds(30) + }; using (var client = new SshClient(connectionInfo)) { @@ -942,4 +944,4 @@ public void ForwardedPortsTest() } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs b/src/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs index df1ea835f..4dc5a2063 100644 --- a/src/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs @@ -43,16 +43,16 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence) + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.InSequence(sequence) .Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateShellStream(_sessionMock.Object, + ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateShellStream(SessionMock.Object, _terminalName, _widthColumns, _heightRows, @@ -67,7 +67,7 @@ protected override void Arrange() { base.Arrange(); - _sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object); + _sshClient = new SshClient(_connectionInfo, false, ServiceFactoryMock.Object); _sshClient.Connect(); } @@ -85,7 +85,7 @@ protected override void Act() [TestMethod] public void CreateShellStreamOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateShellStream(_sessionMock.Object, + ServiceFactoryMock.Verify(p => p.CreateShellStream(SessionMock.Object, _terminalName, _widthColumns, _heightRows, diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs b/src/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs index 337f9bce3..861c8c725 100644 --- a/src/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs @@ -1,9 +1,10 @@ 锘縰sing System; -using System.Collections.Generic; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; -using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes { @@ -41,31 +42,31 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence) - .Setup(p => p.Connect()); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateShellStream(_sessionMock.Object, - _terminalName, - _widthColumns, - _heightRows, - _widthPixels, - _heightPixels, - null, - _bufferSize)) - .Returns(_expected); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSocketFactory()) + .Returns(SocketFactoryMock.Object); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + _ = SessionMock.InSequence(sequence) + .Setup(p => p.Connect()); + _ = ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateShellStream(SessionMock.Object, + _terminalName, + _widthColumns, + _heightRows, + _widthPixels, + _heightPixels, + null, + _bufferSize)) + .Returns(_expected); } protected override void Arrange() { base.Arrange(); - _sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object); + _sshClient = new SshClient(_connectionInfo, false, ServiceFactoryMock.Object); _sshClient.Connect(); } @@ -82,7 +83,7 @@ protected override void Act() [TestMethod] public void CreateShellStreamOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateShellStream(_sessionMock.Object, + ServiceFactoryMock.Verify(p => p.CreateShellStream(SessionMock.Object, _terminalName, _widthColumns, _heightRows, @@ -105,20 +106,20 @@ private ShellStream CreateShellStream() var sessionMock = new Mock(MockBehavior.Loose); var channelSessionMock = new Mock(MockBehavior.Strict); - sessionMock.Setup(p => p.ConnectionInfo) - .Returns(new ConnectionInfo("A", "B", new PasswordAuthenticationMethod("A", "B"))); - sessionMock.Setup(p => p.CreateChannelSession()) - .Returns(channelSessionMock.Object); - channelSessionMock.Setup(p => p.Open()); - channelSessionMock.Setup(p => p.SendPseudoTerminalRequest(_terminalName, + _ = sessionMock.Setup(p => p.ConnectionInfo) + .Returns(new ConnectionInfo("A", "B", new PasswordAuthenticationMethod("A", "B"))); + _ = sessionMock.Setup(p => p.CreateChannelSession()) + .Returns(channelSessionMock.Object); + _ = channelSessionMock.Setup(p => p.Open()); + _ = channelSessionMock.Setup(p => p.SendPseudoTerminalRequest(_terminalName, _widthColumns, _heightRows, _widthPixels, _heightPixels, null)) - .Returns(true); - channelSessionMock.Setup(p => p.SendShellRequest()) - .Returns(true); + .Returns(true); + _ = channelSessionMock.Setup(p => p.SendShellRequest()) + .Returns(true); return new ShellStream(sessionMock.Object, _terminalName, diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_Disconnect_ForwardedPortStarted.cs b/src/Renci.SshNet.Tests/Classes/SshClientTest_Disconnect_ForwardedPortStarted.cs index 6b1259f0c..234512645 100644 --- a/src/Renci.SshNet.Tests/Classes/SshClientTest_Disconnect_ForwardedPortStarted.cs +++ b/src/Renci.SshNet.Tests/Classes/SshClientTest_Disconnect_ForwardedPortStarted.cs @@ -27,24 +27,24 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.Connect()); _forwardedPortMock.InSequence(sequence).Setup(p => p.Start()); - _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); + SessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); _forwardedPortMock.InSequence(sequence).Setup(p => p.Stop()); - _sessionMock.InSequence(sequence).Setup(p => p.Dispose()); + SessionMock.InSequence(sequence).Setup(p => p.Dispose()); } protected override void Arrange() { base.Arrange(); - _sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object); + _sshClient = new SshClient(_connectionInfo, false, ServiceFactoryMock.Object); _sshClient.Connect(); _sshClient.AddForwardedPort(_forwardedPortMock.Object); @@ -71,13 +71,13 @@ public void ForwardedPortShouldBeRemovedFromSshClient() [TestMethod] public void DisconnectOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.Disconnect(), Times.Never); + SessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisposeOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Dispose(), Times.Once); + SessionMock.Verify(p => p.Dispose(), Times.Once); } } } diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Connected.cs b/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Connected.cs index 55108df62..fd10b8937 100644 --- a/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Connected.cs @@ -18,22 +18,22 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); - _sessionMock.InSequence(sequence).Setup(p => p.Dispose()); + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.Connect()); + SessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); + SessionMock.InSequence(sequence).Setup(p => p.Dispose()); } protected override void Arrange() { base.Arrange(); - _sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object); + _sshClient = new SshClient(_connectionInfo, false, ServiceFactoryMock.Object); _sshClient.Connect(); } @@ -45,32 +45,32 @@ protected override void Act() [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void DisconnectOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.Disconnect(), Times.Never); + SessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisposeOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Dispose(), Times.Once); + SessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void OnDisconnectingOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.OnDisconnecting(), Times.Once); + SessionMock.Verify(p => p.OnDisconnecting(), Times.Once); } } } diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disconnected.cs b/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disconnected.cs index 1d78561be..bae18feb5 100644 --- a/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disconnected.cs +++ b/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disconnected.cs @@ -18,22 +18,22 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); - _sessionMock.InSequence(sequence).Setup(p => p.Dispose()); + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.Connect()); + SessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); + SessionMock.InSequence(sequence).Setup(p => p.Dispose()); } protected override void Arrange() { base.Arrange(); - _sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object); + _sshClient = new SshClient(_connectionInfo, false, ServiceFactoryMock.Object); _sshClient.Connect(); _sshClient.Disconnect(); } @@ -46,32 +46,32 @@ protected override void Act() [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void DisconnectOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.Disconnect(), Times.Never); + SessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisposeOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Dispose(), Times.Once); + SessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void OnDisconnectingOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.OnDisconnecting(), Times.Once); + SessionMock.Verify(p => p.OnDisconnecting(), Times.Once); } } } diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disposed.cs b/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disposed.cs index 54e07be9e..c4dcf868a 100644 --- a/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disposed.cs +++ b/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disposed.cs @@ -18,22 +18,22 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); - _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); - _sessionMock.InSequence(sequence).Setup(p => p.Dispose()); + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.Connect()); + SessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); + SessionMock.InSequence(sequence).Setup(p => p.Dispose()); } protected override void Arrange() { base.Arrange(); - _sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object); + _sshClient = new SshClient(_connectionInfo, false, ServiceFactoryMock.Object); _sshClient.Connect(); _sshClient.Dispose(); } @@ -46,32 +46,32 @@ protected override void Act() [TestMethod] public void CreateSocketFactoryOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); + ServiceFactoryMock.Verify(p => p.CreateSocketFactory(), Times.Once); } [TestMethod] public void CreateSessionOnServiceFactoryShouldBeInvokedOnce() { - _serviceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object), + ServiceFactoryMock.Verify(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object), Times.Once); } [TestMethod] public void DisconnectOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.Disconnect(), Times.Never); + SessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisposeOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Dispose(), Times.Once); + SessionMock.Verify(p => p.Dispose(), Times.Once); } [TestMethod] public void OnDisconnectingOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.OnDisconnecting(), Times.Once); + SessionMock.Verify(p => p.OnDisconnecting(), Times.Once); } } } diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_ForwardedPortStarted.cs b/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_ForwardedPortStarted.cs index 0b6da3cd3..213e11ef3 100644 --- a/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_ForwardedPortStarted.cs +++ b/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_ForwardedPortStarted.cs @@ -28,24 +28,24 @@ protected override void SetupMocks() { var sequence = new MockSequence(); - _serviceFactoryMock.InSequence(sequence) + ServiceFactoryMock.InSequence(sequence) .Setup(p => p.CreateSocketFactory()) - .Returns(_socketFactoryMock.Object); - _serviceFactoryMock.InSequence(sequence) - .Setup(p => p.CreateSession(_connectionInfo, _socketFactoryMock.Object)) - .Returns(_sessionMock.Object); - _sessionMock.InSequence(sequence).Setup(p => p.Connect()); + .Returns(SocketFactoryMock.Object); + ServiceFactoryMock.InSequence(sequence) + .Setup(p => p.CreateSession(_connectionInfo, SocketFactoryMock.Object)) + .Returns(SessionMock.Object); + SessionMock.InSequence(sequence).Setup(p => p.Connect()); _forwardedPortMock.InSequence(sequence).Setup(p => p.Start()); - _sessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); + SessionMock.InSequence(sequence).Setup(p => p.OnDisconnecting()); _forwardedPortMock.InSequence(sequence).Setup(p => p.Stop()); - _sessionMock.InSequence(sequence).Setup(p => p.Dispose()); + SessionMock.InSequence(sequence).Setup(p => p.Dispose()); } protected override void Arrange() { base.Arrange(); - _sshClient = new SshClient(_connectionInfo, false, _serviceFactoryMock.Object); + _sshClient = new SshClient(_connectionInfo, false, ServiceFactoryMock.Object); _sshClient.Connect(); _sshClient.AddForwardedPort(_forwardedPortMock.Object); @@ -86,13 +86,13 @@ public void IsConnectedShouldThrowObjectDisposedException() [TestMethod] public void DisconnectOnSessionShouldNeverBeInvoked() { - _sessionMock.Verify(p => p.Disconnect(), Times.Never); + SessionMock.Verify(p => p.Disconnect(), Times.Never); } [TestMethod] public void DisposeOnSessionShouldBeInvokedOnce() { - _sessionMock.Verify(p => p.Dispose(), Times.Once); + SessionMock.Verify(p => p.Dispose(), Times.Once); } } } diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs b/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs index cfd68b078..d43a11e5e 100644 --- a/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs @@ -104,10 +104,14 @@ public void Test_Execute_OutputStream() { var result = reader.ReadToEnd(); if (string.IsNullOrEmpty(result)) + { continue; + } + Console.Write(result); } - cmd.EndExecute(asynch); + + _ = cmd.EndExecute(asynch); client.Disconnect(); #endregion @@ -730,4 +734,4 @@ private static bool ExecuteTestCommand(SshClient s) return result.Equals(testValue); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultFromOtherInstance.cs b/src/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultFromOtherInstance.cs index b312a2058..5584786c5 100644 --- a/src/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultFromOtherInstance.cs +++ b/src/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultFromOtherInstance.cs @@ -1,8 +1,11 @@ 锘縰sing System; using System.Globalization; using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Tests.Common; @@ -39,15 +42,26 @@ private void Arrange() _asyncResultB = null; var seq = new MockSequence(); - _sessionMock.InSequence(seq).Setup(p => p.CreateChannelSession()).Returns(_channelSessionAMock.Object); - _channelSessionAMock.InSequence(seq).Setup(p => p.Open()); - _channelSessionAMock.InSequence(seq).Setup(p => p.SendExecRequest(_commandText)).Returns(true); - _sessionMock.InSequence(seq).Setup(p => p.CreateChannelSession()).Returns(_channelSessionBMock.Object); - _channelSessionBMock.InSequence(seq).Setup(p => p.Open()); - _channelSessionBMock.InSequence(seq).Setup(p => p.SendExecRequest(_commandText)).Returns(true); + + _ = _sessionMock.InSequence(seq) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionAMock.Object); + _ = _channelSessionAMock.InSequence(seq) + .Setup(p => p.Open()); + _ = _channelSessionAMock.InSequence(seq) + .Setup(p => p.SendExecRequest(_commandText)) + .Returns(true); + _ = _sessionMock.InSequence(seq) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionBMock.Object); + _ = _channelSessionBMock.InSequence(seq) + .Setup(p => p.Open()); + _ = _channelSessionBMock.InSequence(seq) + .Setup(p => p.SendExecRequest(_commandText)) + .Returns(true); _sshCommandA = new SshCommand(_sessionMock.Object, _commandText, _encoding); - _sshCommandA.BeginExecute(); + _ = _sshCommandA.BeginExecute(); _sshCommandB = new SshCommand(_sessionMock.Object, _commandText, _encoding); _asyncResultB = _sshCommandB.BeginExecute(); @@ -57,7 +71,7 @@ private void Act() { try { - _sshCommandA.EndExecute(_asyncResultB); + _ = _sshCommandA.EndExecute(_asyncResultB); Assert.Fail(); } catch (ArgumentException ex) @@ -71,7 +85,7 @@ public void EndExecuteShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("The {0} object was not returned from the corresponding asynchronous method on this class.", typeof(IAsyncResult).Name), _actualException.Message); + Assert.AreEqual(string.Format("The {0} object was not returned from the corresponding asynchronous method on this class.", nameof(IAsyncResult)), _actualException.Message); Assert.IsNull(_actualException.ParamName); } } diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSessionStub.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSessionStub.cs index 241b49104..e7fab595a 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSessionStub.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSessionStub.cs @@ -1,7 +1,7 @@ 锘縰sing System; using System.Collections.Generic; -using System.Text; using System.Threading; + using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes @@ -29,10 +29,12 @@ public int OnChannelOpenInvocationCount protected override void OnChannelOpen() { - Interlocked.Increment(ref _onChannelOpenInvocationCount); + _ = Interlocked.Increment(ref _onChannelOpenInvocationCount); if (OnChannelOpenException != null) + { throw OnChannelOpenException; + } } protected override void OnDataReceived(byte[] data) @@ -40,7 +42,9 @@ protected override void OnDataReceived(byte[] data) OnDataReceivedInvocations.Add(new ChannelDataEventArgs(0, data)); if (OnDataReceivedException != null) + { throw OnDataReceivedException; + } } } } diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disconnected.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disconnected.cs index 1d15dd6e5..273ceef45 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disconnected.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disconnected.cs @@ -1,9 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -42,18 +44,29 @@ protected void Arrange() _channelAfterDisconnectMock = new Mock(MockBehavior.Strict); _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.CreateChannelSession()).Returns(_channelBeforeDisconnectMock.Object); - _channelBeforeDisconnectMock.InSequence(_sequence).Setup(p => p.Open()); - _channelBeforeDisconnectMock.InSequence(_sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); - _channelBeforeDisconnectMock.InSequence(_sequence).Setup(p => p.Dispose()); - _sessionMock.InSequence(_sequence).Setup(p => p.CreateChannelSession()).Returns(_channelAfterDisconnectMock.Object); - _channelAfterDisconnectMock.InSequence(_sequence).Setup(p => p.Open()); - _channelAfterDisconnectMock.InSequence(_sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); - - _subsystemSession = new SubsystemSessionStub( - _sessionMock.Object, - _subsystemName, - _operationTimeout); + + _ = _sessionMock.InSequence(_sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelBeforeDisconnectMock.Object); + _ = _channelBeforeDisconnectMock.InSequence(_sequence) + .Setup(p => p.Open()); + _ = _channelBeforeDisconnectMock.InSequence(_sequence) + .Setup(p => p.SendSubsystemRequest(_subsystemName)) + .Returns(true); + _ = _channelBeforeDisconnectMock.InSequence(_sequence) + .Setup(p => p.Dispose()); + _ = _sessionMock.InSequence(_sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelAfterDisconnectMock.Object); + _ = _channelAfterDisconnectMock.InSequence(_sequence) + .Setup(p => p.Open()); + _ = _channelAfterDisconnectMock.InSequence(_sequence) + .Setup(p => p.SendSubsystemRequest(_subsystemName)) + .Returns(true); + + _subsystemSession = new SubsystemSessionStub(_sessionMock.Object, + _subsystemName, + _operationTimeout); _subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args); _subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args); _subsystemSession.Connect(); @@ -80,7 +93,9 @@ public void ErrorOccurredHasNeverFired() [TestMethod] public void IsOpenShouldReturnTrueWhenChannelIsOpen() { - _channelAfterDisconnectMock.InSequence(_sequence).Setup(p => p.IsOpen).Returns(true); + _ = _channelAfterDisconnectMock.InSequence(_sequence) + .Setup(p => p.IsOpen) + .Returns(true); Assert.IsTrue(_subsystemSession.IsOpen); @@ -90,7 +105,9 @@ public void IsOpenShouldReturnTrueWhenChannelIsOpen() [TestMethod] public void IsOpenShouldReturnFalseWhenChannelIsNotOpen() { - _channelAfterDisconnectMock.InSequence(_sequence).Setup(p => p.IsOpen).Returns(false); + _ = _channelAfterDisconnectMock.InSequence(_sequence) + .Setup(p => p.IsOpen) + .Returns(false); Assert.IsFalse(_subsystemSession.IsOpen); diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disposed.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disposed.cs index 11e6b0c63..2d90ce740 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disposed.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disposed.cs @@ -1,9 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -40,14 +42,19 @@ protected void Arrange() _channelMock = new Mock(MockBehavior.Strict); var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelMock.Object); - _channelMock.InSequence(sequence).Setup(p => p.Open()); - _channelMock.InSequence(sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); - _subsystemSession = new SubsystemSessionStub( - _sessionMock.Object, - _subsystemName, - _operationTimeout); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelMock.Object); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.Open()); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.SendSubsystemRequest(_subsystemName)) + .Returns(true); + + _subsystemSession = new SubsystemSessionStub(_sessionMock.Object, + _subsystemName, + _operationTimeout); _subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args); _subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args); _subsystemSession.Dispose(); @@ -58,6 +65,7 @@ protected void Act() try { _subsystemSession.Connect(); + Assert.Fail(); } catch (ObjectDisposedException ex) { diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_NeverConnected.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_NeverConnected.cs index d784c7aed..23bd273ed 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_NeverConnected.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_NeverConnected.cs @@ -1,9 +1,4 @@ -锘縰sing System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Renci.SshNet.Tests.Classes +锘縩amespace Renci.SshNet.Tests.Classes { class SubsystemSession_Connect_NeverConnected { diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Connected.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Connected.cs index f5d078135..bf1b3b789 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Connected.cs @@ -1,9 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -40,10 +42,17 @@ protected void Arrange() _channelMock = new Mock(MockBehavior.Strict); _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.CreateChannelSession()).Returns(_channelMock.Object); - _channelMock.InSequence(_sequence).Setup(p => p.Open()); - _channelMock.InSequence(_sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); - _channelMock.InSequence(_sequence).Setup(p => p.Dispose()); + + _ = _sessionMock.InSequence(_sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelMock.Object); + _ = _channelMock.InSequence(_sequence) + .Setup(p => p.Open()); + _ = _channelMock.InSequence(_sequence) + .Setup(p => p.SendSubsystemRequest(_subsystemName)) + .Returns(true); + _ = _channelMock.InSequence(_sequence) + .Setup(p => p.Dispose()); _subsystemSession = new SubsystemSessionStub( _sessionMock.Object, diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Disposed.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Disposed.cs index 21116a78e..4ee558c3b 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Disposed.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Disposed.cs @@ -1,9 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -39,15 +41,21 @@ protected void Arrange() _channelMock = new Mock(MockBehavior.Strict); var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelMock.Object); - _channelMock.InSequence(sequence).Setup(p => p.Open()); - _channelMock.InSequence(sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); - _channelMock.InSequence(sequence).Setup(p => p.Dispose()); - _subsystemSession = new SubsystemSessionStub( - _sessionMock.Object, - _subsystemName, - _operationTimeout); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelMock.Object); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.Open()); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.SendSubsystemRequest(_subsystemName)) + .Returns(true); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.Dispose()); + + _subsystemSession = new SubsystemSessionStub(_sessionMock.Object, + _subsystemName, + _operationTimeout); _subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args); _subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args); _subsystemSession.Connect(); diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_NeverConnected.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_NeverConnected.cs index 71b161a56..a7edaf9f6 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_NeverConnected.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_NeverConnected.cs @@ -1,9 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes @@ -35,10 +37,9 @@ protected void Arrange() _sessionMock = new Mock(MockBehavior.Strict); - _subsystemSession = new SubsystemSessionStub( - _sessionMock.Object, - _subsystemName, - _operationTimeout); + _subsystemSession = new SubsystemSessionStub(_sessionMock.Object, + _subsystemName, + _operationTimeout); _subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args); _subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args); } diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Connected.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Connected.cs index f89da65ce..3de5b14a7 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Connected.cs @@ -1,9 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -39,15 +41,13 @@ protected void Arrange() _channelMock = new Mock(MockBehavior.Strict); var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelMock.Object); - _channelMock.InSequence(sequence).Setup(p => p.Open()); - _channelMock.InSequence(sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); - _channelMock.InSequence(sequence).Setup(p => p.Dispose()); - _subsystemSession = new SubsystemSessionStub( - _sessionMock.Object, - _subsystemName, - _operationTimeout); + _ = _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelMock.Object); + _ = _channelMock.InSequence(sequence).Setup(p => p.Open()); + _ = _channelMock.InSequence(sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); + _ = _channelMock.InSequence(sequence).Setup(p => p.Dispose()); + + _subsystemSession = new SubsystemSessionStub(_sessionMock.Object, _subsystemName, _operationTimeout); _subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args); _subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args); _subsystemSession.Connect(); diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disconnected.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disconnected.cs index c304ed43a..eaae69dc0 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disconnected.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disconnected.cs @@ -1,9 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -39,10 +41,17 @@ protected void Arrange() _channelMock = new Mock(MockBehavior.Strict); var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelMock.Object); - _channelMock.InSequence(sequence).Setup(p => p.Open()); - _channelMock.InSequence(sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); - _channelMock.InSequence(sequence).Setup(p => p.Dispose()); + + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelMock.Object); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.Open()); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.SendSubsystemRequest(_subsystemName)) + .Returns(true); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.Dispose()); _subsystemSession = new SubsystemSessionStub( _sessionMock.Object, diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disposed.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disposed.cs index d2f93decf..e0da36780 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disposed.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disposed.cs @@ -1,9 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -39,10 +41,17 @@ protected void Arrange() _channelMock = new Mock(MockBehavior.Strict); var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelMock.Object); - _channelMock.InSequence(sequence).Setup(p => p.Open()); - _channelMock.InSequence(sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); - _channelMock.InSequence(sequence).Setup(p => p.Dispose()); + + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelMock.Object); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.Open()); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.SendSubsystemRequest(_subsystemName)) + .Returns(true); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.Dispose()); _subsystemSession = new SubsystemSessionStub( _sessionMock.Object, diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_NeverConnected.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_NeverConnected.cs index 83fab8995..96e768c9e 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_NeverConnected.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_NeverConnected.cs @@ -1,10 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; -using Renci.SshNet.Channels; + using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes @@ -29,6 +30,7 @@ public void Setup() protected void Arrange() { var random = new Random(); + _subsystemName = random.Next().ToString(CultureInfo.InvariantCulture); _operationTimeout = 30000; _disconnectedRegister = new List(); @@ -36,10 +38,9 @@ protected void Arrange() _sessionMock = new Mock(MockBehavior.Strict); - _subsystemSession = new SubsystemSessionStub( - _sessionMock.Object, - _subsystemName, - _operationTimeout); + _subsystemSession = new SubsystemSessionStub(_sessionMock.Object, + _subsystemName, + _operationTimeout); _subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args); _subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args); } diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Disposed.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Disposed.cs index d9b3a162b..9f6f054ec 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Disposed.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Disposed.cs @@ -1,9 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -41,10 +43,17 @@ protected void Arrange() _channelMock = new Mock(MockBehavior.Strict); var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelMock.Object); - _channelMock.InSequence(sequence).Setup(p => p.Open()); - _channelMock.InSequence(sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); - _channelMock.InSequence(sequence).Setup(p => p.Dispose()); + + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelMock.Object); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.Open()); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.SendSubsystemRequest(_subsystemName)) + .Returns(true); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.Dispose()); _subsystemSession = new SubsystemSessionStub( _sessionMock.Object, diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Connected.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Connected.cs index b6851cfcf..f689d8017 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Connected.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Connected.cs @@ -1,9 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -40,14 +42,19 @@ protected void Arrange() _channelMock = new Mock(MockBehavior.Strict); _sequence = new MockSequence(); - _sessionMock.InSequence(_sequence).Setup(p => p.CreateChannelSession()).Returns(_channelMock.Object); - _channelMock.InSequence(_sequence).Setup(p => p.Open()); - _channelMock.InSequence(_sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); - - _subsystemSession = new SubsystemSessionStub( - _sessionMock.Object, - _subsystemName, - _operationTimeout); + + _ = _sessionMock.InSequence(_sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelMock.Object); + _ = _channelMock.InSequence(_sequence) + .Setup(p => p.Open()); + _ = _channelMock.InSequence(_sequence) + .Setup(p => p.SendSubsystemRequest(_subsystemName)) + .Returns(true); + + _subsystemSession = new SubsystemSessionStub(_sessionMock.Object, + _subsystemName, + _operationTimeout); _subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args); _subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args); _subsystemSession.Connect(); @@ -73,7 +80,9 @@ public void ErrorOccurredHasNeverFired() [TestMethod] public void IsOpenShouldReturnTrueWhenChannelIsOpen() { - _channelMock.InSequence(_sequence).Setup(p => p.IsOpen).Returns(true); + _ = _channelMock.InSequence(_sequence) + .Setup(p => p.IsOpen) + .Returns(true); Assert.IsTrue(_subsystemSession.IsOpen); @@ -83,7 +92,9 @@ public void IsOpenShouldReturnTrueWhenChannelIsOpen() [TestMethod] public void IsOpenShouldReturnFalseWhenChannelIsNotOpen() { - _channelMock.InSequence(_sequence).Setup(p => p.IsOpen).Returns(false); + _ = _channelMock.InSequence(_sequence) + .Setup(p => p.IsOpen) + .Returns(false); Assert.IsFalse(_subsystemSession.IsOpen); diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Disposed.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Disposed.cs index 7a90eba4c..177bbff33 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Disposed.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Disposed.cs @@ -1,9 +1,11 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; -using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; @@ -39,15 +41,21 @@ protected void Arrange() _channelMock = new Mock(MockBehavior.Strict); var sequence = new MockSequence(); - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelMock.Object); - _channelMock.InSequence(sequence).Setup(p => p.Open()); - _channelMock.InSequence(sequence).Setup(p => p.SendSubsystemRequest(_subsystemName)).Returns(true); - _channelMock.InSequence(sequence).Setup(p => p.Dispose()); - _subsystemSession = new SubsystemSessionStub( - _sessionMock.Object, - _subsystemName, - _operationTimeout); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelMock.Object); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.Open()); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.SendSubsystemRequest(_subsystemName)) + .Returns(true); + _ = _channelMock.InSequence(sequence) + .Setup(p => p.Dispose()); + + _subsystemSession = new SubsystemSessionStub(_sessionMock.Object, + _subsystemName, + _operationTimeout); _subsystemSession.Disconnected += (sender, args) => _disconnectedRegister.Add(args); _subsystemSession.ErrorOccurred += (sender, args) => _errorOccurredRegister.Add(args); _subsystemSession.Connect(); diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disconnected.cs b/src/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disconnected.cs index 6d60a61b2..92754621d 100644 --- a/src/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disconnected.cs +++ b/src/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disconnected.cs @@ -1,9 +1,4 @@ -锘縰sing System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Renci.SshNet.Tests.Classes +锘縩amespace Renci.SshNet.Tests.Classes { class SubsystemSession_SendData_Disconnected { diff --git a/src/Renci.SshNet.Tests/Common/ArrayBuilder.cs b/src/Renci.SshNet.Tests/Common/ArrayBuilder.cs index cff2e4c32..9f9f7d659 100644 --- a/src/Renci.SshNet.Tests/Common/ArrayBuilder.cs +++ b/src/Renci.SshNet.Tests/Common/ArrayBuilder.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Tests.Common { public class ArrayBuilder { - private List _buffer; + private readonly List _buffer; public ArrayBuilder() { @@ -19,7 +19,10 @@ public ArrayBuilder Add(T[] array) public ArrayBuilder Add(T[] array, int index, int length) { for (var i = 0; i < length; i++) + { _buffer.Add(array[index + i]); + } + return this; } diff --git a/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs b/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs index 6815d1609..0f7dac81f 100644 --- a/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs +++ b/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs @@ -10,11 +10,11 @@ public class AsyncSocketListener : IDisposable { private readonly IPEndPoint _endPoint; private readonly ManualResetEvent _acceptCallbackDone; - private List _connectedClients; + private readonly List _connectedClients; + private readonly object _syncLock; private Socket _listener; private Thread _receiveThread; private bool _started; - private object _syncLock; private string _stackTrace; public delegate void BytesReceivedHandler(byte[] bytesReceived, Socket socket); @@ -84,10 +84,7 @@ public void Stop() _connectedClients.Clear(); } - if (_listener != null) - { - _listener.Dispose(); - } + _listener?.Dispose(); if (_receiveThread != null) { @@ -109,9 +106,9 @@ private void StartListener(object state) var listener = (Socket)state; while (_started) { - _acceptCallbackDone.Reset(); - listener.BeginAccept(AcceptCallback, listener); - _acceptCallbackDone.WaitOne(); + _ = _acceptCallbackDone.Reset(); + _ = listener.BeginAccept(AcceptCallback, listener); + _ = _acceptCallbackDone.WaitOne(); } } catch (Exception ex) @@ -128,7 +125,7 @@ private void StartListener(object state) private void AcceptCallback(IAsyncResult ar) { // Signal the main thread to continue - _acceptCallbackDone.Set(); + _ = _acceptCallbackDone.Set(); // Get the socket that listens for inbound connections var listener = (Socket)ar.AsyncState; @@ -188,7 +185,7 @@ private void AcceptCallback(IAsyncResult ar) try { - handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state); + _ =handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state); } catch (SocketException ex) { @@ -308,7 +305,7 @@ void ConnectionDisconnected() throw new Exception("Exception in ReadCallback: " + _stackTrace, ex); } - _connectedClients.Remove(handler); + _ = _connectedClients.Remove(handler); } } } @@ -321,7 +318,7 @@ void ConnectionDisconnected() try { - handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state); + _ = handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state); } catch (ObjectDisposedException) { @@ -347,23 +344,17 @@ void ConnectionDisconnected() private void SignalBytesReceived(byte[] bytesReceived, Socket client) { - var subscribers = BytesReceived; - if (subscribers != null) - subscribers(bytesReceived, client); + BytesReceived?.Invoke(bytesReceived, client); } private void SignalConnected(Socket client) { - var subscribers = Connected; - if (subscribers != null) - subscribers(client); + Connected?.Invoke(client); } private void SignalDisconnected(Socket client) { - var subscribers = Disconnected; - if (subscribers != null) - subscribers(client); + Disconnected?.Invoke(client); } private static void DrainSocket(Socket socket) diff --git a/src/Renci.SshNet.Tests/Common/DictionaryAssert.cs b/src/Renci.SshNet.Tests/Common/DictionaryAssert.cs index 0df1c5049..ec45fb61a 100644 --- a/src/Renci.SshNet.Tests/Common/DictionaryAssert.cs +++ b/src/Renci.SshNet.Tests/Common/DictionaryAssert.cs @@ -8,22 +8,29 @@ public static class DictionaryAssert public static void AreEqual(IDictionary expected, IDictionary actual) { if (ReferenceEquals(expected, actual)) + { return; + } if (expected == null) + { throw new AssertFailedException("Expected dictionary to be null, but was not null."); + } if (actual == null) + { throw new AssertFailedException("Expected dictionary not to be null, but was null."); + } if (expected.Count != actual.Count) + { throw new AssertFailedException(string.Format("Expected dictionary to contain {0} entries, but was {1}.", expected.Count, actual.Count)); + } foreach (var expectedEntry in expected) { - TValue actualValue; - if (!actual.TryGetValue(expectedEntry.Key, out actualValue)) + if (!actual.TryGetValue(expectedEntry.Key, out var actualValue)) { throw new AssertFailedException(string.Format("Dictionary contains no entry with key '{0}'.", expectedEntry.Key)); } diff --git a/src/Renci.SshNet.Tests/Common/Extensions.cs b/src/Renci.SshNet.Tests/Common/Extensions.cs index 4e88a7900..2c2e04bef 100644 --- a/src/Renci.SshNet.Tests/Common/Extensions.cs +++ b/src/Renci.SshNet.Tests/Common/Extensions.cs @@ -10,11 +10,15 @@ internal static class Extensions public static string AsString(this IList exceptionEvents) { if (exceptionEvents.Count == 0) + { return string.Empty; + } - string reportedExceptions = string.Empty; + var reportedExceptions = string.Empty; foreach (var exceptionEvent in exceptionEvents) + { reportedExceptions += exceptionEvent.Exception.ToString(); + } return reportedExceptions; } diff --git a/src/Renci.SshNet.Tests/Common/HttpProxyStub.cs b/src/Renci.SshNet.Tests/Common/HttpProxyStub.cs index d7bdba506..7cc8c4715 100644 --- a/src/Renci.SshNet.Tests/Common/HttpProxyStub.cs +++ b/src/Renci.SshNet.Tests/Common/HttpProxyStub.cs @@ -24,7 +24,10 @@ public HttpRequest HttpRequest get { if (_httpRequestParser == null) + { throw new InvalidOperationException("The proxy is not started."); + } + return _httpRequestParser.HttpRequest; } } @@ -45,8 +48,7 @@ public void Start() public void Stop() { - if (_listener != null) - _listener.Stop(); + _listener?.Stop(); } public void Dispose() @@ -62,7 +64,10 @@ private void OnBytesReceived(byte[] bytesReceived, Socket socket) if (_httpRequestParser.CurrentState == HttpRequestParser.State.Content) { foreach (var response in Responses) - socket.Send(response); + { + _ = socket.Send(response); + } + socket.Shutdown(SocketShutdown.Send); } } @@ -150,11 +155,16 @@ private string ReadLine(byte[] data, ref int position) { var buffer = _buffer.ToArray(); var bytesInLine = buffer.Length; + // when the previous byte was a CR, then do not include it in line if (buffer.Length > 0 && buffer[buffer.Length - 1] == '\r') + { bytesInLine -= 1; + } + // clear the buffer _buffer.Clear(); + // move position up one position as we've processed the current byte position++; return Encoding.ASCII.GetString(buffer, 0, bytesInLine); @@ -166,4 +176,4 @@ private string ReadLine(byte[] data, ref int position) } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Common/SftpFileAttributesBuilder.cs b/src/Renci.SshNet.Tests/Common/SftpFileAttributesBuilder.cs index 2cf1b11a8..92521316e 100644 --- a/src/Renci.SshNet.Tests/Common/SftpFileAttributesBuilder.cs +++ b/src/Renci.SshNet.Tests/Common/SftpFileAttributesBuilder.cs @@ -64,23 +64,27 @@ public SftpFileAttributesBuilder WithExtension(string name, string value) public SftpFileAttributes Build() { if (_lastAccessTime == null) + { _lastAccessTime = DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc); + } else if (_lastAccessTime.Value.Kind != DateTimeKind.Utc) + { _lastAccessTime = _lastAccessTime.Value.ToUniversalTime(); + } if (_lastWriteTime == null) + { _lastWriteTime = DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc); + } else if (_lastWriteTime.Value.Kind != DateTimeKind.Utc) + { _lastWriteTime = _lastWriteTime.Value.ToUniversalTime(); + } - if (_size == null) - _size = 0; - if (_userId == null) - _userId = 0; - if (_groupId == null) - _groupId = 0; - if (_permissions == null) - _permissions = 0; + _size ??= 0; + _userId ??= 0; + _groupId ??= 0; + _permissions ??= 0; return new SftpFileAttributes(_lastAccessTime.Value, _lastWriteTime.Value, diff --git a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index 89a270445..f4c0b6f33 100644 --- a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -13,10 +13,6 @@ $(NoWarn);CS1591 - - FEATURE_TPL - - diff --git a/src/Renci.SshNet/.editorconfig b/src/Renci.SshNet/.editorconfig index 7c507c75c..c0430021e 100644 --- a/src/Renci.SshNet/.editorconfig +++ b/src/Renci.SshNet/.editorconfig @@ -1,5 +1,12 @@ 锘縖*.cs] +#### SYSLIB diagnostics #### + +# SYSLIB1045: Use 'GeneratedRegexAttribute' to generate the regular expression implementation at compile-time +# +# TODO: Remove this when https://github.com/sshnet/SSH.NET/issues/1131 is implemented. +dotnet_diagnostic.SYSLIB1045.severity = none + ### StyleCop Analyzers rules ### # SA1202: Elements must be ordered by access diff --git a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs index 3c6fb90a3..5784879fa 100644 --- a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs @@ -186,6 +186,7 @@ public static void ReadContinuous(Socket socket, byte[] buffer, int offset, int continue; } +#pragma warning disable IDE0010 // Add missing cases switch (ex.SocketErrorCode) { case SocketError.ConnectionAborted: @@ -199,6 +200,7 @@ public static void ReadContinuous(Socket socket, byte[] buffer, int offset, int default: throw; // throw any other error } +#pragma warning restore IDE0010 // Add missing cases } } } @@ -369,6 +371,7 @@ public static void Send(Socket socket, byte[] data, int offset, int size) public static bool IsErrorResumable(SocketError socketError) { +#pragma warning disable IDE0010 // Add missing cases switch (socketError) { case SocketError.WouldBlock: @@ -378,6 +381,7 @@ public static bool IsErrorResumable(SocketError socketError) default: return false; } +#pragma warning restore IDE0010 // Add missing cases } #if FEATURE_SOCKET_EAP diff --git a/src/Renci.SshNet/Abstractions/SocketExtensions.cs b/src/Renci.SshNet/Abstractions/SocketExtensions.cs index 84c2f03df..8e6c0133b 100644 --- a/src/Renci.SshNet/Abstractions/SocketExtensions.cs +++ b/src/Renci.SshNet/Abstractions/SocketExtensions.cs @@ -36,7 +36,7 @@ public void SetCompleted() IsCompleted = true; var continuation = _continuationAction ?? Interlocked.CompareExchange(ref _continuationAction, SENTINEL, null); - if (continuation != null) + if (continuation is not null) { continuation(); } diff --git a/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs b/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs index b506a64c8..0c9e3b64f 100644 --- a/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs @@ -15,7 +15,7 @@ public static void Sleep(int millisecondsTimeout) public static void ExecuteThreadLongRunning(Action action) { - if (action == null) + if (action is null) { throw new ArgumentNullException(nameof(action)); } @@ -30,7 +30,7 @@ public static void ExecuteThreadLongRunning(Action action) /// The action to execute. public static void ExecuteThread(Action action) { - if (action == null) + if (action is null) { throw new ArgumentNullException(nameof(action)); } diff --git a/src/Renci.SshNet/BaseClient.cs b/src/Renci.SshNet/BaseClient.cs index 6596ceedb..ed0db2bba 100644 --- a/src/Renci.SshNet/BaseClient.cs +++ b/src/Renci.SshNet/BaseClient.cs @@ -182,12 +182,12 @@ protected BaseClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo) /// internal BaseClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) { - if (connectionInfo == null) + if (connectionInfo is null) { throw new ArgumentNullException(nameof(connectionInfo)); } - if (serviceFactory == null) + if (serviceFactory is null) { throw new ArgumentNullException(nameof(serviceFactory)); } @@ -453,7 +453,7 @@ protected void CheckDisposed() /// private void StopKeepAliveTimer() { - if (_keepAliveTimer == null) + if (_keepAliveTimer is null) { return; } @@ -467,7 +467,7 @@ private void SendKeepAliveMessage() var session = Session; // do nothing if we have disposed or disconnected - if (session == null) + if (session is null) { return; } diff --git a/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs b/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs index 374272b29..11eea894c 100644 --- a/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs +++ b/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs @@ -113,14 +113,14 @@ public void Bind() /// private void CloseSocket() { - if (_socket == null) + if (_socket is null) { return; } lock (_socketLock) { - if (_socket == null) + if (_socket is null) { return; } @@ -138,7 +138,7 @@ private void CloseSocket() /// One of the values that specifies the operation that will no longer be allowed. private void ShutdownSocket(SocketShutdown how) { - if (_socket == null) + if (_socket is null) { return; } diff --git a/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs b/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs index 321a00d02..465c8f181 100644 --- a/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs +++ b/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs @@ -119,7 +119,7 @@ private void ForwardedPort_Closing(object sender, EventArgs eventArgs) /// One of the values that specifies the operation that will no longer be allowed. private void ShutdownSocket(SocketShutdown how) { - if (_socket == null) + if (_socket is null) { return; } @@ -149,7 +149,7 @@ private void ShutdownSocket(SocketShutdown how) /// private void CloseSocket() { - if (_socket == null) + if (_socket is null) { return; } diff --git a/src/Renci.SshNet/Channels/ClientChannel.cs b/src/Renci.SshNet/Channels/ClientChannel.cs index 1ec03c6bc..f1b332afb 100644 --- a/src/Renci.SshNet/Channels/ClientChannel.cs +++ b/src/Renci.SshNet/Channels/ClientChannel.cs @@ -117,7 +117,7 @@ protected override void Dispose(bool disposing) /// private void UnsubscribeFromSessionEvents(ISession session) { - if (session == null) + if (session is null) { return; } diff --git a/src/Renci.SshNet/ClientAuthentication.cs b/src/Renci.SshNet/ClientAuthentication.cs index a8a6745e2..6d91455af 100644 --- a/src/Renci.SshNet/ClientAuthentication.cs +++ b/src/Renci.SshNet/ClientAuthentication.cs @@ -44,12 +44,12 @@ internal int PartialSuccessLimit /// The for which to perform authentication. public void Authenticate(IConnectionInfoInternal connectionInfo, ISession session) { - if (connectionInfo == null) + if (connectionInfo is null) { throw new ArgumentNullException(nameof(connectionInfo)); } - if (session == null) + if (session is null) { throw new ArgumentNullException(nameof(session)); } @@ -138,6 +138,8 @@ private bool TryAuthenticate(ISession session, case AuthenticationResult.Success: authenticationException = null; break; + default: + break; } if (authenticationResult == AuthenticationResult.Success) diff --git a/src/Renci.SshNet/Common/AsyncResult.cs b/src/Renci.SshNet/Common/AsyncResult.cs index ec103552e..acc1da119 100644 --- a/src/Renci.SshNet/Common/AsyncResult.cs +++ b/src/Renci.SshNet/Common/AsyncResult.cs @@ -121,7 +121,7 @@ public WaitHandle AsyncWaitHandle { get { - if (_asyncWaitHandle == null) + if (_asyncWaitHandle is null) { var done = IsCompleted; var mre = new ManualResetEvent(done); diff --git a/src/Renci.SshNet/Common/BigInteger.cs b/src/Renci.SshNet/Common/BigInteger.cs index 8e8f7b514..47c0aa4a4 100644 --- a/src/Renci.SshNet/Common/BigInteger.cs +++ b/src/Renci.SshNet/Common/BigInteger.cs @@ -288,13 +288,15 @@ public BigInteger(ulong value) else { _sign = 1; - var low = (uint)value; - var high = (uint)(value >> 32); + var low = (uint) value; + var high = (uint) (value >> 32); _data = new uint[high != 0 ? 2 : 1]; _data[0] = low; if (high != 0) + { _data[1] = high; + } } } @@ -377,7 +379,10 @@ public BigInteger(decimal value) var bits = decimal.GetBits(decimal.Truncate(value)); var size = 3; - while (size > 0 && bits[size - 1] == 0) size--; + while (size > 0 && bits[size - 1] == 0) + { + size--; + } if (size == 0) { @@ -409,7 +414,7 @@ public BigInteger(decimal value) [CLSCompliant(false)] public BigInteger(byte[] value) { - if (value == null) + if (value is null) { throw new ArgumentNullException(nameof(value)); } @@ -765,7 +770,7 @@ public static BigInteger Zero /// public static explicit operator int(BigInteger value) { - if (value._data == null) + if (value._data is null) { return 0; } @@ -810,7 +815,7 @@ public static explicit operator int(BigInteger value) [CLSCompliant(false)] public static explicit operator uint(BigInteger value) { - if (value._data == null) + if (value._data is null) { return 0; } @@ -906,7 +911,7 @@ public static explicit operator sbyte(BigInteger value) /// public static explicit operator long(BigInteger value) { - if (value._data == null) + if (value._data is null) { return 0; } @@ -970,7 +975,7 @@ long.MinValue works fine since it's bigint encoding looks like a negative [CLSCompliant(false)] public static explicit operator ulong(BigInteger value) { - if (value._data == null) + if (value._data is null) { return 0; } @@ -999,7 +1004,7 @@ public static explicit operator ulong(BigInteger value) /// public static explicit operator double(BigInteger value) { - if (value._data == null) + if (value._data is null) { return 0.0; } @@ -1050,7 +1055,7 @@ public static explicit operator float(BigInteger value) /// public static explicit operator decimal(BigInteger value) { - if (value._data == null) + if (value._data is null) { return decimal.Zero; } @@ -1360,7 +1365,10 @@ public static explicit operator BigInteger(decimal value) } int m; - for (m = res.Length - 1; m >= 0 && res[m] == 0; --m) ; + for (m = res.Length - 1; m >= 0 && res[m] == 0; --m) + { + // Intentionally empty block + } if (m < res.Length - 1) { @@ -1394,7 +1402,10 @@ public static explicit operator BigInteger(decimal value) DivModUnsigned(dividend._data, divisor._data, out var quotient, out _); int i; - for (i = quotient.Length - 1; i >= 0 && quotient[i] == 0; --i) ; + for (i = quotient.Length - 1; i >= 0 && quotient[i] == 0; --i) + { + // Intentionally empty block + } if (i == -1) { @@ -1432,7 +1443,10 @@ public static explicit operator BigInteger(decimal value) DivModUnsigned(dividend._data, divisor._data, out _, out var remainderValue); int i; - for (i = remainderValue.Length - 1; i >= 0 && remainderValue[i] == 0; --i) ; + for (i = remainderValue.Length - 1; i >= 0 && remainderValue[i] == 0; --i) + { + // Intentionally empty block + } if (i == -1) { @@ -1456,7 +1470,7 @@ public static explicit operator BigInteger(decimal value) /// public static BigInteger operator -(BigInteger value) { - if (value._data == null) + if (value._data is null) { return value; } @@ -1488,7 +1502,7 @@ public static explicit operator BigInteger(decimal value) /// public static BigInteger operator ++(BigInteger value) { - if (value._data == null) + if (value._data is null) { return One; } @@ -1522,7 +1536,7 @@ public static explicit operator BigInteger(decimal value) /// public static BigInteger operator --(BigInteger value) { - if (value._data == null) + if (value._data is null) { return MinusOne; } @@ -1619,7 +1633,10 @@ public static explicit operator BigInteger(decimal value) result[i] = word; } - for (i = result.Length - 1; i >= 0 && result[i] == 0; --i) ; + for (i = result.Length - 1; i >= 0 && result[i] == 0; --i) + { + // Intentionally empty block + } if (i == -1) { @@ -1706,7 +1723,10 @@ public static explicit operator BigInteger(decimal value) result[i] = word; } - for (i = result.Length - 1; i >= 0 && result[i] == 0; --i) ; + for (i = result.Length - 1; i >= 0 && result[i] == 0; --i) + { + // Intentionally empty block + } if (i == -1) { @@ -1793,7 +1813,10 @@ public static explicit operator BigInteger(decimal value) result[i] = word; } - for (i = result.Length - 1; i >= 0 && result[i] == 0; --i) ; + for (i = result.Length - 1; i >= 0 && result[i] == 0; --i) + { + // Intentionally empty block + } if (i == -1) { @@ -1817,7 +1840,7 @@ public static explicit operator BigInteger(decimal value) /// public static BigInteger operator ~(BigInteger value) { - if (value._data == null) + if (value._data is null) { return MinusOne; } @@ -1854,7 +1877,10 @@ public static explicit operator BigInteger(decimal value) result[i] = word; } - for (i = result.Length - 1; i >= 0 && result[i] == 0; --i) ; + for (i = result.Length - 1; i >= 0 && result[i] == 0; --i) + { + // Intentionally empty block + } if (i == -1) { @@ -1895,7 +1921,7 @@ static int BitScanBackward(uint word) /// public static BigInteger operator <<(BigInteger value, int shift) { - if (shift == 0 || value._data == null) + if (shift == 0 || value._data is null) { return value; } @@ -2876,7 +2902,7 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, result = Zero; exc = null; - if (value == null) + if (value is null) { if (!tryParse) { @@ -3420,7 +3446,7 @@ private static bool Parse(string value, bool tryParse, out BigInteger result, ou result = Zero; exc = null; - if (value == null) + if (value is null) { if (!tryParse) { @@ -3630,7 +3656,10 @@ public static BigInteger DivRem(BigInteger dividend, BigInteger divisor, out Big DivModUnsigned(dividend._data, divisor._data, out var quotient, out var remainderValue); int i; - for (i = remainderValue.Length - 1; i >= 0 && remainderValue[i] == 0; --i) ; + for (i = remainderValue.Length - 1; i >= 0 && remainderValue[i] == 0; --i) + { + // Intentionally empty block + } if (i == -1) { @@ -3646,7 +3675,10 @@ public static BigInteger DivRem(BigInteger dividend, BigInteger divisor, out Big remainder = new BigInteger(dividend._sign, remainderValue); } - for (i = quotient.Length - 1; i >= 0 && quotient[i] == 0; --i) ; + for (i = quotient.Length - 1; i >= 0 && quotient[i] == 0; --i) + { + // Intentionally empty block + } if (i == -1) { @@ -3870,7 +3902,7 @@ public static double Log(BigInteger value, double baseValue) return value.IsOne ? 0 : double.NaN; } - if (value._data == null) + if (value._data is null) { return double.NegativeInfinity; } @@ -4079,7 +4111,7 @@ public static BigInteger Negate(BigInteger value) /// is not a . public readonly int CompareTo(object obj) { - if (obj == null) + if (obj is null) { return 1; } @@ -4539,7 +4571,11 @@ private static uint[] CoreSub(uint[] a, uint[] b) } // remove extra zeroes - for (i = bl - 1; i >= 0 && res[i] == 0; --i) ; + for (i = bl - 1; i >= 0 && res[i] == 0; --i) + { + // Intentionally empty block + } + if (i < bl - 1) { Array.Resize(ref res, i + 1); @@ -4586,7 +4622,11 @@ private static uint[] CoreSub(uint[] a, uint b) } // Remove extra zeroes - for (i = len - 1; i >= 0 && res[i] == 0; --i) ; + for (i = len - 1; i >= 0 && res[i] == 0; --i) + { + // Intentionally empty block + } + if (i < len - 1) { Array.Resize(ref res, i + 1); @@ -4658,7 +4698,9 @@ private static int GetNormalizeShift(uint value) if ((value & 0x80000000) == 0) { +#pragma warning disable IDE0059 // Unnecessary assignment of a value value <<= 1; +#pragma warning restore IDE0059 // Unnecessary assignment of a value shift += 1; } @@ -4746,7 +4788,7 @@ private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] q[j] = (uint)div; } - r[0] = (uint)rem; + r[0] = (uint) rem; } else if (m >= n) { @@ -4759,7 +4801,6 @@ private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] Normalize(v, n, vn, shift); q = new uint[m - n + 1]; - r = null; // Main division loop for (var j = m - n; j >= 0; j--) @@ -4789,7 +4830,7 @@ private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] // Multiply and subtract long b = 0; - long t = 0; + long t; for (i = 0; i < n; i++) { var p = vn[i] * qq; diff --git a/src/Renci.SshNet/Common/Extensions.cs b/src/Renci.SshNet/Common/Extensions.cs index 1e6bb6def..8fed310c1 100644 --- a/src/Renci.SshNet/Common/Extensions.cs +++ b/src/Renci.SshNet/Common/Extensions.cs @@ -126,7 +126,7 @@ internal static void DebugPrint(this IEnumerable bytes) internal static T CreateInstance(this Type type) where T : class { - if (type == null) + if (type is null) { return null; } @@ -173,7 +173,7 @@ internal static void ValidatePort(this int value, string argument) /// public static byte[] Take(this byte[] value, int offset, int count) { - if (value == null) + if (value is null) { throw new ArgumentNullException(nameof(value)); } @@ -208,7 +208,7 @@ public static byte[] Take(this byte[] value, int offset, int count) /// public static byte[] Take(this byte[] value, int count) { - if (value == null) + if (value is null) { throw new ArgumentNullException(nameof(value)); } @@ -230,12 +230,12 @@ public static byte[] Take(this byte[] value, int count) public static bool IsEqualTo(this byte[] left, byte[] right) { - if (left == null) + if (left is null) { throw new ArgumentNullException(nameof(left)); } - if (right == null) + if (right is null) { throw new ArgumentNullException(nameof(right)); } @@ -270,7 +270,7 @@ public static bool IsEqualTo(this byte[] left, byte[] right) /// public static byte[] TrimLeadingZeros(this byte[] value) { - if (value == null) + if (value is null) { throw new ArgumentNullException(nameof(value)); } @@ -317,12 +317,12 @@ public static byte[] Pad(this byte[] data, int length) public static byte[] Concat(this byte[] first, byte[] second) { - if (first == null || first.Length == 0) + if (first is null || first.Length == 0) { return second; } - if (second == null || second.Length == 0) + if (second is null || second.Length == 0) { return first; } @@ -345,7 +345,7 @@ internal static bool CanWrite(this Socket socket) internal static bool IsConnected(this Socket socket) { - if (socket == null) + if (socket is null) { return false; } diff --git a/src/Renci.SshNet/Common/ObjectIdentifier.cs b/src/Renci.SshNet/Common/ObjectIdentifier.cs index ab491cce6..f1b2d88df 100644 --- a/src/Renci.SshNet/Common/ObjectIdentifier.cs +++ b/src/Renci.SshNet/Common/ObjectIdentifier.cs @@ -20,7 +20,7 @@ public struct ObjectIdentifier /// has less than two elements. public ObjectIdentifier(params ulong[] identifiers) { - if (identifiers == null) + if (identifiers is null) { throw new ArgumentNullException(nameof(identifiers)); } diff --git a/src/Renci.SshNet/Common/PacketDump.cs b/src/Renci.SshNet/Common/PacketDump.cs index c9357a3af..47329f6d0 100644 --- a/src/Renci.SshNet/Common/PacketDump.cs +++ b/src/Renci.SshNet/Common/PacketDump.cs @@ -14,7 +14,7 @@ public static string Create(List data, int indentLevel) public static string Create(byte[] data, int indentLevel) { - if (data == null) + if (data is null) { throw new ArgumentNullException(nameof(data)); } diff --git a/src/Renci.SshNet/Common/PipeStream.cs b/src/Renci.SshNet/Common/PipeStream.cs index 71a82e1d8..d2fe8d369 100644 --- a/src/Renci.SshNet/Common/PipeStream.cs +++ b/src/Renci.SshNet/Common/PipeStream.cs @@ -185,7 +185,7 @@ public override int Read(byte[] buffer, int offset, int count) throw new NotSupportedException("Offsets with value of non-zero are not supported"); } - if (buffer == null) + if (buffer is null) { throw new ArgumentNullException(nameof(buffer)); } @@ -269,7 +269,7 @@ private bool ReadAvailable(int count) /// offset or count is negative. public override void Write(byte[] buffer, int offset, int count) { - if (buffer == null) + if (buffer is null) { throw new ArgumentNullException(nameof(buffer)); } diff --git a/src/Renci.SshNet/Common/PortForwardEventArgs.cs b/src/Renci.SshNet/Common/PortForwardEventArgs.cs index 4d1f1656d..a94748b6f 100644 --- a/src/Renci.SshNet/Common/PortForwardEventArgs.cs +++ b/src/Renci.SshNet/Common/PortForwardEventArgs.cs @@ -17,7 +17,7 @@ public class PortForwardEventArgs : EventArgs /// is not within and . internal PortForwardEventArgs(string host, uint port) { - if (host == null) + if (host is null) { throw new ArgumentNullException(nameof(host)); } diff --git a/src/Renci.SshNet/Common/PosixPath.cs b/src/Renci.SshNet/Common/PosixPath.cs index 2d028bd67..0dae95ea1 100644 --- a/src/Renci.SshNet/Common/PosixPath.cs +++ b/src/Renci.SshNet/Common/PosixPath.cs @@ -38,7 +38,7 @@ private PosixPath() /// is empty (""). public static PosixPath CreateAbsoluteOrRelativeFilePath(string path) { - if (path == null) + if (path is null) { throw new ArgumentNullException(nameof(path)); } @@ -95,7 +95,7 @@ public static PosixPath CreateAbsoluteOrRelativeFilePath(string path) /// public static string GetFileName(string path) { - if (path == null) + if (path is null) { throw new ArgumentNullException(nameof(path)); } @@ -125,7 +125,7 @@ public static string GetFileName(string path) /// is null. public static string GetDirectoryName(string path) { - if (path == null) + if (path is null) { throw new ArgumentNullException(nameof(path)); } diff --git a/src/Renci.SshNet/Common/SemaphoreLight.cs b/src/Renci.SshNet/Common/SemaphoreLight.cs index f3210c788..8ee4167d1 100644 --- a/src/Renci.SshNet/Common/SemaphoreLight.cs +++ b/src/Renci.SshNet/Common/SemaphoreLight.cs @@ -52,7 +52,7 @@ public WaitHandle AvailableWaitHandle { get { - if (_waitHandle == null) + if (_waitHandle is null) { lock (_lock) { diff --git a/src/Renci.SshNet/Common/SshData.cs b/src/Renci.SshNet/Common/SshData.cs index 0a10eee64..67823ec2d 100644 --- a/src/Renci.SshNet/Common/SshData.cs +++ b/src/Renci.SshNet/Common/SshData.cs @@ -85,7 +85,7 @@ protected virtual void WriteBytes(SshDataStream stream) /// is null. public void Load(byte[] data) { - if (data == null) + if (data is null) { throw new ArgumentNullException(nameof(data)); } @@ -102,7 +102,7 @@ public void Load(byte[] data) /// is null. public void Load(byte[] data, int offset, int count) { - if (data == null) + if (data is null) { throw new ArgumentNullException(nameof(data)); } diff --git a/src/Renci.SshNet/Common/SshDataStream.cs b/src/Renci.SshNet/Common/SshDataStream.cs index 54a5505f5..1eedd3ffc 100644 --- a/src/Renci.SshNet/Common/SshDataStream.cs +++ b/src/Renci.SshNet/Common/SshDataStream.cs @@ -93,7 +93,7 @@ public void Write(BigInteger data) /// is null. public void Write(byte[] data) { - if (data == null) + if (data is null) { throw new ArgumentNullException(nameof(data)); } @@ -126,7 +126,7 @@ public byte[] ReadBinary() /// is null. public void WriteBinary(byte[] buffer) { - if (buffer == null) + if (buffer is null) { throw new ArgumentNullException(nameof(buffer)); } @@ -158,7 +158,7 @@ public void WriteBinary(byte[] buffer, int offset, int count) /// is null. public void Write(string s, Encoding encoding) { - if (encoding == null) + if (encoding is null) { throw new ArgumentNullException(nameof(encoding)); } diff --git a/src/Renci.SshNet/Compression/ZlibStream.cs b/src/Renci.SshNet/Compression/ZlibStream.cs index e12996943..5c9d3b841 100644 --- a/src/Renci.SshNet/Compression/ZlibStream.cs +++ b/src/Renci.SshNet/Compression/ZlibStream.cs @@ -14,7 +14,9 @@ public class ZlibStream ///
/// The stream. /// The mode. +#pragma warning disable IDE0060 // Remove unused parameter public ZlibStream(Stream stream, CompressionMode mode) +#pragma warning restore IDE0060 // Remove unused parameter { //switch (mode) //{ @@ -37,7 +39,9 @@ public ZlibStream(Stream stream, CompressionMode mode) /// The buffer. /// The offset. /// The count. +#pragma warning disable IDE0060 // Remove unused parameter public void Write(byte[] buffer, int offset, int count) +#pragma warning restore IDE0060 // Remove unused parameter { //this._baseStream.Write(buffer, offset, count); } diff --git a/src/Renci.SshNet/Connection/ConnectorBase.cs b/src/Renci.SshNet/Connection/ConnectorBase.cs index 1725657f5..bdea64a6f 100644 --- a/src/Renci.SshNet/Connection/ConnectorBase.cs +++ b/src/Renci.SshNet/Connection/ConnectorBase.cs @@ -14,7 +14,7 @@ internal abstract class ConnectorBase : IConnector { protected ConnectorBase(ISocketFactory socketFactory) { - if (socketFactory == null) + if (socketFactory is null) { throw new ArgumentNullException(nameof(socketFactory)); } diff --git a/src/Renci.SshNet/Connection/HttpConnector.cs b/src/Renci.SshNet/Connection/HttpConnector.cs index 01fa6fa10..832bb3dd3 100644 --- a/src/Renci.SshNet/Connection/HttpConnector.cs +++ b/src/Renci.SshNet/Connection/HttpConnector.cs @@ -63,13 +63,13 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke while (true) { var response = SocketReadLine(socket, connectionInfo.Timeout); - if (response == null) + if (response is null) { // server shut down socket break; } - if (statusCode == null) + if (statusCode is null) { var statusMatch = httpResponseRe.Match(response); if (statusMatch.Success) @@ -112,7 +112,7 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke } } - if (statusCode == null) + if (statusCode is null) { throw new ProxyException("HTTP response does not contain status line."); } diff --git a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs index 044f58715..8f3beb51f 100644 --- a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs +++ b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs @@ -47,7 +47,7 @@ public SshIdentification Start(string clientVersion, Socket socket, TimeSpan tim while (true) { var line = SocketReadLine(socket, timeout, bytesReceived); - if (line == null) + if (line is null) { if (bytesReceived.Count == 0) { @@ -80,7 +80,7 @@ public async Task StartAsync(string clientVersion, Socket soc while (true) { var line = await SocketReadLineAsync(socket, bytesReceived, cancellationToken).ConfigureAwait(false); - if (line == null) + if (line is null) { if (bytesReceived.Count == 0) { @@ -143,7 +143,7 @@ private static string SocketReadLine(Socket socket, TimeSpan timeout, List buffer.Add(byteRead); // The null character MUST NOT be sent - if (byteRead == Null) + if (byteRead is Null) { throw CreateServerResponseContainsNullCharacterException(buffer); } @@ -187,7 +187,7 @@ private static async Task SocketReadLineAsync(Socket socket, List buffer.Add(byteRead); // The null character MUST NOT be sent - if (byteRead == Null) + if (byteRead is Null) { throw CreateServerResponseContainsNullCharacterException(buffer); } diff --git a/src/Renci.SshNet/Connection/Socks5Connector.cs b/src/Renci.SshNet/Connection/Socks5Connector.cs index 9cfc4758f..ef9f9974c 100644 --- a/src/Renci.SshNet/Connection/Socks5Connector.cs +++ b/src/Renci.SshNet/Connection/Socks5Connector.cs @@ -49,6 +49,7 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke switch (authenticationMethod) { case 0x00: + // No authentication break; case 0x02: // Create username/password authentication request @@ -73,6 +74,8 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke break; case 0xFF: throw new ProxyException("SOCKS5: No acceptable authentication methods were offered."); + default: + throw new ProxyException($"SOCKS5: Chosen authentication method '0x{authenticationMethod:x2}' is not supported."); } var connectionRequest = CreateSocks5ConnectionRequest(connectionInfo.Host, (ushort) connectionInfo.Port); @@ -238,6 +241,7 @@ private static byte[] GetSocks5DestinationAddress(string hostname, out byte addr byte[] address; +#pragma warning disable IDE0010 // Add missing cases switch (ip.AddressFamily) { case AddressFamily.InterNetwork: @@ -251,6 +255,7 @@ private static byte[] GetSocks5DestinationAddress(string hostname, out byte addr default: throw new ProxyException(string.Format("SOCKS5: IP address '{0}' is not supported.", ip)); } +#pragma warning restore IDE0010 // Add missing cases return address; } diff --git a/src/Renci.SshNet/Connection/SshIdentification.cs b/src/Renci.SshNet/Connection/SshIdentification.cs index 9484ea0c8..a950ad71f 100644 --- a/src/Renci.SshNet/Connection/SshIdentification.cs +++ b/src/Renci.SshNet/Connection/SshIdentification.cs @@ -31,12 +31,12 @@ public SshIdentification(string protocolVersion, string softwareVersion) /// is . public SshIdentification(string protocolVersion, string softwareVersion, string comments) { - if (protocolVersion == null) + if (protocolVersion is null) { throw new ArgumentNullException(nameof(protocolVersion)); } - if (softwareVersion == null) + if (softwareVersion is null) { throw new ArgumentNullException(nameof(softwareVersion)); } diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index b36b4eb15..89abcd63d 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -297,14 +297,14 @@ public ConnectionInfo(string host, int port, string username, params Authenticat /// No specified. public ConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params AuthenticationMethod[] authenticationMethods) { - if (host == null) + if (host is null) { throw new ArgumentNullException(nameof(host)); } port.ValidatePort("port"); - if (username == null) + if (username is null) { throw new ArgumentNullException(nameof(username)); } @@ -316,7 +316,7 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy if (proxyType != ProxyTypes.None) { - if (proxyHost == null) + if (proxyHost is null) { throw new ArgumentNullException(nameof(proxyHost)); } @@ -324,7 +324,7 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy proxyPort.ValidatePort("proxyPort"); } - if (authenticationMethods == null) + if (authenticationMethods is null) { throw new ArgumentNullException(nameof(authenticationMethods)); } @@ -445,7 +445,7 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy /// No suitable authentication method found to complete authentication, or permission denied. internal void Authenticate(ISession session, IServiceFactory serviceFactory) { - if (serviceFactory == null) + if (serviceFactory is null) { throw new ArgumentNullException(nameof(serviceFactory)); } diff --git a/src/Renci.SshNet/ExpectAction.cs b/src/Renci.SshNet/ExpectAction.cs index 4a52c889d..2274c52a3 100644 --- a/src/Renci.SshNet/ExpectAction.cs +++ b/src/Renci.SshNet/ExpectAction.cs @@ -26,12 +26,12 @@ public class ExpectAction /// or is null. public ExpectAction(Regex expect, Action action) { - if (expect == null) + if (expect is null) { throw new ArgumentNullException(nameof(expect)); } - if (action == null) + if (action is null) { throw new ArgumentNullException(nameof(action)); } @@ -48,12 +48,12 @@ public ExpectAction(Regex expect, Action action) /// or is null. public ExpectAction(string expect, Action action) { - if (expect == null) + if (expect is null) { throw new ArgumentNullException(nameof(expect)); } - if (action == null) + if (action is null) { throw new ArgumentNullException(nameof(action)); } diff --git a/src/Renci.SshNet/ForwardedPort.cs b/src/Renci.SshNet/ForwardedPort.cs index deca52423..f4544094c 100644 --- a/src/Renci.SshNet/ForwardedPort.cs +++ b/src/Renci.SshNet/ForwardedPort.cs @@ -60,7 +60,7 @@ public virtual void Start() throw new InvalidOperationException("Forwarded port is already started."); } - if (Session == null) + if (Session is null) { throw new InvalidOperationException("Forwarded port is not added to a client."); } diff --git a/src/Renci.SshNet/ForwardedPortDynamic.NET.cs b/src/Renci.SshNet/ForwardedPortDynamic.NET.cs index 957483f71..eca6f6427 100644 --- a/src/Renci.SshNet/ForwardedPortDynamic.NET.cs +++ b/src/Renci.SshNet/ForwardedPortDynamic.NET.cs @@ -43,7 +43,7 @@ partial void InternalStart() private void StartAccept(SocketAsyncEventArgs e) { - if (e == null) + if (e is null) { e = new SocketAsyncEventArgs(); e.Completed += AcceptCompleted; @@ -178,9 +178,12 @@ private void InitializePendingChannelCountdown() private bool HandleSocks(IChannelDirectTcpip channel, Socket clientSocket, TimeSpan timeout) { - // create eventhandler which is to be invoked to interrupt a blocking receive - // when we're closing the forwarded port + +#pragma warning disable IDE0039 // Use lambda instead of local function to reduce allocations + // Create eventhandler which is to be invoked to interrupt a blocking receive + // when we're closing the forwarded port. EventHandler closeClientSocket = (_, args) => CloseClientSocket(clientSocket); +#pragma warning restore IDE0039 // Use lambda instead of local function to reduce allocations Closing += closeClientSocket; @@ -351,7 +354,7 @@ private bool HandleSocks4(Socket socket, IChannelDirectTcpip channel, TimeSpan t var ipAddress = new IPAddress(ipBuffer); var username = ReadString(socket, timeout); - if (username == null) + if (username is null) { // SOCKS client closed connection return false; @@ -418,7 +421,9 @@ private bool HandleSocks5(Socket socket, IChannelDirectTcpip channel, TimeSpan t } if (version != 5) + { throw new ProxyException("SOCKS5: Version 5 is expected."); + } var commandCode = SocketAbstraction.ReadByte(socket, timeout); if (commandCode == -1) @@ -447,7 +452,7 @@ private bool HandleSocks5(Socket socket, IChannelDirectTcpip channel, TimeSpan t } var host = GetSocks5Host(addressType, socket, timeout); - if (host == null) + if (host is null) { // SOCKS client closed connection return false; diff --git a/src/Renci.SshNet/ForwardedPortLocal.NET.cs b/src/Renci.SshNet/ForwardedPortLocal.NET.cs index 60777b97a..3bd9e3f52 100644 --- a/src/Renci.SshNet/ForwardedPortLocal.NET.cs +++ b/src/Renci.SshNet/ForwardedPortLocal.NET.cs @@ -38,7 +38,7 @@ partial void InternalStart() private void StartAccept(SocketAsyncEventArgs e) { - if (e == null) + if (e is null) { e = new SocketAsyncEventArgs(); e.Completed += AcceptCompleted; diff --git a/src/Renci.SshNet/ForwardedPortLocal.cs b/src/Renci.SshNet/ForwardedPortLocal.cs index fe3215de2..8dabb09fb 100644 --- a/src/Renci.SshNet/ForwardedPortLocal.cs +++ b/src/Renci.SshNet/ForwardedPortLocal.cs @@ -88,12 +88,12 @@ public ForwardedPortLocal(string boundHost, string host, uint port) /// is greater than . public ForwardedPortLocal(string boundHost, uint boundPort, string host, uint port) { - if (boundHost == null) + if (boundHost is null) { throw new ArgumentNullException(nameof(boundHost)); } - if (host == null) + if (host is null) { throw new ArgumentNullException(nameof(host)); } diff --git a/src/Renci.SshNet/ForwardedPortRemote.cs b/src/Renci.SshNet/ForwardedPortRemote.cs index 6405f13a1..4d220c644 100644 --- a/src/Renci.SshNet/ForwardedPortRemote.cs +++ b/src/Renci.SshNet/ForwardedPortRemote.cs @@ -86,12 +86,12 @@ public string Host /// is greater than . public ForwardedPortRemote(IPAddress boundHostAddress, uint boundPort, IPAddress hostAddress, uint port) { - if (boundHostAddress == null) + if (boundHostAddress is null) { throw new ArgumentNullException(nameof(boundHostAddress)); } - if (hostAddress == null) + if (hostAddress is null) { throw new ArgumentNullException(nameof(hostAddress)); } @@ -328,7 +328,7 @@ private void Session_RequestSuccess(object sender, MessageEventArgs hash) { KeySize = keySize; - HashAlgorithm = key => (hash(key.Take(KeySize / 8))); + HashAlgorithm = key => hash(key.Take(KeySize / 8)); } } } diff --git a/src/Renci.SshNet/MessageEventArgs.cs b/src/Renci.SshNet/MessageEventArgs.cs index fead62e1e..c3886dce1 100644 --- a/src/Renci.SshNet/MessageEventArgs.cs +++ b/src/Renci.SshNet/MessageEventArgs.cs @@ -20,7 +20,7 @@ public class MessageEventArgs : EventArgs /// is null. public MessageEventArgs(T message) { - if (message == null) + if (message is null) { throw new ArgumentNullException(nameof(message)); } diff --git a/src/Renci.SshNet/Messages/Authentication/RequestMessagePublicKey.cs b/src/Renci.SshNet/Messages/Authentication/RequestMessagePublicKey.cs index 9a888e295..391e60e76 100644 --- a/src/Renci.SshNet/Messages/Authentication/RequestMessagePublicKey.cs +++ b/src/Renci.SshNet/Messages/Authentication/RequestMessagePublicKey.cs @@ -92,7 +92,9 @@ protected override void SaveData() WriteBinaryString(PublicKeyAlgorithmName); WriteBinaryString(PublicKeyData); if (Signature != null) + { WriteBinaryString(Signature); + } } } } diff --git a/src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs index 7e88d2828..8a764d798 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs @@ -74,7 +74,7 @@ public ChannelDataMessage() public ChannelDataMessage(uint localChannelNumber, byte[] data) : base(localChannelNumber) { - if (data == null) + if (data is null) { throw new ArgumentNullException(nameof(data)); } @@ -94,7 +94,7 @@ public ChannelDataMessage(uint localChannelNumber, byte[] data) public ChannelDataMessage(uint localChannelNumber, byte[] data, int offset, int size) : base(localChannelNumber) { - if (data == null) + if (data is null) { throw new ArgumentNullException(nameof(data)); } diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExecRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExecRequestInfo.cs index 877dd4326..412a86d88 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExecRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExecRequestInfo.cs @@ -6,7 +6,7 @@ namespace Renci.SshNet.Messages.Connection /// /// Represents "exec" type channel request information. /// - internal class ExecRequestInfo : RequestInfo + internal sealed class ExecRequestInfo : RequestInfo { private byte[] _command; @@ -79,12 +79,12 @@ public ExecRequestInfo() public ExecRequestInfo(string command, Encoding encoding) : this() { - if (command == null) + if (command is null) { throw new ArgumentNullException(nameof(command)); } - if (encoding == null) + if (encoding is null) { throw new ArgumentNullException(nameof(encoding)); } diff --git a/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs b/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs index 72fc10699..7c9fa247c 100644 --- a/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs @@ -49,7 +49,7 @@ protected override int BufferCapacity /// The data. public IgnoreMessage(byte[] data) { - if (data == null) + if (data is null) { throw new ArgumentNullException(nameof(data)); } diff --git a/src/Renci.SshNet/Netconf/NetConfSession.cs b/src/Renci.SshNet/Netconf/NetConfSession.cs index 6e4e251f7..6e6f8c6c8 100644 --- a/src/Renci.SshNet/Netconf/NetConfSession.cs +++ b/src/Renci.SshNet/Netconf/NetConfSession.cs @@ -110,7 +110,7 @@ protected override void OnDataReceived(byte[] data) { var chunk = Encoding.UTF8.GetString(data); - if (ServerCapabilities == null) + if (ServerCapabilities is null) { _ = _data.Append(chunk); diff --git a/src/Renci.SshNet/NoneAuthenticationMethod.cs b/src/Renci.SshNet/NoneAuthenticationMethod.cs index 468d46559..71e100175 100644 --- a/src/Renci.SshNet/NoneAuthenticationMethod.cs +++ b/src/Renci.SshNet/NoneAuthenticationMethod.cs @@ -43,7 +43,7 @@ public NoneAuthenticationMethod(string username) /// is null. public override AuthenticationResult Authenticate(Session session) { - if (session == null) + if (session is null) { throw new ArgumentNullException(nameof(session)); } diff --git a/src/Renci.SshNet/PasswordAuthenticationMethod.cs b/src/Renci.SshNet/PasswordAuthenticationMethod.cs index a60b40ebf..5c7e8aaa9 100644 --- a/src/Renci.SshNet/PasswordAuthenticationMethod.cs +++ b/src/Renci.SshNet/PasswordAuthenticationMethod.cs @@ -68,7 +68,7 @@ public PasswordAuthenticationMethod(string username, string password) public PasswordAuthenticationMethod(string username, byte[] password) : base(username) { - if (password == null) + if (password is null) { throw new ArgumentNullException(nameof(password)); } @@ -87,7 +87,7 @@ public PasswordAuthenticationMethod(string username, byte[] password) /// is null. public override AuthenticationResult Authenticate(Session session) { - if (session == null) + if (session is null) { throw new ArgumentNullException(nameof(session)); } diff --git a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs index 25f3f7605..1606ef757 100644 --- a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs +++ b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs @@ -41,7 +41,7 @@ public override string Name public PrivateKeyAuthenticationMethod(string username, params IPrivateKeySource[] keyFiles) : base(username) { - if (keyFiles == null) + if (keyFiles is null) { throw new ArgumentNullException(nameof(keyFiles)); } diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 4da514384..e00a27fcd 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -147,7 +147,7 @@ public PrivateKeyFile(Stream privateKey, string passPhrase) /// The pass phrase. private void Open(Stream privateKey, string passPhrase) { - if (privateKey == null) + if (privateKey is null) { throw new ArgumentNullException(nameof(privateKey)); } @@ -258,7 +258,9 @@ private void Open(Stream privateKey, string passPhrase) else if (ssh2CipherName == "3des-cbc") { if (string.IsNullOrEmpty(passPhrase)) + { throw new SshPassPhraseNullOrEmptyException("Private key is encrypted but passphrase is empty."); + } var key = GetCipherKey(passPhrase, 192 / 8); var ssh2小ipher = new TripleDesCipher(key, new CbcCipherMode(new byte[8]), new PKCS7Padding()); @@ -349,17 +351,17 @@ private static byte[] GetCipherKey(string passphrase, int length) /// , , or is null. private static byte[] DecryptKey(CipherInfo cipherInfo, byte[] cipherData, string passPhrase, byte[] binarySalt) { - if (cipherInfo == null) + if (cipherInfo is null) { throw new ArgumentNullException(nameof(cipherInfo)); } - if (cipherData == null) + if (cipherData is null) { throw new ArgumentNullException(nameof(cipherData)); } - if (binarySalt == null) + if (binarySalt is null) { throw new ArgumentNullException(nameof(binarySalt)); } diff --git a/src/Renci.SshNet/RemotePathDoubleQuoteTransformation.cs b/src/Renci.SshNet/RemotePathDoubleQuoteTransformation.cs index e4f5496f2..68abce256 100644 --- a/src/Renci.SshNet/RemotePathDoubleQuoteTransformation.cs +++ b/src/Renci.SshNet/RemotePathDoubleQuoteTransformation.cs @@ -50,7 +50,7 @@ internal class RemotePathDoubleQuoteTransformation : IRemotePathTransformation /// public string Transform(string path) { - if (path == null) + if (path is null) { throw new ArgumentNullException(nameof(path)); } diff --git a/src/Renci.SshNet/RemotePathNoneTransformation.cs b/src/Renci.SshNet/RemotePathNoneTransformation.cs index f7bfbab6a..31dea7a87 100644 --- a/src/Renci.SshNet/RemotePathNoneTransformation.cs +++ b/src/Renci.SshNet/RemotePathNoneTransformation.cs @@ -21,7 +21,7 @@ internal class RemotePathNoneTransformation : IRemotePathTransformation /// public string Transform(string path) { - if (path == null) + if (path is null) { throw new ArgumentNullException(nameof(path)); } diff --git a/src/Renci.SshNet/RemotePathShellQuoteTransformation.cs b/src/Renci.SshNet/RemotePathShellQuoteTransformation.cs index 53424286c..9f247ccff 100644 --- a/src/Renci.SshNet/RemotePathShellQuoteTransformation.cs +++ b/src/Renci.SshNet/RemotePathShellQuoteTransformation.cs @@ -80,7 +80,7 @@ internal class RemotePathShellQuoteTransformation : IRemotePathTransformation /// public string Transform(string path) { - if (path == null) + if (path is null) { throw new ArgumentNullException(nameof(path)); } diff --git a/src/Renci.SshNet/ScpClient.NET.cs b/src/Renci.SshNet/ScpClient.NET.cs index 8ca396e7d..ede001942 100644 --- a/src/Renci.SshNet/ScpClient.NET.cs +++ b/src/Renci.SshNet/ScpClient.NET.cs @@ -27,7 +27,7 @@ public partial class ScpClient /// The secure copy execution request was rejected by the server. public void Upload(FileInfo fileInfo, string path) { - if (fileInfo == null) + if (fileInfo is null) { throw new ArgumentNullException(nameof(fileInfo)); } @@ -70,12 +70,12 @@ public void Upload(FileInfo fileInfo, string path) /// The secure copy execution request was rejected by the server. public void Upload(DirectoryInfo directoryInfo, string path) { - if (directoryInfo == null) + if (directoryInfo is null) { throw new ArgumentNullException(nameof(directoryInfo)); } - if (path == null) + if (path is null) { throw new ArgumentNullException(nameof(path)); } @@ -123,7 +123,7 @@ public void Download(string filename, FileInfo fileInfo) throw new ArgumentException("filename"); } - if (fileInfo == null) + if (fileInfo is null) { throw new ArgumentNullException(nameof(fileInfo)); } @@ -163,7 +163,7 @@ public void Download(string directoryName, DirectoryInfo directoryInfo) throw new ArgumentException("directoryName"); } - if (directoryInfo == null) + if (directoryInfo is null) { throw new ArgumentNullException(nameof(directoryInfo)); } diff --git a/src/Renci.SshNet/ScpClient.cs b/src/Renci.SshNet/ScpClient.cs index 7907bfe7d..7269e81c3 100644 --- a/src/Renci.SshNet/ScpClient.cs +++ b/src/Renci.SshNet/ScpClient.cs @@ -77,7 +77,7 @@ public IRemotePathTransformation RemotePathTransformation get { return _remotePathTransformation; } set { - if (value == null) + if (value is null) { throw new ArgumentNullException(nameof(value)); } @@ -248,7 +248,7 @@ public void Download(string filename, Stream destination) throw new ArgumentException(Message); } - if (destination == null) + if (destination is null) { throw new ArgumentNullException(nameof(destination)); } diff --git a/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs b/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs index 17e14c5dc..5a06d7a37 100644 --- a/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs @@ -60,8 +60,7 @@ protected BlockCipher(byte[] key, byte blockSize, CipherMode mode, CipherPadding _mode = mode; _padding = padding; - if (_mode != null) - _mode.Init(this); + _mode?.Init(this); } /// @@ -75,10 +74,11 @@ public override byte[] Encrypt(byte[] data, int offset, int length) { if (length % _blockSize > 0) { - if (_padding == null) + if (_padding is null) { throw new ArgumentException("data"); } + var paddingLength = _blockSize - (length % _blockSize); data = _padding.Pad(data, offset, length, paddingLength); length += paddingLength; @@ -90,7 +90,7 @@ public override byte[] Encrypt(byte[] data, int offset, int length) for (var i = 0; i < length / _blockSize; i++) { - if (_mode == null) + if (_mode is null) { writtenBytes += EncryptBlock(data, offset + (i * _blockSize), _blockSize, output, i * _blockSize); } @@ -131,7 +131,7 @@ public override byte[] Decrypt(byte[] data, int offset, int length) { if (length % _blockSize > 0) { - if (_padding == null) + if (_padding is null) { throw new ArgumentException("data"); } @@ -146,7 +146,7 @@ public override byte[] Decrypt(byte[] data, int offset, int length) var writtenBytes = 0; for (var i = 0; i < length / _blockSize; i++) { - if (_mode == null) + if (_mode is null) { writtenBytes += DecryptBlock(data, offset + (i * _blockSize), _blockSize, output, i * _blockSize); } diff --git a/src/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs index 7312a6292..ec9243fe6 100644 --- a/src/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs @@ -18,7 +18,7 @@ public abstract class CipherDigitalSignature : DigitalSignature /// The cipher. protected CipherDigitalSignature(ObjectIdentifier oid, AsymmetricCipher cipher) { - if (cipher == null) + if (cipher is null) { throw new ArgumentNullException(nameof(cipher)); } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs index 9fb8d0a25..29e4c42e7 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs @@ -1,5 +1,6 @@ 锘縰sing System; using System.Globalization; + using Renci.SshNet.Common; namespace Renci.SshNet.Security.Cryptography.Ciphers @@ -9,19 +10,14 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers /// public sealed class AesCipher : BlockCipher { - private const uint m1 = 0x80808080; - - private const uint m2 = 0x7f7f7f7f; - - private const uint m3 = 0x0000001b; + private const uint M1 = 0x80808080; + private const uint M2 = 0x7f7f7f7f; + private const uint M3 = 0x0000001b; private int _rounds; - private uint[] _encryptionKey; - private uint[] _decryptionKey; - - private uint C0, C1, C2, C3; + private uint _c0, _c1, _c2, _c3; #region Static Definition Tables @@ -99,7 +95,7 @@ public sealed class AesCipher : BlockCipher }; // vector used in calculating key schedule (powers of x in GF(256)) - private static readonly byte[] rcon = + private static readonly byte[] Rcon = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 @@ -590,12 +586,12 @@ public AesCipher(byte[] key, CipherMode mode, CipherPadding padding) /// or is too short. public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - if (inputBuffer == null) + if (inputBuffer is null) { throw new ArgumentNullException(nameof(inputBuffer)); } - if (outputBuffer == null) + if (outputBuffer is null) { throw new ArgumentNullException(nameof(outputBuffer)); } @@ -636,12 +632,12 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC /// or is too short. public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - if (inputBuffer == null) + if (inputBuffer is null) { throw new ArgumentNullException(nameof(inputBuffer)); } - if (outputBuffer == null) + if (outputBuffer is null) { throw new ArgumentNullException(nameof(outputBuffer)); } @@ -669,7 +665,7 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC private uint[] GenerateWorkingKey(bool isEncryption, byte[] key) { - int KC = key.Length / 4; // key length in words + var KC = key.Length / 4; // key length in words if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.Length)) { @@ -677,13 +673,13 @@ private uint[] GenerateWorkingKey(bool isEncryption, byte[] key) } _rounds = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes - uint[] W = new uint[(_rounds + 1) * 4]; // 4 words in a block + var W = new uint[(_rounds + 1) * 4]; // 4 words in a block // // copy the key into the round key array // - int t = 0; + var t = 0; for (var i = 0; i < key.Length; t++) { @@ -695,13 +691,13 @@ private uint[] GenerateWorkingKey(bool isEncryption, byte[] key) // while not enough round key material calculated // calculate new values // - int k = (_rounds + 1) << 2; - for (int i = KC; (i < k); i++) + var k = (_rounds + 1) << 2; + for (var i = KC; i < k; i++) { - uint temp = W[((i - 1) >> 2) * 4 + ((i - 1) & 3)]; + var temp = W[((i - 1) >> 2) * 4 + ((i - 1) & 3)]; if ((i % KC) == 0) { - temp = SubWord(Shift(temp, 8)) ^ rcon[(i / KC) - 1]; + temp = SubWord(Shift(temp, 8)) ^ Rcon[(i / KC) - 1]; } else if ((KC > 6) && ((i % KC) == 4)) { @@ -713,9 +709,9 @@ private uint[] GenerateWorkingKey(bool isEncryption, byte[] key) if (!isEncryption) { - for (int j = 1; j < _rounds; j++) + for (var j = 1; j < _rounds; j++) { - for (int i = 0; i < 4; i++) + for (var i = 0; i < 4; i++) { W[j * 4 + i] = InvMcol(W[j * 4 + i]); } @@ -732,15 +728,15 @@ private static uint Shift(uint r, int shift) private static uint FFmulX(uint x) { - return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3); + return ((x & M2) << 1) ^ (((x & M1) >> 7) * M3); } private static uint InvMcol(uint x) { - uint f2 = FFmulX(x); - uint f4 = FFmulX(f2); - uint f8 = FFmulX(f4); - uint f9 = x ^ f8; + var f2 = FFmulX(x); + var f4 = FFmulX(f2); + var f8 = FFmulX(f4); + var f9 = x ^ f8; return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24); } @@ -755,18 +751,18 @@ private static uint SubWord(uint x) private void UnPackBlock(byte[] bytes, int off) { - C0 = Pack.LittleEndianToUInt32(bytes, off); - C1 = Pack.LittleEndianToUInt32(bytes, off + 4); - C2 = Pack.LittleEndianToUInt32(bytes, off + 8); - C3 = Pack.LittleEndianToUInt32(bytes, off + 12); + _c0 = Pack.LittleEndianToUInt32(bytes, off); + _c1 = Pack.LittleEndianToUInt32(bytes, off + 4); + _c2 = Pack.LittleEndianToUInt32(bytes, off + 8); + _c3 = Pack.LittleEndianToUInt32(bytes, off + 12); } private void PackBlock(byte[] bytes, int off) { - Pack.UInt32ToLittleEndian(C0, bytes, off); - Pack.UInt32ToLittleEndian(C1, bytes, off + 4); - Pack.UInt32ToLittleEndian(C2, bytes, off + 8); - Pack.UInt32ToLittleEndian(C3, bytes, off + 12); + Pack.UInt32ToLittleEndian(_c0, bytes, off); + Pack.UInt32ToLittleEndian(_c1, bytes, off + 4); + Pack.UInt32ToLittleEndian(_c2, bytes, off + 8); + Pack.UInt32ToLittleEndian(_c3, bytes, off + 12); } private void EncryptBlock(uint[] KW) @@ -774,34 +770,34 @@ private void EncryptBlock(uint[] KW) int r; uint r0, r1, r2, r3; - C0 ^= KW[0 * 4 + 0]; - C1 ^= KW[0 * 4 + 1]; - C2 ^= KW[0 * 4 + 2]; - C3 ^= KW[0 * 4 + 3]; + _c0 ^= KW[0 * 4 + 0]; + _c1 ^= KW[0 * 4 + 1]; + _c2 ^= KW[0 * 4 + 2]; + _c3 ^= KW[0 * 4 + 3]; for (r = 1; r < _rounds - 1;) { - r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[C3 >> 24] ^ KW[r * 4 + 0]; - r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[C0 >> 24] ^ KW[r * 4 + 1]; - r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[C1 >> 24] ^ KW[r * 4 + 2]; - r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[C2 >> 24] ^ KW[r++ * 4 + 3]; - C0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[r3 >> 24] ^ KW[r * 4 + 0]; - C1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[r0 >> 24] ^ KW[r * 4 + 1]; - C2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[r1 >> 24] ^ KW[r * 4 + 2]; - C3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[r2 >> 24] ^ KW[r++ * 4 + 3]; + r0 = T0[_c0 & 255] ^ T1[(_c1 >> 8) & 255] ^ T2[(_c2 >> 16) & 255] ^ T3[_c3 >> 24] ^ KW[r * 4 + 0]; + r1 = T0[_c1 & 255] ^ T1[(_c2 >> 8) & 255] ^ T2[(_c3 >> 16) & 255] ^ T3[_c0 >> 24] ^ KW[r * 4 + 1]; + r2 = T0[_c2 & 255] ^ T1[(_c3 >> 8) & 255] ^ T2[(_c0 >> 16) & 255] ^ T3[_c1 >> 24] ^ KW[r * 4 + 2]; + r3 = T0[_c3 & 255] ^ T1[(_c0 >> 8) & 255] ^ T2[(_c1 >> 16) & 255] ^ T3[_c2 >> 24] ^ KW[r++ * 4 + 3]; + _c0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[r3 >> 24] ^ KW[r * 4 + 0]; + _c1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[r0 >> 24] ^ KW[r * 4 + 1]; + _c2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[r1 >> 24] ^ KW[r * 4 + 2]; + _c3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[r2 >> 24] ^ KW[r++ * 4 + 3]; } - r0 = T0[C0 & 255] ^ T1[(C1 >> 8) & 255] ^ T2[(C2 >> 16) & 255] ^ T3[C3 >> 24] ^ KW[r * 4 + 0]; - r1 = T0[C1 & 255] ^ T1[(C2 >> 8) & 255] ^ T2[(C3 >> 16) & 255] ^ T3[C0 >> 24] ^ KW[r * 4 + 1]; - r2 = T0[C2 & 255] ^ T1[(C3 >> 8) & 255] ^ T2[(C0 >> 16) & 255] ^ T3[C1 >> 24] ^ KW[r * 4 + 2]; - r3 = T0[C3 & 255] ^ T1[(C0 >> 8) & 255] ^ T2[(C1 >> 16) & 255] ^ T3[C2 >> 24] ^ KW[r++ * 4 + 3]; + r0 = T0[_c0 & 255] ^ T1[(_c1 >> 8) & 255] ^ T2[(_c2 >> 16) & 255] ^ T3[_c3 >> 24] ^ KW[r * 4 + 0]; + r1 = T0[_c1 & 255] ^ T1[(_c2 >> 8) & 255] ^ T2[(_c3 >> 16) & 255] ^ T3[_c0 >> 24] ^ KW[r * 4 + 1]; + r2 = T0[_c2 & 255] ^ T1[(_c3 >> 8) & 255] ^ T2[(_c0 >> 16) & 255] ^ T3[_c1 >> 24] ^ KW[r * 4 + 2]; + r3 = T0[_c3 & 255] ^ T1[(_c0 >> 8) & 255] ^ T2[(_c1 >> 16) & 255] ^ T3[_c2 >> 24] ^ KW[r++ * 4 + 3]; // the final round's table is a simple function of S so we don't use a whole other four tables for it - C0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[r3 >> 24]) << 24) ^ KW[r * 4 + 0]; - C1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[r0 >> 24]) << 24) ^ KW[r * 4 + 1]; - C2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[r1 >> 24]) << 24) ^ KW[r * 4 + 2]; - C3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[r2 >> 24]) << 24) ^ KW[r * 4 + 3]; + _c0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[r3 >> 24]) << 24) ^ KW[r * 4 + 0]; + _c1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[r0 >> 24]) << 24) ^ KW[r * 4 + 1]; + _c2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[r1 >> 24]) << 24) ^ KW[r * 4 + 2]; + _c3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[r2 >> 24]) << 24) ^ KW[r * 4 + 3]; } private void DecryptBlock(uint[] KW) @@ -809,34 +805,34 @@ private void DecryptBlock(uint[] KW) int r; uint r0, r1, r2, r3; - C0 ^= KW[_rounds * 4 + 0]; - C1 ^= KW[_rounds * 4 + 1]; - C2 ^= KW[_rounds * 4 + 2]; - C3 ^= KW[_rounds * 4 + 3]; + _c0 ^= KW[_rounds * 4 + 0]; + _c1 ^= KW[_rounds * 4 + 1]; + _c2 ^= KW[_rounds * 4 + 2]; + _c3 ^= KW[_rounds * 4 + 3]; for (r = _rounds - 1; r > 1;) { - r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[C1 >> 24] ^ KW[r * 4 + 0]; - r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[C2 >> 24] ^ KW[r * 4 + 1]; - r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[C3 >> 24] ^ KW[r * 4 + 2]; - r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[C0 >> 24] ^ KW[r-- * 4 + 3]; - C0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[r1 >> 24] ^ KW[r * 4 + 0]; - C1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[r2 >> 24] ^ KW[r * 4 + 1]; - C2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ KW[r * 4 + 2]; - C3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[r0 >> 24] ^ KW[r-- * 4 + 3]; + r0 = Tinv0[_c0 & 255] ^ Tinv1[(_c3 >> 8) & 255] ^ Tinv2[(_c2 >> 16) & 255] ^ Tinv3[_c1 >> 24] ^ KW[r * 4 + 0]; + r1 = Tinv0[_c1 & 255] ^ Tinv1[(_c0 >> 8) & 255] ^ Tinv2[(_c3 >> 16) & 255] ^ Tinv3[_c2 >> 24] ^ KW[r * 4 + 1]; + r2 = Tinv0[_c2 & 255] ^ Tinv1[(_c1 >> 8) & 255] ^ Tinv2[(_c0 >> 16) & 255] ^ Tinv3[_c3 >> 24] ^ KW[r * 4 + 2]; + r3 = Tinv0[_c3 & 255] ^ Tinv1[(_c2 >> 8) & 255] ^ Tinv2[(_c1 >> 16) & 255] ^ Tinv3[_c0 >> 24] ^ KW[r-- * 4 + 3]; + _c0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[r1 >> 24] ^ KW[r * 4 + 0]; + _c1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[r2 >> 24] ^ KW[r * 4 + 1]; + _c2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ KW[r * 4 + 2]; + _c3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[r0 >> 24] ^ KW[r-- * 4 + 3]; } - r0 = Tinv0[C0 & 255] ^ Tinv1[(C3 >> 8) & 255] ^ Tinv2[(C2 >> 16) & 255] ^ Tinv3[C1 >> 24] ^ KW[r * 4 + 0]; - r1 = Tinv0[C1 & 255] ^ Tinv1[(C0 >> 8) & 255] ^ Tinv2[(C3 >> 16) & 255] ^ Tinv3[C2 >> 24] ^ KW[r * 4 + 1]; - r2 = Tinv0[C2 & 255] ^ Tinv1[(C1 >> 8) & 255] ^ Tinv2[(C0 >> 16) & 255] ^ Tinv3[C3 >> 24] ^ KW[r * 4 + 2]; - r3 = Tinv0[C3 & 255] ^ Tinv1[(C2 >> 8) & 255] ^ Tinv2[(C1 >> 16) & 255] ^ Tinv3[C0 >> 24] ^ KW[r * 4 + 3]; + r0 = Tinv0[_c0 & 255] ^ Tinv1[(_c3 >> 8) & 255] ^ Tinv2[(_c2 >> 16) & 255] ^ Tinv3[_c1 >> 24] ^ KW[r * 4 + 0]; + r1 = Tinv0[_c1 & 255] ^ Tinv1[(_c0 >> 8) & 255] ^ Tinv2[(_c3 >> 16) & 255] ^ Tinv3[_c2 >> 24] ^ KW[r * 4 + 1]; + r2 = Tinv0[_c2 & 255] ^ Tinv1[(_c1 >> 8) & 255] ^ Tinv2[(_c0 >> 16) & 255] ^ Tinv3[_c3 >> 24] ^ KW[r * 4 + 2]; + r3 = Tinv0[_c3 & 255] ^ Tinv1[(_c2 >> 8) & 255] ^ Tinv2[(_c1 >> 16) & 255] ^ Tinv3[_c0 >> 24] ^ KW[r * 4 + 3]; // the final round's table is a simple function of Si so we don't use a whole other four tables for it - C0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[r1 >> 24]) << 24) ^ KW[0 * 4 + 0]; - C1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[r2 >> 24]) << 24) ^ KW[0 * 4 + 1]; - C2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[r3 >> 24]) << 24) ^ KW[0 * 4 + 2]; - C3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[r0 >> 24]) << 24) ^ KW[0 * 4 + 3]; + _c0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[r1 >> 24]) << 24) ^ KW[0 * 4 + 0]; + _c1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[r2 >> 24]) << 24) ^ KW[0 * 4 + 1]; + _c2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[r3 >> 24]) << 24) ^ KW[0 * 4 + 2]; + _c3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[r0 >> 24]) << 24) ^ KW[0 * 4 + 3]; } } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs index 831b7f3cc..fc2174bf9 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs @@ -47,7 +47,9 @@ public Arc4Cipher(byte[] key, bool dischargeFirstBytes) // first encrypted packet MUST be encrypted using the 1537th byte of // keystream. if (dischargeFirstBytes) - Encrypt(new byte[1536]); + { + _ = Encrypt(new byte[1536]); + } } /// @@ -94,7 +96,7 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC public override byte[] Encrypt(byte[] input, int offset, int length) { var output = new byte[length]; - ProcessBytes(input, offset, length, output, 0); + _ = ProcessBytes(input, offset, length, output, 0); return output; } @@ -122,7 +124,7 @@ public override byte[] Decrypt(byte[] input) public override byte[] Decrypt(byte[] input, int offset, int length) { var output = new byte[length]; - ProcessBytes(input, offset, length, output, 0); + _ = ProcessBytes(input, offset, length, output, 0); return output; } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs index 2dfa7909e..f43940c5c 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs @@ -322,8 +322,10 @@ public BlowfishCipher(byte[] key, CipherMode mode, CipherPadding padding) { var keySize = key.Length * 8; - if (keySize < 1 || keySize > 448) + if (keySize is < 1 or > 448) + { throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize)); + } _s0 = new uint[SboxSk]; _s1 = new uint[SboxSk]; @@ -352,12 +354,12 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC throw new ArgumentException("inputCount"); } - uint xl = Pack.BigEndianToUInt32(inputBuffer, inputOffset); - uint xr = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4); + var xl = Pack.BigEndianToUInt32(inputBuffer, inputOffset); + var xr = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4); xl ^= _p[0]; - for (int i = 1; i < Rounds; i += 2) + for (var i = 1; i < Rounds; i += 2) { xr ^= F(xl) ^ _p[i]; xl ^= F(xr) ^ _p[i + 1]; @@ -385,7 +387,9 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputCount != BlockSize) + { throw new ArgumentException("inputCount"); + } var xl = Pack.BigEndianToUInt32(inputBuffer, inputOffset); var xr = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4); @@ -408,7 +412,7 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC private uint F(uint x) { - return (((_s0[x >> 24] + _s1[(x >> 16) & 0xff]) ^ _s2[(x >> 8) & 0xff]) + _s3[x & 0xff]); + return ((_s0[x >> 24] + _s1[(x >> 16) & 0xff]) ^ _s2[(x >> 8) & 0xff]) + _s3[x & 0xff]; } private void SetKey(byte[] key) diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs index e7577f39f..e2b0779e1 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs @@ -38,7 +38,9 @@ public CastCipher(byte[] key, CipherMode mode, CipherPadding padding) var keySize = key.Length * 8; if (!(keySize >= 40 && keySize <= 128 && keySize % 8 == 0)) + { throw new ArgumentException(string.Format("KeySize '{0}' is not valid for this algorithm.", keySize)); + } SetKey(key); } @@ -625,6 +627,7 @@ private void CastEncipher(uint l0, uint r0, uint[] result) var rp = ri; // equivalent to R[i-1] li = rp; + switch (i) { case 1: @@ -649,6 +652,9 @@ private void CastEncipher(uint l0, uint r0, uint[] result) case 15: ri = lp ^ F3(rp, _km[i], _kr[i]); break; + default: + // We should never get here as max. rounds is 16 + break; } } @@ -666,6 +672,7 @@ private void CastDecipher(uint l16, uint r16, uint[] result) var rp = ri; // equivalent to R[i-1] li = rp; + switch (i) { case 1: @@ -690,6 +697,9 @@ private void CastDecipher(uint l16, uint r16, uint[] result) case 15: ri = lp ^ F3(rp, _km[i], _kr[i]); break; + default: + // We should never get here as max. rounds is 16 + break; } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CtrCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CtrCipherMode.cs index 47146567b..90149f575 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CtrCipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CtrCipherMode.cs @@ -56,7 +56,10 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC } var j = IV.Length; - while (--j >= 0 && ++IV[j] == 0) ; + while (--j >= 0 && ++IV[j] == 0) + { + // Intentionally empty block + } return _blockSize; } @@ -97,7 +100,10 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC } var j = IV.Length; - while (--j >= 0 && ++IV[j] == 0) ; + while (--j >= 0 && ++IV[j] == 0) + { + // Intentionally empty block + } return _blockSize; } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs index 0bfce1aad..d3644ba3b 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs @@ -18,7 +18,7 @@ public class RsaCipher : AsymmetricCipher /// The RSA key. public RsaCipher(RsaKey key) { - if (key == null) + if (key is null) { throw new ArgumentNullException(nameof(key)); } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs index f83ed24d0..3d52e2a26 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs @@ -40,12 +40,16 @@ public TripleDesCipher(byte[] key, CipherMode mode, CipherPadding padding) public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if ((inputOffset + BlockSize) > inputBuffer.Length) + { throw new IndexOutOfRangeException("input buffer too short"); + } if ((outputOffset + BlockSize) > outputBuffer.Length) + { throw new IndexOutOfRangeException("output buffer too short"); + } - if (_encryptionKey1 == null || _encryptionKey2 == null || _encryptionKey3 == null) + if (_encryptionKey1 is null || _encryptionKey2 is null || _encryptionKey3 is null) { var part1 = new byte[8]; var part2 = new byte[8]; @@ -102,7 +106,7 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC throw new IndexOutOfRangeException("output buffer too short"); } - if (_decryptionKey1 == null || _decryptionKey2 == null || _decryptionKey3 == null) + if (_decryptionKey1 is null || _decryptionKey2 is null || _decryptionKey3 is null) { var part1 = new byte[8]; var part2 = new byte[8]; diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs index ac33dce9c..1a4bf2cc5 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs @@ -42,13 +42,13 @@ public TwofishCipher(byte[] key, CipherMode mode, CipherPadding padding) mX[1] = Mx_X(j) & 0xff; mY[1] = Mx_Y(j) & 0xff; - gMDS0[i] = m1[P_00] | mX[P_00] << 8 | mY[P_00] << 16 | mY[P_00] << 24; + _gMDS0[i] = m1[P_00] | mX[P_00] << 8 | mY[P_00] << 16 | mY[P_00] << 24; - gMDS1[i] = mY[P_10] | mY[P_10] << 8 | mX[P_10] << 16 | m1[P_10] << 24; + _gMDS1[i] = mY[P_10] | mY[P_10] << 8 | mX[P_10] << 16 | m1[P_10] << 24; - gMDS2[i] = mX[P_20] | mY[P_20] << 8 | m1[P_20] << 16 | mY[P_20] << 24; + _gMDS2[i] = mX[P_20] | mY[P_20] << 8 | m1[P_20] << 16 | mY[P_20] << 24; - gMDS3[i] = mX[P_30] | m1[P_30] << 8 | mY[P_30] << 16 | mX[P_30] << 24; + _gMDS3[i] = mX[P_30] | m1[P_30] << 8 | mY[P_30] << 16 | mX[P_30] << 24; } _k64Cnt = key.Length / 8; // pre-padded ? @@ -68,31 +68,31 @@ public TwofishCipher(byte[] key, CipherMode mode, CipherPadding padding) /// public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - var x0 = BytesTo32Bits(inputBuffer, inputOffset) ^ gSubKeys[INPUT_WHITEN]; - var x1 = BytesTo32Bits(inputBuffer, inputOffset + 4) ^ gSubKeys[INPUT_WHITEN + 1]; - var x2 = BytesTo32Bits(inputBuffer, inputOffset + 8) ^ gSubKeys[INPUT_WHITEN + 2]; - var x3 = BytesTo32Bits(inputBuffer, inputOffset + 12) ^ gSubKeys[INPUT_WHITEN + 3]; + var x0 = BytesTo32Bits(inputBuffer, inputOffset) ^ _gSubKeys[INPUT_WHITEN]; + var x1 = BytesTo32Bits(inputBuffer, inputOffset + 4) ^ _gSubKeys[INPUT_WHITEN + 1]; + var x2 = BytesTo32Bits(inputBuffer, inputOffset + 8) ^ _gSubKeys[INPUT_WHITEN + 2]; + var x3 = BytesTo32Bits(inputBuffer, inputOffset + 12) ^ _gSubKeys[INPUT_WHITEN + 3]; var k = ROUND_SUBKEYS; for (var r = 0; r < ROUNDS; r += 2) { - var t0 = Fe32_0(gSBox, x0); - var t1 = Fe32_3(gSBox, x1); - x2 ^= t0 + t1 + gSubKeys[k++]; + var t0 = Fe32_0(_gSBox, x0); + var t1 = Fe32_3(_gSBox, x1); + x2 ^= t0 + t1 + _gSubKeys[k++]; x2 = (int)((uint)x2 >> 1) | x2 << 31; - x3 = (x3 << 1 | (int)((uint)x3 >> 31)) ^ (t0 + 2 * t1 + gSubKeys[k++]); + x3 = (x3 << 1 | (int)((uint)x3 >> 31)) ^ (t0 + 2 * t1 + _gSubKeys[k++]); - t0 = Fe32_0(gSBox, x2); - t1 = Fe32_3(gSBox, x3); - x0 ^= t0 + t1 + gSubKeys[k++]; + t0 = Fe32_0(_gSBox, x2); + t1 = Fe32_3(_gSBox, x3); + x0 ^= t0 + t1 + _gSubKeys[k++]; x0 = (int)((uint)x0 >> 1) | x0 << 31; - x1 = (x1 << 1 | (int)((uint)x1 >> 31)) ^ (t0 + 2 * t1 + gSubKeys[k++]); + x1 = (x1 << 1 | (int)((uint)x1 >> 31)) ^ (t0 + 2 * t1 + _gSubKeys[k++]); } - Bits32ToBytes(x2 ^ gSubKeys[OUTPUT_WHITEN], outputBuffer, outputOffset); - Bits32ToBytes(x3 ^ gSubKeys[OUTPUT_WHITEN + 1], outputBuffer, outputOffset + 4); - Bits32ToBytes(x0 ^ gSubKeys[OUTPUT_WHITEN + 2], outputBuffer, outputOffset + 8); - Bits32ToBytes(x1 ^ gSubKeys[OUTPUT_WHITEN + 3], outputBuffer, outputOffset + 12); + Bits32ToBytes(x2 ^ _gSubKeys[OUTPUT_WHITEN], outputBuffer, outputOffset); + Bits32ToBytes(x3 ^ _gSubKeys[OUTPUT_WHITEN + 1], outputBuffer, outputOffset + 4); + Bits32ToBytes(x0 ^ _gSubKeys[OUTPUT_WHITEN + 2], outputBuffer, outputOffset + 8); + Bits32ToBytes(x1 ^ _gSubKeys[OUTPUT_WHITEN + 3], outputBuffer, outputOffset + 12); return BlockSize; } @@ -110,31 +110,31 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC /// public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - var x2 = BytesTo32Bits(inputBuffer, inputOffset) ^ gSubKeys[OUTPUT_WHITEN]; - var x3 = BytesTo32Bits(inputBuffer, inputOffset + 4) ^ gSubKeys[OUTPUT_WHITEN + 1]; - var x0 = BytesTo32Bits(inputBuffer, inputOffset + 8) ^ gSubKeys[OUTPUT_WHITEN + 2]; - var x1 = BytesTo32Bits(inputBuffer, inputOffset + 12) ^ gSubKeys[OUTPUT_WHITEN + 3]; + var x2 = BytesTo32Bits(inputBuffer, inputOffset) ^ _gSubKeys[OUTPUT_WHITEN]; + var x3 = BytesTo32Bits(inputBuffer, inputOffset + 4) ^ _gSubKeys[OUTPUT_WHITEN + 1]; + var x0 = BytesTo32Bits(inputBuffer, inputOffset + 8) ^ _gSubKeys[OUTPUT_WHITEN + 2]; + var x1 = BytesTo32Bits(inputBuffer, inputOffset + 12) ^ _gSubKeys[OUTPUT_WHITEN + 3]; var k = ROUND_SUBKEYS + 2 * ROUNDS - 1; for (var r = 0; r < ROUNDS; r += 2) { - var t0 = Fe32_0(gSBox, x2); - var t1 = Fe32_3(gSBox, x3); - x1 ^= t0 + 2 * t1 + gSubKeys[k--]; - x0 = (x0 << 1 | (int)((uint)x0 >> 31)) ^ (t0 + t1 + gSubKeys[k--]); + var t0 = Fe32_0(_gSBox, x2); + var t1 = Fe32_3(_gSBox, x3); + x1 ^= t0 + 2 * t1 + _gSubKeys[k--]; + x0 = (x0 << 1 | (int)((uint)x0 >> 31)) ^ (t0 + t1 + _gSubKeys[k--]); x1 = (int)((uint)x1 >> 1) | x1 << 31; - t0 = Fe32_0(gSBox, x0); - t1 = Fe32_3(gSBox, x1); - x3 ^= t0 + 2 * t1 + gSubKeys[k--]; - x2 = (x2 << 1 | (int)((uint)x2 >> 31)) ^ (t0 + t1 + gSubKeys[k--]); + t0 = Fe32_0(_gSBox, x0); + t1 = Fe32_3(_gSBox, x1); + x3 ^= t0 + 2 * t1 + _gSubKeys[k--]; + x2 = (x2 << 1 | (int)((uint)x2 >> 31)) ^ (t0 + t1 + _gSubKeys[k--]); x3 = (int)((uint)x3 >> 1) | x3 << 31; } - Bits32ToBytes(x0 ^ gSubKeys[INPUT_WHITEN], outputBuffer, outputOffset); - Bits32ToBytes(x1 ^ gSubKeys[INPUT_WHITEN + 1], outputBuffer, outputOffset + 4); - Bits32ToBytes(x2 ^ gSubKeys[INPUT_WHITEN + 2], outputBuffer, outputOffset + 8); - Bits32ToBytes(x3 ^ gSubKeys[INPUT_WHITEN + 3], outputBuffer, outputOffset + 12); + Bits32ToBytes(x0 ^ _gSubKeys[INPUT_WHITEN], outputBuffer, outputOffset); + Bits32ToBytes(x1 ^ _gSubKeys[INPUT_WHITEN + 1], outputBuffer, outputOffset + 4); + Bits32ToBytes(x2 ^ _gSubKeys[INPUT_WHITEN + 2], outputBuffer, outputOffset + 8); + Bits32ToBytes(x3 ^ _gSubKeys[INPUT_WHITEN + 3], outputBuffer, outputOffset + 12); return BlockSize; } @@ -228,19 +228,19 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC private const int SK_BUMP = 0x01010101; private const int SK_ROTL = 9; - private readonly int[] gMDS0 = new int[MAX_KEY_BITS]; - private readonly int[] gMDS1 = new int[MAX_KEY_BITS]; - private readonly int[] gMDS2 = new int[MAX_KEY_BITS]; - private readonly int[] gMDS3 = new int[MAX_KEY_BITS]; + private readonly int[] _gMDS0 = new int[MAX_KEY_BITS]; + private readonly int[] _gMDS1 = new int[MAX_KEY_BITS]; + private readonly int[] _gMDS2 = new int[MAX_KEY_BITS]; + private readonly int[] _gMDS3 = new int[MAX_KEY_BITS]; private readonly int _k64Cnt; /** - * gSubKeys[] and gSBox[] are eventually used in the + * _gSubKeys[] and _gSBox[] are eventually used in the * encryption and decryption methods. */ - private int[] gSubKeys; - private int[] gSBox; + private int[] _gSubKeys; + private int[] _gSBox; private void SetKey(byte[] key) { @@ -248,7 +248,7 @@ private void SetKey(byte[] key) var k32o = new int[MAX_KEY_BITS / 64]; // 4 var sBoxKeys = new int[MAX_KEY_BITS / 64]; // 4 - gSubKeys = new int[TOTAL_SUBKEYS]; + _gSubKeys = new int[TOTAL_SUBKEYS]; if (_k64Cnt < 1) { @@ -283,9 +283,9 @@ private void SetKey(byte[] key) var b = F32(q + SK_BUMP, k32o); b = b << 8 | (int)((uint)b >> 24); a += b; - gSubKeys[i * 2] = a; + _gSubKeys[i * 2] = a; a += b; - gSubKeys[i * 2 + 1] = a << SK_ROTL | (int)((uint)a >> (32 - SK_ROTL)); + _gSubKeys[i * 2 + 1] = a << SK_ROTL | (int)((uint)a >> (32 - SK_ROTL)); } /* @@ -295,18 +295,20 @@ private void SetKey(byte[] key) var k1 = sBoxKeys[1]; var k2 = sBoxKeys[2]; var k3 = sBoxKeys[3]; - gSBox = new int[4 * MAX_KEY_BITS]; + _gSBox = new int[4 * MAX_KEY_BITS]; for (var i = 0; i < MAX_KEY_BITS; i++) { int b1, b2, b3; var b0 = b1 = b2 = b3 = i; + +#pragma warning disable IDE0010 // Add missing cases switch (_k64Cnt & 3) { case 1: - gSBox[i * 2] = gMDS0[(P[P_01 * 256 + b0] & 0xff) ^ M_b0(k0)]; - gSBox[i * 2 + 1] = gMDS1[(P[P_11 * 256 + b1] & 0xff) ^ M_b1(k0)]; - gSBox[i * 2 + 0x200] = gMDS2[(P[P_21 * 256 + b2] & 0xff) ^ M_b2(k0)]; - gSBox[i * 2 + 0x201] = gMDS3[(P[P_31 * 256 + b3] & 0xff) ^ M_b3(k0)]; + _gSBox[i * 2] = _gMDS0[(P[P_01 * 256 + b0] & 0xff) ^ M_b0(k0)]; + _gSBox[i * 2 + 1] = _gMDS1[(P[P_11 * 256 + b1] & 0xff) ^ M_b1(k0)]; + _gSBox[i * 2 + 0x200] = _gMDS2[(P[P_21 * 256 + b2] & 0xff) ^ M_b2(k0)]; + _gSBox[i * 2 + 0x201] = _gMDS3[(P[P_31 * 256 + b3] & 0xff) ^ M_b3(k0)]; break; case 0: /* 256 bits of key */ b0 = (P[P_04 * 256 + b0] & 0xff) ^ M_b0(k3); @@ -321,12 +323,13 @@ private void SetKey(byte[] key) b3 = (P[P_33 * 256 + b3] & 0xff) ^ M_b3(k2); goto case 2; case 2: - gSBox[i * 2] = gMDS0[(P[P_01 * 256 + (P[P_02 * 256 + b0] & 0xff) ^ M_b0(k1)] & 0xff) ^ M_b0(k0)]; - gSBox[i * 2 + 1] = gMDS1[(P[P_11 * 256 + (P[P_12 * 256 + b1] & 0xff) ^ M_b1(k1)] & 0xff) ^ M_b1(k0)]; - gSBox[i * 2 + 0x200] = gMDS2[(P[P_21 * 256 + (P[P_22 * 256 + b2] & 0xff) ^ M_b2(k1)] & 0xff) ^ M_b2(k0)]; - gSBox[i * 2 + 0x201] = gMDS3[(P[P_31 * 256 + (P[P_32 * 256 + b3] & 0xff) ^ M_b3(k1)] & 0xff) ^ M_b3(k0)]; + _gSBox[i * 2] = _gMDS0[(P[P_01 * 256 + (P[P_02 * 256 + b0] & 0xff) ^ M_b0(k1)] & 0xff) ^ M_b0(k0)]; + _gSBox[i * 2 + 1] = _gMDS1[(P[P_11 * 256 + (P[P_12 * 256 + b1] & 0xff) ^ M_b1(k1)] & 0xff) ^ M_b1(k0)]; + _gSBox[i * 2 + 0x200] = _gMDS2[(P[P_21 * 256 + (P[P_22 * 256 + b2] & 0xff) ^ M_b2(k1)] & 0xff) ^ M_b2(k0)]; + _gSBox[i * 2 + 0x201] = _gMDS3[(P[P_31 * 256 + (P[P_32 * 256 + b3] & 0xff) ^ M_b3(k1)] & 0xff) ^ M_b3(k0)]; break; } +#pragma warning restore IDE0010 // Add missing cases } /* @@ -352,13 +355,15 @@ private int F32(int x, int[] k32) var k3 = k32[3]; var result = 0; + +#pragma warning disable IDE0010 // Add missing cases switch (_k64Cnt & 3) { case 1: - result = gMDS0[(P[P_01 * 256 + b0] & 0xff) ^ M_b0(k0)] ^ - gMDS1[(P[P_11 * 256 + b1] & 0xff) ^ M_b1(k0)] ^ - gMDS2[(P[P_21 * 256 + b2] & 0xff) ^ M_b2(k0)] ^ - gMDS3[(P[P_31 * 256 + b3] & 0xff) ^ M_b3(k0)]; + result = _gMDS0[(P[P_01 * 256 + b0] & 0xff) ^ M_b0(k0)] ^ + _gMDS1[(P[P_11 * 256 + b1] & 0xff) ^ M_b1(k0)] ^ + _gMDS2[(P[P_21 * 256 + b2] & 0xff) ^ M_b2(k0)] ^ + _gMDS3[(P[P_31 * 256 + b3] & 0xff) ^ M_b3(k0)]; break; case 0: /* 256 bits of key */ b0 = (P[P_04 * 256 + b0] & 0xff) ^ M_b0(k3); @@ -374,12 +379,13 @@ private int F32(int x, int[] k32) goto case 2; case 2: result = - gMDS0[(P[P_01 * 256 + (P[P_02 * 256 + b0] & 0xff) ^ M_b0(k1)] & 0xff) ^ M_b0(k0)] ^ - gMDS1[(P[P_11 * 256 + (P[P_12 * 256 + b1] & 0xff) ^ M_b1(k1)] & 0xff) ^ M_b1(k0)] ^ - gMDS2[(P[P_21 * 256 + (P[P_22 * 256 + b2] & 0xff) ^ M_b2(k1)] & 0xff) ^ M_b2(k0)] ^ - gMDS3[(P[P_31 * 256 + (P[P_32 * 256 + b3] & 0xff) ^ M_b3(k1)] & 0xff) ^ M_b3(k0)]; + _gMDS0[(P[P_01 * 256 + (P[P_02 * 256 + b0] & 0xff) ^ M_b0(k1)] & 0xff) ^ M_b0(k0)] ^ + _gMDS1[(P[P_11 * 256 + (P[P_12 * 256 + b1] & 0xff) ^ M_b1(k1)] & 0xff) ^ M_b1(k0)] ^ + _gMDS2[(P[P_21 * 256 + (P[P_22 * 256 + b2] & 0xff) ^ M_b2(k1)] & 0xff) ^ M_b2(k0)] ^ + _gMDS3[(P[P_31 * 256 + (P[P_32 * 256 + b3] & 0xff) ^ M_b3(k1)] & 0xff) ^ M_b3(k0)]; break; } +#pragma warning restore IDE0010 // Add missing cases return result; } @@ -423,24 +429,19 @@ private static int RS_MDS_Encode(int k0, int k1) private static int RS_rem(int x) { var b = (int)(((uint)x >> 24) & 0xff); - var g2 = ((b << 1) ^ - ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff; - var g3 = ((int)((uint)b >> 1) ^ - ((b & 0x01) != 0 ? (int)((uint)RS_GF_FDBK >> 1) : 0)) ^ g2; + var g2 = ((b << 1) ^ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff; + var g3 = ((int)((uint)b >> 1) ^ ((b & 0x01) != 0 ? (int)((uint)RS_GF_FDBK >> 1) : 0)) ^ g2; return (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b; } private static int LFSR1(int x) { - return (x >> 1) ^ - (((x & 0x01) != 0) ? GF256_FDBK_2 : 0); + return (x >> 1) ^ (((x & 0x01) != 0) ? GF256_FDBK_2 : 0); } private static int LFSR2(int x) { - return (x >> 2) ^ - (((x & 0x02) != 0) ? GF256_FDBK_2 : 0) ^ - (((x & 0x01) != 0) ? GF256_FDBK_4 : 0); + return (x >> 2) ^ (((x & 0x02) != 0) ? GF256_FDBK_2 : 0) ^ (((x & 0x01) != 0) ? GF256_FDBK_4 : 0); } private static int Mx_X(int x) @@ -453,22 +454,30 @@ private static int Mx_Y(int x) return x ^ LFSR1(x) ^ LFSR2(x); } // EF +#pragma warning disable IDE1006 // Naming Styles private static int M_b0(int x) +#pragma warning restore IDE1006 // Naming Styles { return x & 0xff; } +#pragma warning disable IDE1006 // Naming Styles private static int M_b1(int x) +#pragma warning restore IDE1006 // Naming Styles { return (int)((uint)x >> 8) & 0xff; } +#pragma warning disable IDE1006 // Naming Styles private static int M_b2(int x) +#pragma warning restore IDE1006 // Naming Styles { return (int)((uint)x >> 16) & 0xff; } +#pragma warning disable IDE1006 // Naming Styles private static int M_b3(int x) +#pragma warning restore IDE1006 // Naming Styles { return (int)((uint)x >> 24) & 0xff; } diff --git a/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs index be84f7f83..467a5e0a7 100644 --- a/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs @@ -22,7 +22,7 @@ public class DsaDigitalSignature : DigitalSignature, IDisposable /// is null. public DsaDigitalSignature(DsaKey key) { - if (key == null) + if (key is null) { throw new ArgumentNullException(nameof(key)); } diff --git a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs index bfb185a65..d9664bdd9 100644 --- a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs @@ -147,12 +147,7 @@ public DsaKey(byte[] data) /// The x. public DsaKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y, BigInteger x) { - _privateKey = new BigInteger[5]; - _privateKey[0] = p; - _privateKey[1] = q; - _privateKey[2] = g; - _privateKey[3] = y; - _privateKey[4] = x; + _privateKey = new BigInteger[5] { p, q, g, y, x }; } /// diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs index 4e32772e2..c777f4d48 100644 --- a/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs @@ -19,7 +19,7 @@ public class ED25519DigitalSignature : DigitalSignature, IDisposable /// is null. public ED25519DigitalSignature(ED25519Key key) { - if (key == null) + if (key is null) { throw new ArgumentNullException(nameof(key)); } diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs index 8e0862f4d..99892fa59 100644 --- a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs @@ -13,8 +13,10 @@ public class ED25519Key : Key, IDisposable { private ED25519DigitalSignature _digitalSignature; - private byte[] publicKey = new byte[Ed25519.PublicKeySizeInBytes]; + private byte[] _publicKey = new byte[Ed25519.PublicKeySizeInBytes]; +#pragma warning disable IDE1006 // Naming Styles private readonly byte[] privateKey = new byte[Ed25519.ExpandedPrivateKeySizeInBytes]; +#pragma warning restore IDE1006 // Naming Styles private bool _isDisposed; /// @@ -35,11 +37,11 @@ public override BigInteger[] Public { get { - return new BigInteger[] { publicKey.ToBigInteger2() }; + return new BigInteger[] { _publicKey.ToBigInteger2() }; } set { - publicKey = value[0].ToByteArray().Reverse().TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + _publicKey = value[0].ToByteArray().Reverse().TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); } } @@ -76,7 +78,7 @@ public byte[] PublicKey { get { - return publicKey; + return _publicKey; } } @@ -104,7 +106,7 @@ public ED25519Key() /// pk data. public ED25519Key(byte[] pk) { - publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + _publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); } /// @@ -114,10 +116,10 @@ public ED25519Key(byte[] pk) /// sk data. public ED25519Key(byte[] pk, byte[] sk) { - publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + _publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); var seed = new byte[Ed25519.PrivateKeySeedSizeInBytes]; Buffer.BlockCopy(sk, 0, seed, 0, seed.Length); - Ed25519.KeyPairFromSeed(out publicKey, out privateKey, seed); + Ed25519.KeyPairFromSeed(out _publicKey, out privateKey, seed); } /// diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs index e358c1ecf..48446c52d 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs @@ -23,7 +23,7 @@ public class EcdsaDigitalSignature : DigitalSignature, IDisposable /// is null. public EcdsaDigitalSignature(EcdsaKey key) { - if (key == null) + if (key is null) { throw new ArgumentNullException(nameof(key)); } diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs index 0a5da1963..3de4beac5 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -26,6 +26,8 @@ public class EcdsaKey : Key, IDisposable private bool _isDisposed; #if NETFRAMEWORK + private CngKey _key; + internal enum KeyBlobMagicNumber : int { BCRYPT_ECDSA_PUBLIC_P256_MAGIC = 0x31534345, @@ -52,8 +54,6 @@ internal struct BCRYPT_ECCKEY_BLOB internal KeyBlobMagicNumber Magic; internal int cbKey; } - - private CngKey key; #endif /// @@ -104,9 +104,9 @@ public HashAlgorithmName HashAlgorithm return HashAlgorithmName.SHA384; case 521: return HashAlgorithmName.SHA512; + default: + return HashAlgorithmName.SHA256; } - - return HashAlgorithmName.SHA256; } } #endif @@ -152,7 +152,7 @@ public override BigInteger[] Public byte[] qx; byte[] qy; #if NETFRAMEWORK - var blob = key.Export(CngKeyBlobFormat.EccPublicBlob); + var blob = _key.Export(CngKeyBlobFormat.EccPublicBlob); KeyBlobMagicNumber magic; using (var br = new BinaryReader(new MemoryStream(blob))) @@ -163,6 +163,7 @@ public override BigInteger[] Public qy = br.ReadBytes(cbKey); } +#pragma warning disable IDE0010 // Add missing cases switch (magic) { case KeyBlobMagicNumber.BCRYPT_ECDSA_PUBLIC_P256_MAGIC: @@ -177,6 +178,7 @@ public override BigInteger[] Public default: throw new SshException("Unexpected Curve Magic: " + magic); } +#pragma warning restore IDE0010 // Add missing cases #else var parameter = Ecdsa.ExportParameters(false); qx = parameter.Q.X; @@ -377,9 +379,9 @@ private void Import(string curve_oid, byte[] publickey, byte[] privatekey) bw.Write(privatekey); // d } } - key = CngKey.Import(blob, privatekey == null ? CngKeyBlobFormat.EccPublicBlob : CngKeyBlobFormat.EccPrivateBlob); + _key = CngKey.Import(blob, privatekey is null ? CngKeyBlobFormat.EccPublicBlob : CngKeyBlobFormat.EccPrivateBlob); - Ecdsa = new ECDsaCng(key); + Ecdsa = new ECDsaCng(_key); #else var curve = ECCurve.CreateFromValue(curve_oid); var parameter = new ECParameters diff --git a/src/Renci.SshNet/Security/Cryptography/Key.cs b/src/Renci.SshNet/Security/Cryptography/Key.cs index 6f5a6312b..e23673b1e 100644 --- a/src/Renci.SshNet/Security/Cryptography/Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/Key.cs @@ -48,7 +48,7 @@ public abstract class Key /// DER encoded private key data. protected Key(byte[] data) { - if (data == null) + if (data is null) { throw new ArgumentNullException(nameof(data)); } diff --git a/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs index 15ac6c056..25a375f6b 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs @@ -55,7 +55,9 @@ public void Dispose() protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs index b80e4302c..6d0180114 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs @@ -9,6 +9,7 @@ namespace Renci.SshNet.Security /// public class RsaKey : Key, IDisposable { + private bool _isDisposed; /// /// Gets the Key String. @@ -48,7 +49,10 @@ public BigInteger D get { if (_privateKey.Length > 2) + { return _privateKey[2]; + } + return BigInteger.Zero; } } @@ -61,7 +65,11 @@ public BigInteger P get { if (_privateKey.Length > 3) + { return _privateKey[3]; + } + + return BigInteger.Zero; } } @@ -74,7 +82,10 @@ public BigInteger Q get { if (_privateKey.Length > 4) + { return _privateKey[4]; + } + return BigInteger.Zero; } } @@ -87,7 +98,10 @@ public BigInteger DP get { if (_privateKey.Length > 5) + { return _privateKey[5]; + } + return BigInteger.Zero; } } @@ -100,7 +114,10 @@ public BigInteger DQ get { if (_privateKey.Length > 6) + { return _privateKey[6]; + } + return BigInteger.Zero; } } @@ -113,7 +130,10 @@ public BigInteger InverseQ get { if (_privateKey.Length > 7) + { return _privateKey[7]; + } + return BigInteger.Zero; } } @@ -140,10 +160,8 @@ protected override DigitalSignature DigitalSignature { get { - if (_digitalSignature == null) - { - _digitalSignature = new RsaDigitalSignature(this); - } + _digitalSignature ??= new RsaDigitalSignature(this); + return _digitalSignature; } } @@ -163,7 +181,9 @@ public override BigInteger[] Public set { if (value.Length != 2) + { throw new InvalidOperationException("Invalid private key."); + } _privateKey = new[] { value[1], value[0] }; } @@ -184,7 +204,9 @@ public RsaKey(byte[] data) : base(data) { if (_privateKey.Length != 8) + { throw new InvalidOperationException("Invalid private key."); + } } /// @@ -198,15 +220,17 @@ public RsaKey(byte[] data) /// The inverse Q. public RsaKey(BigInteger modulus, BigInteger exponent, BigInteger d, BigInteger p, BigInteger q, BigInteger inverseQ) { - _privateKey = new BigInteger[8]; - _privateKey[0] = modulus; - _privateKey[1] = exponent; - _privateKey[2] = d; - _privateKey[3] = p; - _privateKey[4] = q; - _privateKey[5] = PrimeExponent(d, p); - _privateKey[6] = PrimeExponent(d, q); - _privateKey[7] = inverseQ; + _privateKey = new BigInteger[8] + { + modulus, + exponent, + d, + p, + q, + PrimeExponent(d, p), + PrimeExponent(d, q), + inverseQ + }; } private static BigInteger PrimeExponent(BigInteger privateExponent, BigInteger prime) @@ -215,10 +239,6 @@ private static BigInteger PrimeExponent(BigInteger privateExponent, BigInteger p return privateExponent % pe; } - #region IDisposable Members - - private bool _isDisposed; - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// @@ -235,7 +255,9 @@ public void Dispose() protected virtual void Dispose(bool disposing) { if (_isDisposed) + { return; + } if (disposing) { @@ -258,7 +280,5 @@ protected virtual void Dispose(bool disposing) { Dispose(false); } - - #endregion } } diff --git a/src/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs b/src/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs index f4e35c375..667492501 100644 --- a/src/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/SymmetricCipher.cs @@ -19,7 +19,7 @@ public abstract class SymmetricCipher : Cipher /// is null. protected SymmetricCipher(byte[] key) { - if (key == null) + if (key is null) { throw new ArgumentNullException(nameof(key)); } diff --git a/src/Renci.SshNet/Security/KeyExchange.cs b/src/Renci.SshNet/Security/KeyExchange.cs index 92a61973f..194358271 100644 --- a/src/Renci.SshNet/Security/KeyExchange.cs +++ b/src/Renci.SshNet/Security/KeyExchange.cs @@ -49,10 +49,7 @@ public byte[] ExchangeHash { get { - if (_exchangeHash == null) - { - _exchangeHash = CalculateHash(); - } + _exchangeHash ??= CalculateHash(); return _exchangeHash; } @@ -262,7 +259,7 @@ public HashAlgorithm CreateClientHash() /// public Compressor CreateCompressor() { - if (_compressionType == null) + if (_compressionType is null) { return null; } @@ -282,7 +279,7 @@ public Compressor CreateCompressor() /// public Compressor CreateDecompressor() { - if (_decompressionType == null) + if (_decompressionType is null) { return null; } diff --git a/src/Renci.SshNet/ServiceFactory.cs b/src/Renci.SshNet/ServiceFactory.cs index 42e541f0b..210df0229 100644 --- a/src/Renci.SshNet/ServiceFactory.cs +++ b/src/Renci.SshNet/ServiceFactory.cs @@ -92,12 +92,12 @@ public PipeStream CreatePipeStream() /// No key exchange algorithms are supported by both client and server. public IKeyExchange CreateKeyExchange(IDictionary clientAlgorithms, string[] serverAlgorithms) { - if (clientAlgorithms == null) + if (clientAlgorithms is null) { throw new ArgumentNullException(nameof(clientAlgorithms)); } - if (serverAlgorithms == null) + if (serverAlgorithms is null) { throw new ArgumentNullException(nameof(serverAlgorithms)); } @@ -108,7 +108,7 @@ from s in serverAlgorithms where s == c.Key select c.Value).FirstOrDefault(); - if (keyExchangeAlgorithmType == null) + if (keyExchangeAlgorithmType is null) { throw new SshConnectionException("Failed to negotiate key exchange algorithm.", DisconnectReason.KeyExchangeFailed); } @@ -215,12 +215,12 @@ public IRemotePathTransformation CreateRemotePathDoubleQuoteTransformation() /// The value of is not supported. public IConnector CreateConnector(IConnectionInfo connectionInfo, ISocketFactory socketFactory) { - if (connectionInfo == null) + if (connectionInfo is null) { throw new ArgumentNullException(nameof(connectionInfo)); } - if (socketFactory == null) + if (socketFactory is null) { throw new ArgumentNullException(nameof(socketFactory)); } diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index 17dd51256..02013bd22 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -207,14 +207,11 @@ public SemaphoreLight SessionSemaphore { get { - if (_sessionSemaphore == null) + if (_sessionSemaphore is null) { lock (this) { - if (_sessionSemaphore == null) - { - _sessionSemaphore = new SemaphoreLight(ConnectionInfo.MaxSessions); - } + _sessionSemaphore ??= new SemaphoreLight(ConnectionInfo.MaxSessions); } } @@ -282,7 +279,7 @@ public bool IsConnected return false; } - if (_messageListenerCompleted == null || _messageListenerCompleted.WaitOne(0)) + if (_messageListenerCompleted is null || _messageListenerCompleted.WaitOne(0)) { return false; } @@ -309,24 +306,21 @@ public Message ClientInitMessage { get { - if (_clientInitMessage == null) - { - _clientInitMessage = new KeyExchangeInitMessage - { - KeyExchangeAlgorithms = ConnectionInfo.KeyExchangeAlgorithms.Keys.ToArray(), - ServerHostKeyAlgorithms = ConnectionInfo.HostKeyAlgorithms.Keys.ToArray(), - EncryptionAlgorithmsClientToServer = ConnectionInfo.Encryptions.Keys.ToArray(), - EncryptionAlgorithmsServerToClient = ConnectionInfo.Encryptions.Keys.ToArray(), - MacAlgorithmsClientToServer = ConnectionInfo.HmacAlgorithms.Keys.ToArray(), - MacAlgorithmsServerToClient = ConnectionInfo.HmacAlgorithms.Keys.ToArray(), - CompressionAlgorithmsClientToServer = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(), - CompressionAlgorithmsServerToClient = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(), - LanguagesClientToServer = new[] { string.Empty }, - LanguagesServerToClient = new[] { string.Empty }, - FirstKexPacketFollows = false, - Reserved = 0 - }; - } + _clientInitMessage ??= new KeyExchangeInitMessage + { + KeyExchangeAlgorithms = ConnectionInfo.KeyExchangeAlgorithms.Keys.ToArray(), + ServerHostKeyAlgorithms = ConnectionInfo.HostKeyAlgorithms.Keys.ToArray(), + EncryptionAlgorithmsClientToServer = ConnectionInfo.Encryptions.Keys.ToArray(), + EncryptionAlgorithmsServerToClient = ConnectionInfo.Encryptions.Keys.ToArray(), + MacAlgorithmsClientToServer = ConnectionInfo.HmacAlgorithms.Keys.ToArray(), + MacAlgorithmsServerToClient = ConnectionInfo.HmacAlgorithms.Keys.ToArray(), + CompressionAlgorithmsClientToServer = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(), + CompressionAlgorithmsServerToClient = ConnectionInfo.CompressionAlgorithms.Keys.ToArray(), + LanguagesClientToServer = new[] { string.Empty }, + LanguagesServerToClient = new[] { string.Empty }, + FirstKexPacketFollows = false, + Reserved = 0 + }; return _clientInitMessage; } @@ -547,17 +541,17 @@ public Message ClientInitMessage /// is null. internal Session(ConnectionInfo connectionInfo, IServiceFactory serviceFactory, ISocketFactory socketFactory) { - if (connectionInfo == null) + if (connectionInfo is null) { throw new ArgumentNullException(nameof(connectionInfo)); } - if (serviceFactory == null) + if (serviceFactory is null) { throw new ArgumentNullException(nameof(serviceFactory)); } - if (socketFactory == null) + if (socketFactory is null) { throw new ArgumentNullException(nameof(socketFactory)); } @@ -641,13 +635,13 @@ public void Connect() // Start incoming request listener // ToDo: Make message pump async, to not consume a thread for every session - ThreadAbstraction.ExecuteThreadLongRunning(() => MessageListener()); + ThreadAbstraction.ExecuteThreadLongRunning(MessageListener); // Wait for key exchange to be completed WaitOnHandle(_keyExchangeCompletedWaitHandle); // If sessionId is not set then its not connected - if (SessionId == null) + if (SessionId is null) { Disconnect(); return; @@ -753,13 +747,13 @@ public async Task ConnectAsync(CancellationToken cancellationToken) // Start incoming request listener // ToDo: Make message pump async, to not consume a thread for every session - ThreadAbstraction.ExecuteThreadLongRunning(() => MessageListener()); + ThreadAbstraction.ExecuteThreadLongRunning(MessageListener); // Wait for key exchange to be completed WaitOnHandle(_keyExchangeCompletedWaitHandle); // If sessionId is not set then its not connected - if (SessionId == null) + if (SessionId is null) { Disconnect(); return; @@ -934,7 +928,7 @@ WaitResult ISession.TryWait(WaitHandle waitHandle, TimeSpan timeout, out Excepti /// private WaitResult TryWait(WaitHandle waitHandle, TimeSpan timeout, out Exception exception) { - if (waitHandle == null) + if (waitHandle is null) { throw new ArgumentNullException(nameof(waitHandle)); } @@ -982,7 +976,7 @@ private WaitResult TryWait(WaitHandle waitHandle, TimeSpan timeout, out Exceptio /// A socket error was signaled while receiving messages from the server. internal void WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout) { - if (waitHandle == null) + if (waitHandle is null) { throw new ArgumentNullException(nameof(waitHandle)); } @@ -994,12 +988,16 @@ internal void WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout) waitHandle }; - switch (WaitHandle.WaitAny(waitHandles, timeout)) + var signaledElement = WaitHandle.WaitAny(waitHandles, timeout); + switch (signaledElement) { case 0: throw _exception; case 1: throw new SshConnectionException("Client not connected."); + case 2: + // Specified waithandle was signaled + break; case WaitHandle.WaitTimeout: // when the session is disconnecting, a timeout is likely when no // network connectivity is available; depending on the configured @@ -1013,6 +1011,8 @@ internal void WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout) } break; + default: + throw new SshException($"Unexpected element '{signaledElement.ToString(CultureInfo.InvariantCulture)}' signaled."); } } @@ -1038,7 +1038,7 @@ internal void SendMessage(Message message) DiagnosticAbstraction.Log(string.Format("[{0}] Sending message '{1}' to server: '{2}'.", ToHex(SessionId), message.GetType().Name, message)); - var paddingMultiplier = _clientCipher == null ? (byte) 8 : Math.Max((byte) 8, _serverCipher.MinimumSize); + var paddingMultiplier = _clientCipher is null ? (byte) 8 : Math.Max((byte) 8, _serverCipher.MinimumSize); var packetData = message.GetPacket(paddingMultiplier, _clientCompression); // take a write lock to ensure the outbound packet sequence number is incremented @@ -1070,7 +1070,7 @@ internal void SendMessage(Message message) } var packetLength = packetData.Length - packetDataOffset; - if (hash == null) + if (hash is null) { SendPacket(packetData, packetDataOffset, packetLength); } @@ -1174,7 +1174,7 @@ private Message ReceiveMessage(Socket socket) const int paddingLengthFieldLength = 1; // Determine the size of the first block, which is 8 or cipher block size (whichever is larger) bytes - var blockSize = _serverCipher == null ? (byte) 8 : Math.Max((byte) 8, _serverCipher.MinimumSize); + var blockSize = _serverCipher is null ? (byte) 8 : Math.Max((byte) 8, _serverCipher.MinimumSize); var serverMacLength = _serverMac != null ? _serverMac.HashSize/8 : 0; @@ -1708,7 +1708,7 @@ private static string ToHex(byte[] bytes, int offset) internal static string ToHex(byte[] bytes) { - if (bytes == null) + if (bytes is null) { return null; } @@ -1842,7 +1842,7 @@ private void MessageListener() { var socket = _socket; - if (socket == null || !socket.Connected) + if (socket is null || !socket.Connected) { break; } @@ -1867,7 +1867,7 @@ private void MessageListener() } var message = ReceiveMessage(socket); - if (message == null) + if (message is null) { // connection with SSH server was closed; // break out of the message loop diff --git a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/FStatVfsRequest.cs b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/FStatVfsRequest.cs index 06eeef1e2..49341e89a 100644 --- a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/FStatVfsRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/FStatVfsRequest.cs @@ -1,4 +1,5 @@ 锘縰sing System; + using Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Sftp.Requests diff --git a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/HardLinkRequest.cs b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/HardLinkRequest.cs index 963249d22..cd744f0e2 100644 --- a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/HardLinkRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/HardLinkRequest.cs @@ -1,4 +1,5 @@ 锘縰sing System; + using Renci.SshNet.Sftp.Responses; namespace Renci.SshNet.Sftp.Requests diff --git a/src/Renci.SshNet/Sftp/Requests/SftpMkDirRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpMkDirRequest.cs index 752e88c1d..126925b95 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpMkDirRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpMkDirRequest.cs @@ -28,10 +28,7 @@ private byte[] AttributesBytes { get { - if (_attributesBytes == null) - { - _attributesBytes = Attributes.GetBytes(); - } + _attributesBytes ??= Attributes.GetBytes(); return _attributesBytes; } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpRealPathRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpRealPathRequest.cs index 52e57bbe3..d19497f0b 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpRealPathRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpRealPathRequest.cs @@ -43,7 +43,7 @@ protected override int BufferCapacity public SftpRealPathRequest(uint protocolVersion, uint requestId, string path, Encoding encoding, Action nameAction, Action statusAction) : base(protocolVersion, requestId, statusAction) { - if (nameAction == null) + if (nameAction is null) { throw new ArgumentNullException(nameof(nameAction)); } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpSetStatRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpSetStatRequest.cs index 9f44a92a6..8731b9fc6 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpSetStatRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpSetStatRequest.cs @@ -28,10 +28,8 @@ private byte[] AttributesBytes { get { - if (_attributesBytes == null) - { - _attributesBytes = Attributes.GetBytes(); - } + _attributesBytes ??= Attributes.GetBytes(); + return _attributesBytes; } } diff --git a/src/Renci.SshNet/Sftp/SftpFile.cs b/src/Renci.SshNet/Sftp/SftpFile.cs index 07d1039e1..b5fe3af36 100644 --- a/src/Renci.SshNet/Sftp/SftpFile.cs +++ b/src/Renci.SshNet/Sftp/SftpFile.cs @@ -25,17 +25,17 @@ public sealed class SftpFile : ISftpFile /// or is null. internal SftpFile(ISftpSession sftpSession, string fullName, SftpFileAttributes attributes) { - if (sftpSession == null) + if (sftpSession is null) { throw new SshConnectionException("Client not connected."); } - if (attributes == null) + if (attributes is null) { throw new ArgumentNullException(nameof(attributes)); } - if (fullName == null) + if (fullName is null) { throw new ArgumentNullException(nameof(fullName)); } @@ -481,7 +481,7 @@ public void Delete() /// is null. public void MoveTo(string destFileName) { - if (destFileName == null) + if (destFileName is null) { throw new ArgumentNullException(nameof(destFileName)); } diff --git a/src/Renci.SshNet/Sftp/SftpFileAttributes.cs b/src/Renci.SshNet/Sftp/SftpFileAttributes.cs index 901d6ee5a..e0cea9dba 100644 --- a/src/Renci.SshNet/Sftp/SftpFileAttributes.cs +++ b/src/Renci.SshNet/Sftp/SftpFileAttributes.cs @@ -12,45 +12,28 @@ namespace Renci.SshNet.Sftp /// public class SftpFileAttributes { +#pragma warning disable IDE1006 // Naming Styles private const uint S_IFMT = 0xF000; // bitmask for the file type bitfields - private const uint S_IFSOCK = 0xC000; // socket - private const uint S_IFLNK = 0xA000; // symbolic link - private const uint S_IFREG = 0x8000; // regular file - private const uint S_IFBLK = 0x6000; // block device - private const uint S_IFDIR = 0x4000; // directory - private const uint S_IFCHR = 0x2000; // character device - private const uint S_IFIFO = 0x1000; // FIFO - private const uint S_ISUID = 0x0800; // set UID bit - private const uint S_ISGID = 0x0400; // set-group-ID bit (see below) - private const uint S_ISVTX = 0x0200; // sticky bit (see below) - private const uint S_IRUSR = 0x0100; // owner has read permission - private const uint S_IWUSR = 0x0080; // owner has write permission - private const uint S_IXUSR = 0x0040; // owner has execute permission - private const uint S_IRGRP = 0x0020; // group has read permission - private const uint S_IWGRP = 0x0010; // group has write permission - private const uint S_IXGRP = 0x0008; // group has execute permission - private const uint S_IROTH = 0x0004; // others have read permission - private const uint S_IWOTH = 0x0002; // others have write permission - private const uint S_IXOTH = 0x0001; // others have execute permission +#pragma warning restore IDE1006 // Naming Styles private readonly DateTime _originalLastAccessTimeUtc; private readonly DateTime _originalLastWriteTimeUtc; diff --git a/src/Renci.SshNet/Sftp/SftpFileReader.cs b/src/Renci.SshNet/Sftp/SftpFileReader.cs index a6a1f0898..ca8ed29d1 100644 --- a/src/Renci.SshNet/Sftp/SftpFileReader.cs +++ b/src/Renci.SshNet/Sftp/SftpFileReader.cs @@ -94,7 +94,7 @@ public byte[] Read() { // wait until either the next chunk is available, an exception has occurred or the current // instance is already disposed - while (!_queue.TryGetValue(_nextChunkIndex, out nextChunk) && _exception == null) + while (!_queue.TryGetValue(_nextChunkIndex, out nextChunk) && _exception is null) { _ =Monitor.Wait(_readLock); } @@ -281,7 +281,7 @@ private void StartReadAhead() { ThreadAbstraction.ExecuteThread(() => { - while (!_endOfFileReceived && _exception == null) + while (!_endOfFileReceived && _exception is null) { // check if we should continue with the read-ahead loop // note that the EOF and exception check are not included diff --git a/src/Renci.SshNet/Sftp/SftpFileStream.cs b/src/Renci.SshNet/Sftp/SftpFileStream.cs index e42cad978..26e22ee88 100644 --- a/src/Renci.SshNet/Sftp/SftpFileStream.cs +++ b/src/Renci.SshNet/Sftp/SftpFileStream.cs @@ -201,12 +201,12 @@ private SftpFileStream(ISftpSession session, string path, FileAccess access, int internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAccess access, int bufferSize) { - if (session == null) + if (session is null) { throw new SshConnectionException("Client not connected."); } - if (path == null) + if (path is null) { throw new ArgumentNullException(nameof(path)); } @@ -267,7 +267,7 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc break; case FileMode.Create: _handle = _session.RequestOpen(path, flags | Flags.Truncate, nullOnError: true); - if (_handle == null) + if (_handle is null) { flags |= Flags.CreateNew; } @@ -312,12 +312,12 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc internal static async Task OpenAsync(ISftpSession session, string path, FileMode mode, FileAccess access, int bufferSize, CancellationToken cancellationToken) { - if (session == null) + if (session is null) { throw new SshConnectionException("Client not connected."); } - if (path == null) + if (path is null) { throw new ArgumentNullException(nameof(path)); } @@ -501,7 +501,7 @@ public override int Read(byte[] buffer, int offset, int count) { var readLen = 0; - if (buffer == null) + if (buffer is null) { throw new ArgumentNullException(nameof(buffer)); } @@ -642,7 +642,7 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, { var readLen = 0; - if (buffer == null) + if (buffer is null) { throw new ArgumentNullException(nameof(buffer)); } @@ -987,7 +987,7 @@ public override void SetLength(long value) /// Methods were called after the stream was closed. public override void Write(byte[] buffer, int offset, int count) { - if (buffer == null) + if (buffer is null) { throw new ArgumentNullException(nameof(buffer)); } @@ -1086,7 +1086,7 @@ public override void Write(byte[] buffer, int offset, int count) /// Methods were called after the stream was closed. public override async Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { - if (buffer == null) + if (buffer is null) { throw new ArgumentNullException(nameof(buffer)); } @@ -1318,7 +1318,7 @@ private void SetupWrite() private void CheckSessionIsOpen() { - if (_session == null) + if (_session is null) { throw new ObjectDisposedException(GetType().FullName); } diff --git a/src/Renci.SshNet/Sftp/SftpResponseFactory.cs b/src/Renci.SshNet/Sftp/SftpResponseFactory.cs index 0edcfcf7c..1d5b4ad50 100644 --- a/src/Renci.SshNet/Sftp/SftpResponseFactory.cs +++ b/src/Renci.SshNet/Sftp/SftpResponseFactory.cs @@ -14,6 +14,7 @@ public SftpMessage Create(uint protocolVersion, byte messageType, Encoding encod SftpMessage message; +#pragma warning disable IDE0010 // Add missing cases switch (sftpMessageType) { case SftpMessageTypes.Version: @@ -40,6 +41,7 @@ public SftpMessage Create(uint protocolVersion, byte messageType, Encoding encod default: throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Message type '{0}' is not supported.", sftpMessageType)); } +#pragma warning restore IDE0010 // Add missing cases return message; } diff --git a/src/Renci.SshNet/Sftp/SftpSession.cs b/src/Renci.SshNet/Sftp/SftpSession.cs index 7bba929ed..c43a7af96 100644 --- a/src/Renci.SshNet/Sftp/SftpSession.cs +++ b/src/Renci.SshNet/Sftp/SftpSession.cs @@ -526,7 +526,7 @@ public SftpOpenAsyncResult BeginOpen(string path, Flags flags, AsyncCallback cal /// is null. public byte[] EndOpen(SftpOpenAsyncResult asyncResult) { - if (asyncResult == null) + if (asyncResult is null) { throw new ArgumentNullException(nameof(asyncResult)); } @@ -638,7 +638,7 @@ public SftpCloseAsyncResult BeginClose(byte[] handle, AsyncCallback callback, ob /// is null. public void EndClose(SftpCloseAsyncResult asyncResult) { - if (asyncResult == null) + if (asyncResult is null) { throw new ArgumentNullException(nameof(asyncResult)); } @@ -716,7 +716,7 @@ public SftpReadAsyncResult BeginRead(byte[] handle, ulong offset, uint length, A /// is null. public byte[] EndRead(SftpReadAsyncResult asyncResult) { - if (asyncResult == null) + if (asyncResult is null) { throw new ArgumentNullException(nameof(asyncResult)); } @@ -984,7 +984,7 @@ public SFtpStatAsyncResult BeginLStat(string path, AsyncCallback callback, objec /// is null. public SftpFileAttributes EndLStat(SFtpStatAsyncResult asyncResult) { - if (asyncResult == null) + if (asyncResult is null) { throw new ArgumentNullException(nameof(asyncResult)); } @@ -1492,7 +1492,7 @@ public SftpRealPathAsyncResult BeginRealPath(string path, AsyncCallback callback /// is null. public string EndRealPath(SftpRealPathAsyncResult asyncResult) { - if (asyncResult == null) + if (asyncResult is null) { throw new ArgumentNullException(nameof(asyncResult)); } @@ -1592,7 +1592,7 @@ public SFtpStatAsyncResult BeginStat(string path, AsyncCallback callback, object /// is null. public SftpFileAttributes EndStat(SFtpStatAsyncResult asyncResult) { - if (asyncResult == null) + if (asyncResult is null) { throw new ArgumentNullException(nameof(asyncResult)); } @@ -2044,6 +2044,7 @@ public uint CalculateOptimalWriteLength(uint bufferSize, byte[] handle) private static SshException GetSftpException(SftpStatusResponse response) { +#pragma warning disable IDE0010 // Add missing cases switch (response.StatusCode) { case StatusCodes.Ok: @@ -2055,6 +2056,7 @@ private static SshException GetSftpException(SftpStatusResponse response) default: return new SshException(response.ErrorMessage); } +#pragma warning restore IDE0010 // Add missing cases } private void HandleResponse(SftpResponse response) @@ -2069,7 +2071,7 @@ private void HandleResponse(SftpResponse response) } } - if (request == null) + if (request is null) { throw new InvalidOperationException("Invalid response."); } diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 937f4a1a0..8190df20c 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -3,7 +3,6 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Globalization; -using System.Linq; using System.Net; using System.Text; using System.Threading; @@ -45,7 +44,7 @@ public class SftpClient : BaseClient, ISftpClient /// one (-1) milliseconds, which indicates an infinite timeout period. /// /// The method was called after the client was disposed. - /// represents a value that is less than -1 or greater than milliseconds. + /// represents a value that is less than -1 or greater than milliseconds. public TimeSpan OperationTimeout { get @@ -59,8 +58,10 @@ public TimeSpan OperationTimeout CheckDisposed(); var timeoutInMilliseconds = value.TotalMilliseconds; - if (timeoutInMilliseconds < -1d || timeoutInMilliseconds > int.MaxValue) - throw new ArgumentOutOfRangeException("value", "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); + if (timeoutInMilliseconds is < -1d or > int.MaxValue) + { + throw new ArgumentOutOfRangeException(nameof(value), "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); + } _operationTimeout = (int) timeoutInMilliseconds; } @@ -121,8 +122,12 @@ public string WorkingDirectory get { CheckDisposed(); - if (_sftpSession == null) + + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } + return _sftpSession.WorkingDirectory; } } @@ -137,8 +142,12 @@ public int ProtocolVersion get { CheckDisposed(); - if (_sftpSession == null) + + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } + return (int) _sftpSession.ProtocolVersion; } } @@ -274,11 +283,15 @@ public void ChangeDirectory(string path) { CheckDisposed(); - if (path == null) - throw new ArgumentNullException("path"); + if (path is null) + { + throw new ArgumentNullException(nameof(path)); + } - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } _sftpSession.ChangeDirectory(path); } @@ -314,10 +327,14 @@ public void CreateDirectory(string path) CheckDisposed(); if (path.IsNullOrWhiteSpace()) + { throw new ArgumentException(path); + } - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var fullPath = _sftpSession.GetCanonicalPath(path); @@ -339,10 +356,14 @@ public void DeleteDirectory(string path) CheckDisposed(); if (path.IsNullOrWhiteSpace()) + { throw new ArgumentException("path"); + } - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var fullPath = _sftpSession.GetCanonicalPath(path); @@ -364,10 +385,14 @@ public void DeleteFile(string path) CheckDisposed(); if (path.IsNullOrWhiteSpace()) + { throw new ArgumentException("path"); + } - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var fullPath = _sftpSession.GetCanonicalPath(path); @@ -388,11 +413,18 @@ public void DeleteFile(string path) /// The method was called after the client was disposed. public async Task DeleteFileAsync(string path, CancellationToken cancellationToken) { - base.CheckDisposed(); + CheckDisposed(); + if (path.IsNullOrWhiteSpace()) + { throw new ArgumentException("path"); - if (_sftpSession == null) + } + + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } + cancellationToken.ThrowIfCancellationRequested(); var fullPath = await _sftpSession.GetCanonicalPathAsync(path, cancellationToken).ConfigureAwait(false); @@ -428,13 +460,23 @@ public void RenameFile(string oldPath, string newPath) /// The method was called after the client was disposed. public async Task RenameFileAsync(string oldPath, string newPath, CancellationToken cancellationToken) { - base.CheckDisposed(); - if (oldPath == null) + CheckDisposed(); + + if (oldPath is null) + { throw new ArgumentNullException("oldPath"); - if (newPath == null) + } + + if (newPath is null) + { throw new ArgumentNullException("newPath"); - if (_sftpSession == null) + } + + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } + cancellationToken.ThrowIfCancellationRequested(); var oldFullPath = await _sftpSession.GetCanonicalPathAsync(oldPath, cancellationToken).ConfigureAwait(false); @@ -457,14 +499,20 @@ public void RenameFile(string oldPath, string newPath, bool isPosix) { CheckDisposed(); - if (oldPath == null) + if (oldPath is null) + { throw new ArgumentNullException("oldPath"); + } - if (newPath == null) + if (newPath is null) + { throw new ArgumentNullException("newPath"); + } - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var oldFullPath = _sftpSession.GetCanonicalPath(oldPath); @@ -495,13 +543,19 @@ public void SymbolicLink(string path, string linkPath) CheckDisposed(); if (path.IsNullOrWhiteSpace()) + { throw new ArgumentException("path"); + } if (linkPath.IsNullOrWhiteSpace()) + { throw new ArgumentException("linkPath"); + } - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var fullPath = _sftpSession.GetCanonicalPath(path); @@ -546,11 +600,18 @@ public IEnumerable ListDirectory(string path, Action listCallbac /// The method was called after the client was disposed. public async Task> ListDirectoryAsync(string path, CancellationToken cancellationToken) { - base.CheckDisposed(); - if (path == null) + CheckDisposed(); + + if (path is null) + { throw new ArgumentNullException("path"); - if (_sftpSession == null) + } + + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } + cancellationToken.ThrowIfCancellationRequested(); var fullPath = await _sftpSession.GetCanonicalPathAsync(path, cancellationToken).ConfigureAwait(false); @@ -566,7 +627,7 @@ public async Task> ListDirectoryAsync(string path, Cancel while (true) { var files = await _sftpSession.RequestReadDirAsync(handle, cancellationToken).ConfigureAwait(false); - if (files == null) + if (files is null) { break; } @@ -611,10 +672,7 @@ public IAsyncResult BeginListDirectory(string path, AsyncCallback asyncCallback, { asyncResult.Update(count); - if (listCallback != null) - { - listCallback(count); - } + listCallback?.Invoke(count); }); asyncResult.SetAsCompleted(result, false); @@ -638,10 +696,10 @@ public IAsyncResult BeginListDirectory(string path, AsyncCallback asyncCallback, /// The object did not come from the corresponding async method on this type.-or- was called multiple times with the same . public IEnumerable EndListDirectory(IAsyncResult asyncResult) { - var ar = asyncResult as SftpListDirectoryAsyncResult; - - if (ar == null || ar.EndInvokeCalled) + if (asyncResult is not SftpListDirectoryAsyncResult ar || ar.EndInvokeCalled) + { throw new ArgumentException("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."); + } // Wait for operation to complete, then return result or throw exception return ar.EndInvoke(); @@ -662,11 +720,15 @@ public ISftpFile Get(string path) { CheckDisposed(); - if (path == null) + if (path is null) + { throw new ArgumentNullException("path"); + } - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var fullPath = _sftpSession.GetCanonicalPath(path); @@ -692,10 +754,14 @@ public bool Exists(string path) CheckDisposed(); if (path.IsNullOrWhiteSpace()) + { throw new ArgumentException("path"); + } - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var fullPath = _sftpSession.GetCanonicalPath(path); @@ -718,7 +784,7 @@ public bool Exists(string path) try { - _sftpSession.RequestLStat(fullPath); + _ = _sftpSession.RequestLStat(fullPath); return true; } catch (SftpPathNotFoundException) @@ -817,10 +883,14 @@ public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback CheckDisposed(); if (path.IsNullOrWhiteSpace()) + { throw new ArgumentException("path"); + } - if (output == null) + if (output is null) + { throw new ArgumentNullException("output"); + } var asyncResult = new SftpDownloadAsyncResult(asyncCallback, state); @@ -832,10 +902,7 @@ public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback { asyncResult.Update(offset); - if (downloadCallback != null) - { - downloadCallback(offset); - } + downloadCallback?.Invoke(offset); }); asyncResult.SetAsCompleted(null, false); @@ -860,10 +927,10 @@ public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback /// A SSH error where is the message from the remote host. public void EndDownloadFile(IAsyncResult asyncResult) { - var ar = asyncResult as SftpDownloadAsyncResult; - - if (ar == null || ar.EndInvokeCalled) + if (asyncResult is not SftpDownloadAsyncResult ar || ar.EndInvokeCalled) + { throw new ArgumentException("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."); + } // Wait for operation to complete, then return result or throw exception ar.EndInvoke(); @@ -912,9 +979,13 @@ public void UploadFile(Stream input, string path, bool canOverride, ActionA SSH error where is the message from the remote host. public void EndUploadFile(IAsyncResult asyncResult) { - var ar = asyncResult as SftpUploadAsyncResult; - - if (ar == null || ar.EndInvokeCalled) + if (asyncResult is not SftpUploadAsyncResult ar || ar.EndInvokeCalled) + { throw new ArgumentException("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."); + } // Wait for operation to complete, then return result or throw exception ar.EndInvoke(); @@ -1108,11 +1184,15 @@ public SftpFileSytemInformation GetStatus(string path) { CheckDisposed(); - if (path == null) + if (path is null) + { throw new ArgumentNullException("path"); + } - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var fullPath = _sftpSession.GetCanonicalPath(path); @@ -1133,11 +1213,18 @@ public SftpFileSytemInformation GetStatus(string path) /// The method was called after the client was disposed. public async Task GetStatusAsync(string path, CancellationToken cancellationToken) { - base.CheckDisposed(); - if (path == null) + CheckDisposed(); + + if (path is null) + { throw new ArgumentNullException("path"); - if (_sftpSession == null) + } + + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } + cancellationToken.ThrowIfCancellationRequested(); var fullPath = await _sftpSession.GetCanonicalPathAsync(path, cancellationToken).ConfigureAwait(false); @@ -1162,8 +1249,10 @@ public void AppendAllLines(string path, IEnumerable contents) { CheckDisposed(); - if (contents == null) + if (contents is null) + { throw new ArgumentNullException("contents"); + } using (var stream = AppendText(path)) { @@ -1188,8 +1277,10 @@ public void AppendAllLines(string path, IEnumerable contents, Encoding e { CheckDisposed(); - if (contents == null) + if (contents is null) + { throw new ArgumentNullException("contents"); + } using (var stream = AppendText(path, encoding)) { @@ -1273,8 +1364,10 @@ public StreamWriter AppendText(string path, Encoding encoding) { CheckDisposed(); - if (encoding == null) + if (encoding is null) + { throw new ArgumentNullException("encoding"); + } return new StreamWriter(new SftpFileStream(_sftpSession, path, FileMode.Append, FileAccess.Write, (int) _bufferSize), encoding); } @@ -1507,11 +1600,18 @@ public SftpFileStream Open(string path, FileMode mode, FileAccess access) /// The method was called after the client was disposed. public Task OpenAsync(string path, FileMode mode, FileAccess access, CancellationToken cancellationToken) { - base.CheckDisposed(); - if (path == null) + CheckDisposed(); + + if (path is null) + { throw new ArgumentNullException("path"); - if (_sftpSession == null) + } + + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } + cancellationToken.ThrowIfCancellationRequested(); return SftpFileStream.OpenAsync(_sftpSession, path, mode, access, (int)_bufferSize, cancellationToken); @@ -1582,7 +1682,7 @@ public byte[] ReadAllBytes(string path) using (var stream = OpenRead(path)) { var buffer = new byte[stream.Length]; - stream.Read(buffer, 0, buffer.Length); + _ = stream.Read(buffer, 0, buffer.Length); return buffer; } } @@ -1943,8 +2043,10 @@ public SftpFileAttributes GetAttributes(string path) { CheckDisposed(); - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var fullPath = _sftpSession.GetCanonicalPath(path); @@ -1963,8 +2065,10 @@ public void SetAttributes(string path, SftpFileAttributes fileAttributes) { CheckDisposed(); - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var fullPath = _sftpSession.GetCanonicalPath(path); @@ -1999,10 +2103,15 @@ public void SetAttributes(string path, SftpFileAttributes fileAttributes) /// If a problem occurs while copying the file public IEnumerable SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern) { - if (sourcePath == null) + if (sourcePath is null) + { throw new ArgumentNullException("sourcePath"); + } + if (destinationPath.IsNullOrWhiteSpace()) + { throw new ArgumentException("destinationPath"); + } return InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, null); } @@ -2023,10 +2132,15 @@ public IEnumerable SynchronizeDirectories(string sourcePath, string de /// If a problem occurs while copying the file public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback asyncCallback, object state) { - if (sourcePath == null) + if (sourcePath is null) + { throw new ArgumentNullException("sourcePath"); + } + if (destinationPath.IsNullOrWhiteSpace()) + { throw new ArgumentException("destDir"); + } var asyncResult = new SftpSynchronizeDirectoriesAsyncResult(asyncCallback, state); @@ -2058,10 +2172,10 @@ public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destin /// The destination path was not found on the remote host. public IEnumerable EndSynchronizeDirectories(IAsyncResult asyncResult) { - var ar = asyncResult as SftpSynchronizeDirectoriesAsyncResult; - - if (ar == null || ar.EndInvokeCalled) + if (asyncResult is not SftpSynchronizeDirectoriesAsyncResult ar || ar.EndInvokeCalled) + { throw new ArgumentException("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."); + } // Wait for operation to complete, then return result or throw exception return ar.EndInvoke(); @@ -2070,7 +2184,9 @@ public IEnumerable EndSynchronizeDirectories(IAsyncResult asyncResult) private IEnumerable InternalSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, SftpSynchronizeDirectoriesAsyncResult asynchResult) { if (!Directory.Exists(sourcePath)) + { throw new FileNotFoundException(string.Format("Source directory not found: {0}", sourcePath)); + } var uploadedFiles = new List(); @@ -2105,7 +2221,7 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, do { var localFile = sourceFiles.Current; - if (localFile == null) + if (localFile is null) { continue; } @@ -2130,10 +2246,7 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, uploadedFiles.Add(localFile); - if (asynchResult != null) - { - asynchResult.Update(uploadedFiles.Count); - } + asynchResult?.Update(uploadedFiles.Count); } catch (Exception ex) { @@ -2163,11 +2276,15 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, /// Client not connected. private IEnumerable InternalListDirectory(string path, Action listCallback) { - if (path == null) + if (path is null) + { throw new ArgumentNullException("path"); + } - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var fullPath = _sftpSession.GetCanonicalPath(path); @@ -2176,7 +2293,9 @@ private IEnumerable InternalListDirectory(string path, Action li var basePath = fullPath; if (!basePath.EndsWith("/")) + { basePath = string.Format("{0}/", fullPath); + } var result = new List(); @@ -2186,10 +2305,9 @@ private IEnumerable InternalListDirectory(string path, Action li { foreach (var f in files) { - result.Add(new SftpFile( - _sftpSession, - string.Format(CultureInfo.InvariantCulture, "{0}{1}", basePath, f.Key), - f.Value)); + result.Add(new SftpFile(_sftpSession, + string.Format(CultureInfo.InvariantCulture, "{0}{1}", basePath, f.Key), + f.Value)); } // Call callback to report number of files read @@ -2219,14 +2337,20 @@ private IEnumerable InternalListDirectory(string path, Action li /// Client not connected. private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncResult asyncResult, Action downloadCallback) { - if (output == null) + if (output is null) + { throw new ArgumentNullException("output"); + } if (path.IsNullOrWhiteSpace()) + { throw new ArgumentException("path"); + } - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var fullPath = _sftpSession.GetCanonicalPath(path); @@ -2238,11 +2362,15 @@ private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncR { // Cancel download if (asyncResult != null && asyncResult.IsDownloadCanceled) + { break; + } var data = fileReader.Read(); if (data.Length == 0) + { break; + } output.Write(data, 0, data.Length); @@ -2273,14 +2401,20 @@ private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncR /// Client not connected. private void InternalUploadFile(Stream input, string path, Flags flags, SftpUploadAsyncResult asyncResult, Action uploadCallback) { - if (input == null) + if (input is null) + { throw new ArgumentNullException("input"); + } if (path.IsNullOrWhiteSpace()) + { throw new ArgumentException("path"); + } - if (_sftpSession == null) + if (_sftpSession is null) + { throw new SshConnectionException("Client not connected."); + } var fullPath = _sftpSession.GetCanonicalPath(path); @@ -2299,7 +2433,9 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo { // Cancel upload if (asyncResult != null && asyncResult.IsUploadCanceled) + { break; + } if (bytesRead > 0) { @@ -2309,8 +2445,8 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo { if (s.StatusCode == StatusCodes.Ok) { - Interlocked.Decrement(ref expectedResponses); - responseReceivedWaitHandle.Set(); + _ = Interlocked.Decrement(ref expectedResponses); + _ = responseReceivedWaitHandle.Set(); // Call callback to report number of bytes written if (uploadCallback != null) @@ -2320,7 +2456,8 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo } } }); - Interlocked.Increment(ref expectedResponses); + + _ = Interlocked.Increment(ref expectedResponses); offset += (ulong) bytesRead; @@ -2331,7 +2468,8 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo // Wait for expectedResponses to change _sftpSession.WaitOnHandle(responseReceivedWaitHandle, _operationTimeout); } - } while (expectedResponses > 0 || bytesRead > 0); + } + while (expectedResponses > 0 || bytesRead > 0); _sftpSession.RequestClose(handle); } @@ -2400,4 +2538,4 @@ private ISftpSession CreateAndConnectToSftpSession() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Shell.cs b/src/Renci.SshNet/Shell.cs index 63ebcf7e7..892c530b4 100644 --- a/src/Renci.SshNet/Shell.cs +++ b/src/Renci.SshNet/Shell.cs @@ -236,7 +236,7 @@ private void Channel_Closed(object sender, ChannelEventArgs e) /// private void UnsubscribeFromSessionEvents(ISession session) { - if (session == null) + if (session is null) { return; } diff --git a/src/Renci.SshNet/ShellStream.cs b/src/Renci.SshNet/ShellStream.cs index 004b962a3..37c3ac4de 100644 --- a/src/Renci.SshNet/ShellStream.cs +++ b/src/Renci.SshNet/ShellStream.cs @@ -155,7 +155,7 @@ public override bool CanWrite /// Methods were called after the stream was closed. public override void Flush() { - if (_channel == null) + if (_channel is null) { throw new ObjectDisposedException("ShellStream"); } @@ -676,12 +676,12 @@ public string Read() /// public void Write(string text) { - if (text == null) + if (text is null) { return; } - if (_channel == null) + if (_channel is null) { throw new ObjectDisposedException("ShellStream"); } @@ -750,7 +750,7 @@ protected override void Dispose(bool disposing) /// private void UnsubscribeFromSessionEvents(ISession session) { - if (session == null) + if (session is null) { return; } @@ -766,10 +766,7 @@ private void Session_ErrorOccured(object sender, ExceptionEventArgs e) private void Session_Disconnected(object sender, EventArgs e) { - if (_channel != null) - { - _channel.Dispose(); - } + _channel?.Dispose(); } private void Channel_Closed(object sender, ChannelEventArgs e) diff --git a/src/Renci.SshNet/SshClient.cs b/src/Renci.SshNet/SshClient.cs index 26a3cb1b4..5ed7036c5 100644 --- a/src/Renci.SshNet/SshClient.cs +++ b/src/Renci.SshNet/SshClient.cs @@ -184,7 +184,7 @@ protected override void OnDisconnecting() /// Client is not connected. public void AddForwardedPort(ForwardedPort port) { - if (port == null) + if (port is null) { throw new ArgumentNullException(nameof(port)); } @@ -202,7 +202,7 @@ public void AddForwardedPort(ForwardedPort port) /// is null. public void RemoveForwardedPort(ForwardedPort port) { - if (port == null) + if (port is null) { throw new ArgumentNullException(nameof(port)); } @@ -509,7 +509,7 @@ protected override void Dispose(bool disposing) private void EnsureSessionIsOpen() { - if (Session == null) + if (Session is null) { throw new SshConnectionException("Client not connected."); } diff --git a/src/Renci.SshNet/SshCommand.cs b/src/Renci.SshNet/SshCommand.cs index 2fa78d4a5..30a6bfe54 100644 --- a/src/Renci.SshNet/SshCommand.cs +++ b/src/Renci.SshNet/SshCommand.cs @@ -131,17 +131,17 @@ public string Error /// Either , is null. internal SshCommand(ISession session, string commandText, Encoding encoding) { - if (session == null) + if (session is null) { throw new ArgumentNullException(nameof(session)); } - if (commandText == null) + if (commandText is null) { throw new ArgumentNullException(nameof(commandText)); } - if (encoding == null) + if (encoding is null) { throw new ArgumentNullException(nameof(encoding)); } @@ -291,7 +291,7 @@ public IAsyncResult BeginExecute(string commandText, AsyncCallback callback, obj /// is null. public string EndExecute(IAsyncResult asyncResult) { - if (asyncResult == null) + if (asyncResult is null) { throw new ArgumentNullException(nameof(asyncResult)); } @@ -479,12 +479,19 @@ private void WaitOnHandle(WaitHandle waitHandle) waitHandle }; - switch (WaitHandle.WaitAny(waitHandles, CommandTimeout)) + var signaledElement = WaitHandle.WaitAny(waitHandles, CommandTimeout); + switch (signaledElement) { case 0: throw _exception; + case 1: + // Specified waithandle was signaled + break; case WaitHandle.WaitTimeout: throw new SshOperationTimeoutException(string.Format(CultureInfo.CurrentCulture, "Command '{0}' has timed out.", CommandText)); + default: + throw new SshException($"Unexpected element '{signaledElement.ToString(CultureInfo.InvariantCulture)}' signaled."); + } } @@ -498,7 +505,7 @@ private void WaitOnHandle(WaitHandle waitHandle) /// private void UnsubscribeFromEventsAndDisposeChannel(IChannel channel) { - if (channel == null) + if (channel is null) { return; } diff --git a/src/Renci.SshNet/SshMessageFactory.cs b/src/Renci.SshNet/SshMessageFactory.cs index 61952f4b5..5941c120e 100644 --- a/src/Renci.SshNet/SshMessageFactory.cs +++ b/src/Renci.SshNet/SshMessageFactory.cs @@ -99,7 +99,7 @@ public Message Create(byte messageNumber) } var enabledMessageMetadata = _enabledMessagesByNumber[messageNumber]; - if (enabledMessageMetadata == null) + if (enabledMessageMetadata is null) { MessageMetadata definedMessageMetadata = null; @@ -114,7 +114,7 @@ public Message Create(byte messageNumber) } } - if (definedMessageMetadata == null) + if (definedMessageMetadata is null) { throw CreateMessageTypeNotSupportedException(messageNumber); } @@ -164,7 +164,7 @@ public void EnableActivatedMessages() public void EnableAndActivateMessage(string messageName) { - if (messageName == null) + if (messageName is null) { throw new ArgumentNullException(nameof(messageName)); } @@ -191,7 +191,7 @@ public void EnableAndActivateMessage(string messageName) public void DisableAndDeactivateMessage(string messageName) { - if (messageName == null) + if (messageName is null) { throw new ArgumentNullException(nameof(messageName)); } diff --git a/src/Renci.SshNet/SubsystemSession.cs b/src/Renci.SshNet/SubsystemSession.cs index 922312e37..2c2b66c06 100644 --- a/src/Renci.SshNet/SubsystemSession.cs +++ b/src/Renci.SshNet/SubsystemSession.cs @@ -82,12 +82,12 @@ public bool IsOpen /// or is null. protected SubsystemSession(ISession session, string subsystemName, int operationTimeout) { - if (session == null) + if (session is null) { throw new ArgumentNullException(nameof(session)); } - if (subsystemName == null) + if (subsystemName is null) { throw new ArgumentNullException(nameof(subsystemName)); } @@ -472,7 +472,7 @@ private void EnsureSessionIsOpen() /// private void UnsubscribeFromSessionEvents(ISession session) { - if (session == null) + if (session is null) { return; } From 27976bb927d3e93dda6adb4738b54d14070c34e1 Mon Sep 17 00:00:00 2001 From: Gert Driesen Date: Wed, 31 May 2023 09:52:52 +0200 Subject: [PATCH 22/96] Analyzer fixes round 3. (#1135) --- Directory.Build.props | 6 +- ...ftpSessionTest_Connected_RequestStatVfs.cs | 67 +++-- .../Sftp/SftpStatVfsResponseBuilder.cs | 9 +- .../Renci.SshNet.Tests.csproj | 6 +- src/Renci.SshNet/.editorconfig | 6 + .../Abstractions/CryptoAbstraction.cs | 16 ++ .../Abstractions/DiagnosticAbstraction.cs | 9 +- .../Abstractions/SocketAbstraction.cs | 6 +- .../Abstractions/SocketExtensions.cs | 8 +- src/Renci.SshNet/BaseClient.cs | 2 +- .../Channels/ChannelDirectTcpip.cs | 2 +- .../Channels/ChannelForwardedTcpip.cs | 2 +- src/Renci.SshNet/ClientAuthentication.cs | 4 +- src/Renci.SshNet/Common/BigInteger.cs | 268 +++++++++--------- .../Common/ChannelExtendedDataEventArgs.cs | 2 +- .../Common/ChannelOpenConfirmedEventArgs.cs | 2 +- .../Common/ChannelOpenFailedEventArgs.cs | 2 +- .../Common/ChannelRequestEventArgs.cs | 2 +- src/Renci.SshNet/Common/DerData.cs | 44 +-- src/Renci.SshNet/Common/PosixPath.cs | 2 +- src/Renci.SshNet/Common/SemaphoreLight.cs | 10 +- src/Renci.SshNet/Common/SshData.cs | 48 ++-- src/Renci.SshNet/Compression/Zlib.cs | 5 +- .../Connection/ProtocolVersionExchange.cs | 2 +- src/Renci.SshNet/Connection/ProxyConnector.cs | 2 +- src/Renci.SshNet/Connection/SocketFactory.cs | 2 +- .../Connection/SshIdentification.cs | 2 +- src/Renci.SshNet/ConnectionInfo.cs | 2 +- src/Renci.SshNet/ForwardedPortDynamic.NET.cs | 6 +- src/Renci.SshNet/ForwardedPortLocal.NET.cs | 6 +- src/Renci.SshNet/ForwardedPortRemote.cs | 4 +- src/Renci.SshNet/ForwardedPortStatus.cs | 8 +- ...KeyboardInteractiveAuthenticationMethod.cs | 2 +- .../InformationRequestMessage.cs | 2 +- .../InformationResponseMessage.cs | 2 +- .../PasswordChangeRequiredMessage.cs | 2 +- .../Authentication/PublicKeyMessage.cs | 2 +- .../RequestMessageKeyboardInteractive.cs | 2 +- .../Authentication/RequestMessageNone.cs | 2 +- .../Authentication/RequestMessagePassword.cs | 2 +- .../CancelTcpIpForwardGlobalRequestMessage.cs | 4 +- .../EnvironmentVariableRequestInfo.cs | 2 +- .../ChannelRequest/ExitSignalRequestInfo.cs | 2 +- .../ChannelRequest/ExitStatusRequestInfo.cs | 2 +- .../ChannelRequest/PseudoTerminalInfo.cs | 2 +- .../TcpIpForwardGlobalRequestMessage.cs | 2 +- src/Renci.SshNet/Netconf/NetConfSession.cs | 2 +- src/Renci.SshNet/NoneAuthenticationMethod.cs | 2 +- .../PasswordAuthenticationMethod.cs | 2 +- .../PrivateKeyAuthenticationMethod.cs | 2 +- src/Renci.SshNet/PrivateKeyFile.cs | 10 +- .../RemotePathDoubleQuoteTransformation.cs | 2 +- .../RemotePathNoneTransformation.cs | 2 +- .../RemotePathShellQuoteTransformation.cs | 2 +- .../Security/BouncyCastle/.editorconfig | 5 +- .../Security/Chaos.NaCl/.editorconfig | 5 +- .../Security/Cryptography/BlockCipher.cs | 36 +-- .../Cryptography/Ciphers/AesCipher.cs | 4 +- .../Cryptography/Ciphers/Arc4Cipher.cs | 14 +- .../Cryptography/Ciphers/DesCipher.cs | 4 +- .../Cryptography/Ciphers/RsaCipher.cs | 26 +- .../Cryptography/Ciphers/TripleDesCipher.cs | 13 +- .../Cryptography/EcdsaDigitalSignature.cs | 2 +- .../Security/Cryptography/EcdsaKey.cs | 15 +- .../Cryptography/RsaDigitalSignature.cs | 4 +- .../Security/Cryptography/RsaKey.cs | 4 +- .../Security/GroupExchangeHashData.cs | 2 +- src/Renci.SshNet/Security/KeyExchange.cs | 5 +- ...xchangeDiffieHellmanGroupExchangeSha256.cs | 6 +- src/Renci.SshNet/ServiceFactory.cs | 4 +- src/Renci.SshNet/Session.cs | 37 ++- .../ExtendedRequests/FStatVfsRequest.cs | 2 +- .../Responses/SftpExtendedReplyResponse.cs | 2 +- src/Renci.SshNet/Sftp/SftpFileReader.cs | 28 +- src/Renci.SshNet/Sftp/SftpFileStream.cs | 4 +- src/Renci.SshNet/Sftp/SftpSession.cs | 62 ++-- src/Renci.SshNet/SftpClient.cs | 136 +++++---- src/Renci.SshNet/Shell.cs | 10 +- src/Renci.SshNet/SshClient.cs | 6 +- src/Renci.SshNet/SshCommand.cs | 20 +- src/Renci.SshNet/SubsystemSession.cs | 10 +- 81 files changed, 554 insertions(+), 528 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index a4f567fdb..0baf38f42 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -37,10 +37,8 @@ - + --> diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestStatVfs.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestStatVfs.cs index 84cc4565a..2d5e00774 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestStatVfs.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestStatVfs.cs @@ -1,7 +1,10 @@ 锘縰sing System; using System.Text; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Moq; + using Renci.SshNet.Channels; using Renci.SshNet.Common; using Renci.SshNet.Sftp; @@ -97,33 +100,47 @@ private void SetupMocks() #region SftpSession.Connect() - _sessionMock.InSequence(sequence).Setup(p => p.CreateChannelSession()).Returns(_channelSessionMock.Object); - _channelSessionMock.InSequence(sequence).Setup(p => p.Open()); - _channelSessionMock.InSequence(sequence).Setup(p => p.SendSubsystemRequest("sftp")).Returns(true); - _channelSessionMock.InSequence(sequence).Setup(p => p.IsOpen).Returns(true); - _channelSessionMock.InSequence(sequence).Setup(p => p.SendData(_sftpInitRequestBytes)).Callback( - () => - { - _channelSessionMock.Raise(c => c.DataReceived += null, - new ChannelDataEventArgs(0, _sftpVersionResponse.GetBytes())); - }); - _channelSessionMock.InSequence(sequence).Setup(p => p.IsOpen).Returns(true); - _channelSessionMock.InSequence(sequence).Setup(p => p.SendData(_sftpRealPathRequestBytes)).Callback( - () => - { - _channelSessionMock.Raise(c => c.DataReceived += null, - new ChannelDataEventArgs(0, _sftpNameResponse.GetBytes())); - }); + _ = _sessionMock.InSequence(sequence) + .Setup(p => p.CreateChannelSession()) + .Returns(_channelSessionMock.Object); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.Open()); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendSubsystemRequest("sftp")) + .Returns(true); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendData(_sftpInitRequestBytes)) + .Callback(() => + { + _channelSessionMock.Raise(c => c.DataReceived += null, + new ChannelDataEventArgs(0, _sftpVersionResponse.GetBytes())); + }); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendData(_sftpRealPathRequestBytes)) + .Callback(() => + { + _channelSessionMock.Raise(c => c.DataReceived += null, + new ChannelDataEventArgs(0, _sftpNameResponse.GetBytes())); + }); #endregion SftpSession.Connect() - _channelSessionMock.InSequence(sequence).Setup(p => p.IsOpen).Returns(true); - _channelSessionMock.InSequence(sequence).Setup(p => p.SendData(_sftpStatVfsRequestBytes)).Callback( - () => - { - _channelSessionMock.Raise(c => c.DataReceived += null, - new ChannelDataEventArgs(0, _sftpStatVfsResponse.GetBytes())); - }); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.IsOpen) + .Returns(true); + _ = _channelSessionMock.InSequence(sequence) + .Setup(p => p.SendData(_sftpStatVfsRequestBytes)) + .Callback(() => + { + _channelSessionMock.Raise(c => c.DataReceived += null, + new ChannelDataEventArgs(0, _sftpStatVfsResponse.GetBytes())); + }); } protected void Arrange() @@ -153,4 +170,4 @@ public void AvailableBlocksInReturnedValueShouldMatchValueInSftpResponse() Assert.AreEqual(_bAvail, _actual.AvailableBlocks); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs index b3735b91d..485ebe560 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Tests.Classes.Sftp { - internal class SftpStatVfsResponseBuilder + internal sealed class SftpStatVfsResponseBuilder { private uint _protocolVersion; private uint _responseId; @@ -141,8 +141,13 @@ public StatVfsResponse Build() } } - internal class StatVfsResponse : SftpExtendedReplyResponse + internal sealed class StatVfsResponse : SftpResponse { + public override SftpMessageTypes SftpMessageType + { + get { return SftpMessageTypes.ExtendedReply; } + } + public SftpFileSytemInformation Information { get; set; } public StatVfsResponse(uint protocolVersion) diff --git a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index f4c0b6f33..88693e5aa 100644 --- a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -64,9 +64,9 @@ - - - + + + diff --git a/src/Renci.SshNet/.editorconfig b/src/Renci.SshNet/.editorconfig index c0430021e..5da8db715 100644 --- a/src/Renci.SshNet/.editorconfig +++ b/src/Renci.SshNet/.editorconfig @@ -13,6 +13,12 @@ dotnet_diagnostic.SYSLIB1045.severity = none # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1202.md dotnet_diagnostic.SA1202.severity = none +#### Meziantou.Analyzer rules #### + +# MA0053: Make class sealed +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0053.md +MA0053.public_class_should_be_sealed = false + #### .NET Compiler Platform analysers rules #### # CA1031: Do not catch general exception types diff --git a/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs b/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs index d46411044..45a624471 100644 --- a/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/CryptoAbstraction.cs @@ -39,12 +39,16 @@ public static System.Security.Cryptography.RandomNumberGenerator CreateRandomNum public static System.Security.Cryptography.MD5 CreateMD5() { +#pragma warning disable CA5351 // Do not use broken cryptographic algorithms return System.Security.Cryptography.MD5.Create(); +#pragma warning restore CA5351 // Do not use broken cryptographic algorithms } public static System.Security.Cryptography.SHA1 CreateSHA1() { +#pragma warning disable CA5350 // Do not use weak cryptographic algorithms return System.Security.Cryptography.SHA1.Create(); +#pragma warning restore CA5350 // Do not use weak cryptographic algorithms } public static System.Security.Cryptography.SHA256 CreateSHA256() @@ -66,7 +70,9 @@ public static System.Security.Cryptography.SHA512 CreateSHA512() public static System.Security.Cryptography.RIPEMD160 CreateRIPEMD160() { #if FEATURE_HASH_RIPEMD160_CREATE +#pragma warning disable CA5350 // Do not use weak cryptographic algorithms return System.Security.Cryptography.RIPEMD160.Create(); +#pragma warning restore CA5350 // Do not use weak cryptographic algorithms #else return new System.Security.Cryptography.RIPEMD160Managed(); #endif @@ -80,22 +86,30 @@ public static System.Security.Cryptography.RIPEMD160 CreateRIPEMD160() public static System.Security.Cryptography.HMACMD5 CreateHMACMD5(byte[] key) { +#pragma warning disable CA5351 // Do not use broken cryptographic algorithms return new System.Security.Cryptography.HMACMD5(key); +#pragma warning restore CA5351 // Do not use broken cryptographic algorithms } public static HMACMD5 CreateHMACMD5(byte[] key, int hashSize) { +#pragma warning disable CA5351 // Do not use broken cryptographic algorithms return new HMACMD5(key, hashSize); +#pragma warning restore CA5351 // Do not use broken cryptographic algorithms } public static System.Security.Cryptography.HMACSHA1 CreateHMACSHA1(byte[] key) { +#pragma warning disable CA5350 // Do not use weak cryptographic algorithms return new System.Security.Cryptography.HMACSHA1(key); +#pragma warning restore CA5350 // Do not use weak cryptographic algorithms } public static HMACSHA1 CreateHMACSHA1(byte[] key, int hashSize) { +#pragma warning disable CA5350 // Do not use weak cryptographic algorithms return new HMACSHA1(key, hashSize); +#pragma warning restore CA5350 // Do not use weak cryptographic algorithms } public static System.Security.Cryptography.HMACSHA256 CreateHMACSHA256(byte[] key) @@ -131,7 +145,9 @@ public static HMACSHA512 CreateHMACSHA512(byte[] key, int hashSize) #if FEATURE_HMAC_RIPEMD160 public static System.Security.Cryptography.HMACRIPEMD160 CreateHMACRIPEMD160(byte[] key) { +#pragma warning disable CA5350 // Do not use weak cryptographic algorithms return new System.Security.Cryptography.HMACRIPEMD160(key); +#pragma warning restore CA5350 // Do not use weak cryptographic algorithms } #else public static global::SshNet.Security.Cryptography.HMACRIPEMD160 CreateHMACRIPEMD160(byte[] key) diff --git a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs index 16ee1c0ab..18275e724 100644 --- a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs @@ -1,5 +1,4 @@ 锘縰sing System.Diagnostics; -using System.Threading; namespace Renci.SshNet.Abstractions { @@ -22,7 +21,13 @@ public static bool IsEnabled(TraceEventType traceEventType) [Conditional("DEBUG")] public static void Log(string text) { - Loggging.TraceEvent(TraceEventType.Verbose, Thread.CurrentThread.ManagedThreadId, text); + Loggging.TraceEvent(TraceEventType.Verbose, +#if NET6_0_OR_GREATER + System.Environment.CurrentManagedThreadId, +#else + System.Threading.Thread.CurrentThread.ManagedThreadId, +#endif // NET6_0_OR_GREATER + text); } } } diff --git a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs index 5784879fa..a1fe71d75 100644 --- a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs @@ -43,13 +43,13 @@ public static bool CanWrite(Socket socket) public static Socket Connect(IPEndPoint remoteEndpoint, TimeSpan connectTimeout) { var socket = new Socket(remoteEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp) { NoDelay = true }; - ConnectCore(socket, remoteEndpoint, connectTimeout, true); + ConnectCore(socket, remoteEndpoint, connectTimeout, ownsSocket: true); return socket; } public static void Connect(Socket socket, IPEndPoint remoteEndpoint, TimeSpan connectTimeout) { - ConnectCore(socket, remoteEndpoint, connectTimeout, false); + ConnectCore(socket, remoteEndpoint, connectTimeout, ownsSocket: false); } public static async Task ConnectAsync(Socket socket, IPEndPoint remoteEndpoint, CancellationToken cancellationToken) @@ -60,7 +60,7 @@ public static async Task ConnectAsync(Socket socket, IPEndPoint remoteEndpoint, private static void ConnectCore(Socket socket, IPEndPoint remoteEndpoint, TimeSpan connectTimeout, bool ownsSocket) { #if FEATURE_SOCKET_EAP - var connectCompleted = new ManualResetEvent(false); + var connectCompleted = new ManualResetEvent(initialState: false); var args = new SocketAsyncEventArgs { UserToken = connectCompleted, diff --git a/src/Renci.SshNet/Abstractions/SocketExtensions.cs b/src/Renci.SshNet/Abstractions/SocketExtensions.cs index 8e6c0133b..a51d0cb8d 100644 --- a/src/Renci.SshNet/Abstractions/SocketExtensions.cs +++ b/src/Renci.SshNet/Abstractions/SocketExtensions.cs @@ -35,7 +35,7 @@ public void SetCompleted() { IsCompleted = true; - var continuation = _continuationAction ?? Interlocked.CompareExchange(ref _continuationAction, SENTINEL, null); + var continuation = _continuationAction ?? Interlocked.CompareExchange(ref _continuationAction, SENTINEL, comparand: null); if (continuation is not null) { continuation(); @@ -57,7 +57,7 @@ public SocketAsyncEventArgsAwaitable GetAwaiter() void INotifyCompletion.OnCompleted(Action continuation) { - if (_continuationAction == SENTINEL || Interlocked.CompareExchange(ref _continuationAction, continuation, null) == SENTINEL) + if (_continuationAction == SENTINEL || Interlocked.CompareExchange(ref _continuationAction, continuation, comparand: null) == SENTINEL) { // We have already completed; run continuation asynchronously _ = Task.Run(continuation); @@ -92,7 +92,7 @@ public static async Task ConnectAsync(this Socket socket, IPEndPoint remoteEndpo { args.RemoteEndPoint = remoteEndpoint; - using (cancellationToken.Register(o => ((SocketAsyncEventArgsAwaitable)o).SetCancelled(), args, false)) + using (cancellationToken.Register(o => ((SocketAsyncEventArgsAwaitable)o).SetCancelled(), args, useSynchronizationContext: false)) { await args.ExecuteAsync(socket.ConnectAsync); } @@ -107,7 +107,7 @@ public static async Task ReceiveAsync(this Socket socket, byte[] buffer, in { args.SetBuffer(buffer, offset, length); - using (cancellationToken.Register(o => ((SocketAsyncEventArgsAwaitable)o).SetCancelled(), args, false)) + using (cancellationToken.Register(o => ((SocketAsyncEventArgsAwaitable)o).SetCancelled(), args, useSynchronizationContext: false)) { await args.ExecuteAsync(socket.ReceiveAsync); } diff --git a/src/Renci.SshNet/BaseClient.cs b/src/Renci.SshNet/BaseClient.cs index ed0db2bba..a879c02f8 100644 --- a/src/Renci.SshNet/BaseClient.cs +++ b/src/Renci.SshNet/BaseClient.cs @@ -180,7 +180,7 @@ protected BaseClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo) /// If is true, then the /// connection info will be disposed when this instance is disposed. /// - internal BaseClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) + private protected BaseClient(ConnectionInfo connectionInfo, bool ownsConnectionInfo, IServiceFactory serviceFactory) { if (connectionInfo is null) { diff --git a/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs b/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs index 11eea894c..6c521bce2 100644 --- a/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs +++ b/src/Renci.SshNet/Channels/ChannelDirectTcpip.cs @@ -11,7 +11,7 @@ namespace Renci.SshNet.Channels /// /// Implements "direct-tcpip" SSH channel. /// - internal class ChannelDirectTcpip : ClientChannel, IChannelDirectTcpip + internal sealed class ChannelDirectTcpip : ClientChannel, IChannelDirectTcpip { private readonly object _socketLock = new object(); diff --git a/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs b/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs index 465c8f181..0d67c7afe 100644 --- a/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs +++ b/src/Renci.SshNet/Channels/ChannelForwardedTcpip.cs @@ -10,7 +10,7 @@ namespace Renci.SshNet.Channels /// /// Implements "forwarded-tcpip" SSH channel. /// - internal class ChannelForwardedTcpip : ServerChannel, IChannelForwardedTcpip + internal sealed class ChannelForwardedTcpip : ServerChannel, IChannelForwardedTcpip { private readonly object _socketShutdownAndCloseLock = new object(); private Socket _socket; diff --git a/src/Renci.SshNet/ClientAuthentication.cs b/src/Renci.SshNet/ClientAuthentication.cs index 6d91455af..1cdfbecbe 100644 --- a/src/Renci.SshNet/ClientAuthentication.cs +++ b/src/Renci.SshNet/ClientAuthentication.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet { - internal class ClientAuthentication : IClientAuthentication + internal sealed class ClientAuthentication : IClientAuthentication { private readonly int _partialSuccessLimit; @@ -151,7 +151,7 @@ private bool TryAuthenticate(ISession session, return false; } - private class AuthenticationState + private sealed class AuthenticationState { private readonly IList _supportedAuthenticationMethods; diff --git a/src/Renci.SshNet/Common/BigInteger.cs b/src/Renci.SshNet/Common/BigInteger.cs index 47c0aa4a4..dd6919687 100644 --- a/src/Renci.SshNet/Common/BigInteger.cs +++ b/src/Renci.SshNet/Common/BigInteger.cs @@ -300,24 +300,6 @@ public BigInteger(ulong value) } } - private static bool Negative(byte[] v) - { - return (v[7] & 0x80) != 0; - } - - private static ushort Exponent(byte[] v) - { - return (ushort)((((ushort)(v[7] & 0x7F)) << (ushort)4) | (((ushort)(v[6] & 0xF0)) >> 4)); - } - - private static ulong Mantissa(byte[] v) - { - var i1 = (uint)v[0] | ((uint)v[1] << 8) | ((uint)v[2] << 16) | ((uint)v[3] << 24); - var i2 = (uint)v[4] | ((uint)v[5] << 8) | ((uint)(v[6] & 0xF) << 16); - - return (ulong)((ulong)i1 | ((ulong)i2 << 32)); - } - /// /// Initializes a new instance of the structure using a double-precision floating-point value. /// @@ -355,7 +337,7 @@ public BigInteger(double value) BigInteger res = mantissa; res = exponent > Bias ? res << (exponent - Bias) : res >> (Bias - exponent); - _sign = (short)(Negative(bytes) ? -1 : 1); + _sign = (short) (Negative(bytes) ? -1 : 1); _data = res._data; } } @@ -365,7 +347,7 @@ public BigInteger(double value) /// /// A single-precision floating-point value. public BigInteger(float value) - : this((double)value) + : this((double) value) { } @@ -391,10 +373,10 @@ public BigInteger(decimal value) return; } - _sign = (short)((bits[3] & DecimalSignMask) != 0 ? -1 : 1); + _sign = (short) ((bits[3] & DecimalSignMask) != 0 ? -1 : 1); _data = new uint[size]; - _data[0] = (uint)bits[0]; + _data[0] = (uint) bits[0]; if (size > 1) { _data[1] = (uint) bits[1]; @@ -498,9 +480,9 @@ public BigInteger(byte[] value) (uint) (value[j++] << 16) | (uint) (value[j++] << 24); - sub = (ulong)word - borrow; - word = (uint)sub; - borrow = (uint)(sub >> 32) & 0x1u; + sub = (ulong) word - borrow; + word = (uint) sub; + borrow = (uint) (sub >> 32) & 0x1u; _data[i] = ~word; } @@ -512,13 +494,13 @@ public BigInteger(byte[] value) uint storeMask = 0; for (var i = 0; i < size; ++i) { - word |= (uint)(value[j++] << (i * 8)); + word |= (uint) (value[j++] << (i * 8)); storeMask = (storeMask << 8) | 0xFF; } sub = word - borrow; - word = (uint)sub; - borrow = (uint)(sub >> 32) & 0x1u; + word = (uint) sub; + borrow = (uint) (sub >> 32) & 0x1u; if ((~word & storeMask) == 0) { @@ -538,6 +520,24 @@ public BigInteger(byte[] value) } } + private static bool Negative(byte[] v) + { + return (v[7] & 0x80) != 0; + } + + private static ushort Exponent(byte[] v) + { + return (ushort)((((ushort)(v[7] & 0x7F)) << (ushort)4) | (((ushort)(v[6] & 0xF0)) >> 4)); + } + + private static ulong Mantissa(byte[] v) + { + var i1 = (uint)v[0] | ((uint)v[1] << 8) | ((uint)v[2] << 16) | ((uint)v[3] << 24); + var i2 = (uint)v[4] | ((uint)v[5] << 8) | ((uint)(v[6] & 0xF) << 16); + + return ((ulong) i1 | ((ulong) i2 << 32)); + } + /// /// Gets a value indicating whether the value of the current object is an even number. /// @@ -2514,7 +2514,7 @@ static int BitScanBackward(uint word) /// of implicit conversion to a value, and its value is equal to the value of the /// current object; otherwise, false. /// - public override bool Equals(object obj) + public override readonly bool Equals(object obj) { if (obj is not BigInteger other) { @@ -2533,7 +2533,7 @@ public override bool Equals(object obj) /// true if this object and have the same value; /// otherwise, false. /// - public bool Equals(BigInteger other) + public readonly bool Equals(BigInteger other) { if (_sign != other._sign) { @@ -2572,37 +2572,27 @@ public readonly bool Equals(long other) } /// - /// Converts the numeric value of the current object to its equivalent string representation. + /// Returns a value that indicates whether the current instance and an unsigned 64-bit integer have the same value. /// + /// The unsigned 64-bit integer to compare. /// - /// The string representation of the current value. + /// true if the current instance and the unsigned 64-bit integer have the same value; otherwise, false. /// - public override string ToString() + [CLSCompliant(false)] + public readonly bool Equals(ulong other) { - return ToString(10, provider: null); + return CompareTo(other) == 0; } - private string ToStringWithPadding(string format, uint radix, IFormatProvider provider) + /// + /// Converts the numeric value of the current object to its equivalent string representation. + /// + /// + /// The string representation of the current value. + /// + public override readonly string ToString() { - if (format.Length > 1) - { - var precision = Convert.ToInt32(format.Substring(1), CultureInfo.InvariantCulture.NumberFormat); - var baseStr = ToString(radix, provider); - if (baseStr.Length < precision) - { - var additional = new string('0', precision - baseStr.Length); - if (baseStr[0] != '-') - { - return additional + baseStr; - } - - return "-" + additional + baseStr.Substring(1); - } - - return baseStr; - } - - return ToString(radix, provider); + return ToString(10, provider: null); } /// @@ -2615,9 +2605,9 @@ private string ToStringWithPadding(string format, uint radix, IFormatProvider pr /// parameter. /// /// is not a valid format string. - public string ToString(string format) + public readonly string ToString(string format) { - return ToString(format, provider: null); + return ToString(format, formatProvider: null); } /// @@ -2629,7 +2619,7 @@ public string ToString(string format) /// The string representation of the current value in the format specified by the /// parameter. /// - public string ToString(IFormatProvider provider) + public readonly string ToString(IFormatProvider provider) { return ToString(format: null, provider); } @@ -2639,16 +2629,16 @@ public string ToString(IFormatProvider provider) /// by using the specified format and culture-specific format information. /// /// A standard or custom numeric format string. - /// An object that supplies culture-specific formatting information. + /// An object that supplies culture-specific formatting information. /// /// The string representation of the current value as specified by the - /// and parameters. + /// and parameters. /// - public string ToString(string format, IFormatProvider provider) + public readonly string ToString(string format, IFormatProvider formatProvider) { if (string.IsNullOrEmpty(format)) { - return ToString(10, provider); + return ToString(10, formatProvider); } switch (format[0]) @@ -2659,7 +2649,7 @@ public string ToString(string format, IFormatProvider provider) case 'G': case 'r': case 'R': - return ToStringWithPadding(format, 10, provider); + return ToStringWithPadding(format, 10, formatProvider); case 'x': case 'X': return ToStringWithPadding(format, 16, provider: null); @@ -2668,6 +2658,29 @@ public string ToString(string format, IFormatProvider provider) } } + private readonly string ToStringWithPadding(string format, uint radix, IFormatProvider provider) + { + if (format.Length > 1) + { + var precision = Convert.ToInt32(format.Substring(1), CultureInfo.InvariantCulture.NumberFormat); + var baseStr = ToString(radix, provider); + if (baseStr.Length < precision) + { + var additional = new string('0', precision - baseStr.Length); + if (baseStr[0] != '-') + { + return additional + baseStr; + } + + return "-" + additional + baseStr.Substring(1); + } + + return baseStr; + } + + return ToString(radix, provider); + } + private static uint[] MakeTwoComplement(uint[] v) { var res = new uint[v.Length]; @@ -3369,7 +3382,7 @@ private static bool FindExponent(ref int pos, string s, ref int exponent, bool t } // Reduce the risk of throwing an overflow exc - exp = checked((exp * 10) - (int)(s[i] - '0')); + exp = checked((exp * 10) - (s[i] - '0')); if (exp is < int.MinValue or > int.MaxValue) { exc = tryParse ? null : new OverflowException("Value too large or too small."); @@ -3627,7 +3640,7 @@ public static BigInteger Max(BigInteger left, BigInteger right) /// public static BigInteger Abs(BigInteger value) { - return new BigInteger((short) Math.Abs(value._sign), value._data); + return new BigInteger(Math.Abs(value._sign), value._data); } /// @@ -3971,19 +3984,6 @@ public static double Log10(BigInteger value) return Log(value, 10); } - /// - /// Returns a value that indicates whether the current instance and an unsigned 64-bit integer have the same value. - /// - /// The unsigned 64-bit integer to compare. - /// - /// true if the current instance and the unsigned 64-bit integer have the same value; otherwise, false. - /// - [CLSCompliant(false)] - public readonly bool Equals(ulong other) - { - return CompareTo(other) == 0; - } - /// /// Returns the hash code for the current object. /// @@ -4207,40 +4207,6 @@ public readonly int CompareTo(ulong other) return LongCompare(low, high); } - private readonly int LongCompare(uint low, uint high) - { - uint h = 0; - - if (_data.Length > 1) - { - h = _data[1]; - } - - if (h > high) - { - return 1; - } - - if (h < high) - { - return -1; - } - - var l = _data[0]; - - if (l > low) - { - return 1; - } - - if (l < low) - { - return -1; - } - - return 0; - } - /// /// Compares this instance to a signed 64-bit integer and returns an integer that indicates whether the value of this /// instance is less than, equal to, or greater than the value of the signed 64-bit integer. @@ -4305,6 +4271,40 @@ public readonly int CompareTo(long other) return r; } + private readonly int LongCompare(uint low, uint high) + { + uint h = 0; + + if (_data.Length > 1) + { + h = _data[1]; + } + + if (h > high) + { + return 1; + } + + if (h < high) + { + return -1; + } + + var l = _data[0]; + + if (l > low) + { + return 1; + } + + if (l < low) + { + return -1; + } + + return 0; + } + /// /// Compares two values and returns an integer that indicates whether the first value is less than, equal to, or greater than the second value. /// @@ -4545,6 +4545,29 @@ private static uint[] CoreAdd(uint[] a, uint[] b) return res; } + private static uint[] CoreAdd(uint[] a, uint b) + { + var len = a.Length; + var res = new uint[len]; + + ulong sum = b; + int i; + for (i = 0; i < len; i++) + { + sum += a[i]; + res[i] = (uint) sum; + sum >>= 32; + } + + if (sum != 0) + { + Array.Resize(ref res, len + 1); + res[i] = (uint) sum; + } + + return res; + } + /*invariant a > b*/ private static uint[] CoreSub(uint[] a, uint[] b) { @@ -4584,29 +4607,6 @@ private static uint[] CoreSub(uint[] a, uint[] b) return res; } - private static uint[] CoreAdd(uint[] a, uint b) - { - var len = a.Length; - var res = new uint[len]; - - ulong sum = b; - int i; - for (i = 0; i < len; i++) - { - sum += a[i]; - res[i] = (uint)sum; - sum >>= 32; - } - - if (sum != 0) - { - Array.Resize(ref res, len + 1); - res[i] = (uint)sum; - } - - return res; - } - private static uint[] CoreSub(uint[] a, uint b) { var len = a.Length; diff --git a/src/Renci.SshNet/Common/ChannelExtendedDataEventArgs.cs b/src/Renci.SshNet/Common/ChannelExtendedDataEventArgs.cs index b5eadffe1..e67ccb901 100644 --- a/src/Renci.SshNet/Common/ChannelExtendedDataEventArgs.cs +++ b/src/Renci.SshNet/Common/ChannelExtendedDataEventArgs.cs @@ -3,7 +3,7 @@ /// /// Provides data for events. /// - internal class ChannelExtendedDataEventArgs : ChannelDataEventArgs + internal sealed class ChannelExtendedDataEventArgs : ChannelDataEventArgs { /// /// Initializes a new instance of the class. diff --git a/src/Renci.SshNet/Common/ChannelOpenConfirmedEventArgs.cs b/src/Renci.SshNet/Common/ChannelOpenConfirmedEventArgs.cs index 9af1e782d..78cd9cd6b 100644 --- a/src/Renci.SshNet/Common/ChannelOpenConfirmedEventArgs.cs +++ b/src/Renci.SshNet/Common/ChannelOpenConfirmedEventArgs.cs @@ -3,7 +3,7 @@ /// /// Provides data for event. /// - internal class ChannelOpenConfirmedEventArgs : ChannelEventArgs + internal sealed class ChannelOpenConfirmedEventArgs : ChannelEventArgs { /// /// Initializes a new instance of the class. diff --git a/src/Renci.SshNet/Common/ChannelOpenFailedEventArgs.cs b/src/Renci.SshNet/Common/ChannelOpenFailedEventArgs.cs index 43b5790c6..291e9d7a6 100644 --- a/src/Renci.SshNet/Common/ChannelOpenFailedEventArgs.cs +++ b/src/Renci.SshNet/Common/ChannelOpenFailedEventArgs.cs @@ -3,7 +3,7 @@ /// /// Provides data for event. /// - internal class ChannelOpenFailedEventArgs : ChannelEventArgs + internal sealed class ChannelOpenFailedEventArgs : ChannelEventArgs { /// /// Initializes a new instance of the class. diff --git a/src/Renci.SshNet/Common/ChannelRequestEventArgs.cs b/src/Renci.SshNet/Common/ChannelRequestEventArgs.cs index b03102aef..7747b7621 100644 --- a/src/Renci.SshNet/Common/ChannelRequestEventArgs.cs +++ b/src/Renci.SshNet/Common/ChannelRequestEventArgs.cs @@ -7,7 +7,7 @@ namespace Renci.SshNet.Common /// /// Provides data for event. /// - internal class ChannelRequestEventArgs : EventArgs + internal sealed class ChannelRequestEventArgs : EventArgs { /// /// Initializes a new instance of the class. diff --git a/src/Renci.SshNet/Common/DerData.cs b/src/Renci.SshNet/Common/DerData.cs index ee6c07e36..5928d3086 100644 --- a/src/Renci.SshNet/Common/DerData.cs +++ b/src/Renci.SshNet/Common/DerData.cs @@ -230,18 +230,6 @@ public void Write(byte[] data) WriteBytes(data); } - /// - /// Writes BITSTRING data into internal buffer. - /// - /// The data. - public void WriteBitstring(byte[] data) - { - _data.Add(BITSTRING); - var length = GetLength(data.Length); - WriteBytes(length); - WriteBytes(data); - } - /// /// Writes OBJECTIDENTIFIER data into internal buffer. /// @@ -285,6 +273,28 @@ public void Write(ObjectIdentifier identifier) WriteBytes(bytes); } + /// + /// Writes DerData data into internal buffer. + /// + /// DerData data to write. + public void Write(DerData data) + { + var bytes = data.Encode(); + _data.AddRange(bytes); + } + + /// + /// Writes BITSTRING data into internal buffer. + /// + /// The data. + public void WriteBitstring(byte[] data) + { + _data.Add(BITSTRING); + var length = GetLength(data.Length); + WriteBytes(length); + WriteBytes(data); + } + /// /// Writes OBJECTIDENTIFIER data into internal buffer. /// @@ -306,16 +316,6 @@ public void WriteNull() _data.Add(0); } - /// - /// Writes DerData data into internal buffer. - /// - /// DerData data to write. - public void Write(DerData data) - { - var bytes = data.Encode(); - _data.AddRange(bytes); - } - private static byte[] GetLength(int length) { if (length > 127) diff --git a/src/Renci.SshNet/Common/PosixPath.cs b/src/Renci.SshNet/Common/PosixPath.cs index 0dae95ea1..1eddc5710 100644 --- a/src/Renci.SshNet/Common/PosixPath.cs +++ b/src/Renci.SshNet/Common/PosixPath.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Common /// /// Represents a POSIX path. /// - internal class PosixPath + internal sealed class PosixPath { private PosixPath() { diff --git a/src/Renci.SshNet/Common/SemaphoreLight.cs b/src/Renci.SshNet/Common/SemaphoreLight.cs index 8ee4167d1..5c20a9e94 100644 --- a/src/Renci.SshNet/Common/SemaphoreLight.cs +++ b/src/Renci.SshNet/Common/SemaphoreLight.cs @@ -215,14 +215,6 @@ private bool WaitWithTimeout(int timeoutInMilliseconds) } } - /// - /// Finalizes an instance of the class. - /// - ~SemaphoreLight() - { - Dispose(disposing: false); - } - /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// @@ -241,7 +233,7 @@ protected void Dispose(bool disposing) if (disposing) { var waitHandle = _waitHandle; - if (waitHandle != null) + if (waitHandle is not null) { waitHandle.Dispose(); _waitHandle = null; diff --git a/src/Renci.SshNet/Common/SshData.cs b/src/Renci.SshNet/Common/SshData.cs index 67823ec2d..ac063b7a0 100644 --- a/src/Renci.SshNet/Common/SshData.cs +++ b/src/Renci.SshNet/Common/SshData.cs @@ -358,30 +358,6 @@ protected void Write(string data, Encoding encoding) _stream.Write(data, encoding); } - /// - /// Writes data into internal buffer. - /// - /// The data to write. - /// is null. - protected void WriteBinaryString(byte[] buffer) - { - _stream.WriteBinary(buffer); - } - - /// - /// Writes data into internal buffer. - /// - /// An array of bytes. This method write bytes from buffer to the current SSH data stream. - /// The zero-based byte offset in at which to begin writing bytes to the SSH data stream. - /// The number of bytes to be written to the current SSH data stream. - /// is null. - /// The sum of and is greater than the buffer length. - /// or is negative. - protected void WriteBinary(byte[] buffer, int offset, int count) - { - _stream.WriteBinary(buffer, offset, count); - } - /// /// Writes mpint data into internal buffer. /// @@ -412,5 +388,29 @@ protected void Write(IDictionary data) Write(item.Value, Ascii); } } + + /// + /// Writes data into internal buffer. + /// + /// The data to write. + /// is null. + protected void WriteBinaryString(byte[] buffer) + { + _stream.WriteBinary(buffer); + } + + /// + /// Writes data into internal buffer. + /// + /// An array of bytes. This method write bytes from buffer to the current SSH data stream. + /// The zero-based byte offset in at which to begin writing bytes to the SSH data stream. + /// The number of bytes to be written to the current SSH data stream. + /// is null. + /// The sum of and is greater than the buffer length. + /// or is negative. + protected void WriteBinary(byte[] buffer, int offset, int count) + { + _stream.WriteBinary(buffer, offset, count); + } } } diff --git a/src/Renci.SshNet/Compression/Zlib.cs b/src/Renci.SshNet/Compression/Zlib.cs index b518717a4..0dc5918c4 100644 --- a/src/Renci.SshNet/Compression/Zlib.cs +++ b/src/Renci.SshNet/Compression/Zlib.cs @@ -3,7 +3,7 @@ /// /// Represents "zlib" compression implementation /// - internal class Zlib : Compressor + internal sealed class Zlib : Compressor { /// /// Gets algorithm name. @@ -20,7 +20,8 @@ public override string Name public override void Init(Session session) { base.Init(session); + IsActive = true; } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs index 8f3beb51f..068df230c 100644 --- a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs +++ b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs @@ -19,7 +19,7 @@ namespace Renci.SshNet.Connection /// /// https://tools.ietf.org/html/rfc4253#section-4.2. /// - internal class ProtocolVersionExchange : IProtocolVersionExchange + internal sealed class ProtocolVersionExchange : IProtocolVersionExchange { private const byte Null = 0x00; diff --git a/src/Renci.SshNet/Connection/ProxyConnector.cs b/src/Renci.SshNet/Connection/ProxyConnector.cs index 9bbf8b0f2..089ee562a 100644 --- a/src/Renci.SshNet/Connection/ProxyConnector.cs +++ b/src/Renci.SshNet/Connection/ProxyConnector.cs @@ -7,7 +7,7 @@ namespace Renci.SshNet.Connection { internal abstract class ProxyConnector : ConnectorBase { - public ProxyConnector(ISocketFactory socketFactory) + protected ProxyConnector(ISocketFactory socketFactory) : base(socketFactory) { } diff --git a/src/Renci.SshNet/Connection/SocketFactory.cs b/src/Renci.SshNet/Connection/SocketFactory.cs index 8c61b87c6..d279da288 100644 --- a/src/Renci.SshNet/Connection/SocketFactory.cs +++ b/src/Renci.SshNet/Connection/SocketFactory.cs @@ -2,7 +2,7 @@ namespace Renci.SshNet.Connection { - internal class SocketFactory : ISocketFactory + internal sealed class SocketFactory : ISocketFactory { public Socket Create(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) { diff --git a/src/Renci.SshNet/Connection/SshIdentification.cs b/src/Renci.SshNet/Connection/SshIdentification.cs index a950ad71f..931656296 100644 --- a/src/Renci.SshNet/Connection/SshIdentification.cs +++ b/src/Renci.SshNet/Connection/SshIdentification.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Connection /// /// Represents an SSH identification. /// - internal class SshIdentification + internal sealed class SshIdentification { /// /// Initializes a new instance of the class with the specified protocol version diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index 89abcd63d..e7bd6cdd2 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -23,7 +23,7 @@ namespace Renci.SshNet /// public class ConnectionInfo : IConnectionInfoInternal { - internal static int DefaultPort = 22; + internal const int DefaultPort = 22; /// /// The default connection timeout. diff --git a/src/Renci.SshNet/ForwardedPortDynamic.NET.cs b/src/Renci.SshNet/ForwardedPortDynamic.NET.cs index eca6f6427..0ae0f4319 100644 --- a/src/Renci.SshNet/ForwardedPortDynamic.NET.cs +++ b/src/Renci.SshNet/ForwardedPortDynamic.NET.cs @@ -38,7 +38,7 @@ partial void InternalStart() // consider port started when we're listening for inbound connections _status = ForwardedPortStatus.Started; - StartAccept(null); + StartAccept(e: null); } private void StartAccept(SocketAsyncEventArgs e) @@ -61,12 +61,12 @@ private void StartAccept(SocketAsyncEventArgs e) { if (!_listener.AcceptAsync(e)) { - AcceptCompleted(null, e); + AcceptCompleted(sender: null, e); } } catch (ObjectDisposedException) { - if (_status == ForwardedPortStatus.Stopped || _status == ForwardedPortStatus.Stopped) + if (_status == ForwardedPortStatus.Stopping || _status == ForwardedPortStatus.Stopped) { // ignore ObjectDisposedException while stopping or stopped return; diff --git a/src/Renci.SshNet/ForwardedPortLocal.NET.cs b/src/Renci.SshNet/ForwardedPortLocal.NET.cs index 3bd9e3f52..ca7ec6261 100644 --- a/src/Renci.SshNet/ForwardedPortLocal.NET.cs +++ b/src/Renci.SshNet/ForwardedPortLocal.NET.cs @@ -33,7 +33,7 @@ partial void InternalStart() // consider port started when we're listening for inbound connections _status = ForwardedPortStatus.Started; - StartAccept(null); + StartAccept(e: null); } private void StartAccept(SocketAsyncEventArgs e) @@ -56,12 +56,12 @@ private void StartAccept(SocketAsyncEventArgs e) { if (!_listener.AcceptAsync(e)) { - AcceptCompleted(null, e); + AcceptCompleted(sender: null, e); } } catch (ObjectDisposedException) { - if (_status == ForwardedPortStatus.Stopped || _status == ForwardedPortStatus.Stopped) + if (_status == ForwardedPortStatus.Stopping || _status == ForwardedPortStatus.Stopped) { // ignore ObjectDisposedException while stopping or stopped return; diff --git a/src/Renci.SshNet/ForwardedPortRemote.cs b/src/Renci.SshNet/ForwardedPortRemote.cs index 4d220c644..ce465e12e 100644 --- a/src/Renci.SshNet/ForwardedPortRemote.cs +++ b/src/Renci.SshNet/ForwardedPortRemote.cs @@ -16,7 +16,7 @@ public class ForwardedPortRemote : ForwardedPort, IDisposable { private ForwardedPortStatus _status; private bool _requestStatus; - private EventWaitHandle _globalRequestResponse = new AutoResetEvent(false); + private EventWaitHandle _globalRequestResponse = new AutoResetEvent(initialState: false); private CountdownEvent _pendingChannelCountdown; private bool _isDisposed; @@ -390,7 +390,7 @@ protected override void Dispose(bool disposing) /// ~ForwardedPortRemote() { - Dispose(false); + Dispose(disposing: false); } } } diff --git a/src/Renci.SshNet/ForwardedPortStatus.cs b/src/Renci.SshNet/ForwardedPortStatus.cs index d82531a1c..2f151e842 100644 --- a/src/Renci.SshNet/ForwardedPortStatus.cs +++ b/src/Renci.SshNet/ForwardedPortStatus.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet { - internal class ForwardedPortStatus + internal sealed class ForwardedPortStatus { public static readonly ForwardedPortStatus Stopped = new ForwardedPortStatus(1, "Stopped"); public static readonly ForwardedPortStatus Stopping = new ForwardedPortStatus(2, "Stopping"); @@ -19,14 +19,14 @@ private ForwardedPortStatus(int value, string name) _name = name; } - public override bool Equals(object other) + public override bool Equals(object obj) { - if (ReferenceEquals(this, other)) + if (ReferenceEquals(this, obj)) { return true; } - if (other is not ForwardedPortStatus forwardedPortStatus) + if (obj is not ForwardedPortStatus forwardedPortStatus) { return false; } diff --git a/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs b/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs index 90fc1f283..b559808d1 100644 --- a/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs +++ b/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs @@ -17,7 +17,7 @@ public class KeyboardInteractiveAuthenticationMethod : AuthenticationMethod, IDi private readonly RequestMessage _requestMessage; private AuthenticationResult _authenticationResult = AuthenticationResult.Failure; private Session _session; - private EventWaitHandle _authenticationCompleted = new AutoResetEvent(false); + private EventWaitHandle _authenticationCompleted = new AutoResetEvent(initialState: false); private Exception _exception; private bool _isDisposed; diff --git a/src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs b/src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs index 910a0f55e..c887cc883 100644 --- a/src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs @@ -9,7 +9,7 @@ namespace Renci.SshNet.Messages.Authentication /// Represents SSH_MSG_USERAUTH_INFO_REQUEST message. /// [Message("SSH_MSG_USERAUTH_INFO_REQUEST", 60)] - internal class InformationRequestMessage : Message + internal sealed class InformationRequestMessage : Message { /// /// Gets information request name. diff --git a/src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs b/src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs index 5e0c352fb..4aa9cda41 100644 --- a/src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs @@ -7,7 +7,7 @@ namespace Renci.SshNet.Messages.Authentication /// Represents SSH_MSG_USERAUTH_INFO_RESPONSE message. /// [Message("SSH_MSG_USERAUTH_INFO_RESPONSE", 61)] - internal class InformationResponseMessage : Message + internal sealed class InformationResponseMessage : Message { /// /// Gets authentication responses. diff --git a/src/Renci.SshNet/Messages/Authentication/PasswordChangeRequiredMessage.cs b/src/Renci.SshNet/Messages/Authentication/PasswordChangeRequiredMessage.cs index ac05dffa2..a87b53dfb 100644 --- a/src/Renci.SshNet/Messages/Authentication/PasswordChangeRequiredMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/PasswordChangeRequiredMessage.cs @@ -4,7 +4,7 @@ /// Represents SSH_MSG_USERAUTH_PASSWD_CHANGEREQ message. /// [Message("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ", 60)] - internal class PasswordChangeRequiredMessage : Message + internal sealed class PasswordChangeRequiredMessage : Message { /// /// Gets password change request message as UTF-8 encoded byte array. diff --git a/src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs b/src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs index 9658a2e05..b5582b788 100644 --- a/src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs @@ -4,7 +4,7 @@ /// Represents SSH_MSG_USERAUTH_PK_OK message. /// [Message("SSH_MSG_USERAUTH_PK_OK", 60)] - internal class PublicKeyMessage : Message + internal sealed class PublicKeyMessage : Message { /// /// Gets the name of the public key algorithm as ASCII encoded byte array. diff --git a/src/Renci.SshNet/Messages/Authentication/RequestMessageKeyboardInteractive.cs b/src/Renci.SshNet/Messages/Authentication/RequestMessageKeyboardInteractive.cs index 6961cb5a3..0b9b0fb68 100644 --- a/src/Renci.SshNet/Messages/Authentication/RequestMessageKeyboardInteractive.cs +++ b/src/Renci.SshNet/Messages/Authentication/RequestMessageKeyboardInteractive.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Messages.Authentication /// /// Represents "keyboard-interactive" SSH_MSG_USERAUTH_REQUEST message. /// - internal class RequestMessageKeyboardInteractive : RequestMessage + internal sealed class RequestMessageKeyboardInteractive : RequestMessage { /// /// Gets message language. diff --git a/src/Renci.SshNet/Messages/Authentication/RequestMessageNone.cs b/src/Renci.SshNet/Messages/Authentication/RequestMessageNone.cs index 77cc55f3a..1827c3299 100644 --- a/src/Renci.SshNet/Messages/Authentication/RequestMessageNone.cs +++ b/src/Renci.SshNet/Messages/Authentication/RequestMessageNone.cs @@ -3,7 +3,7 @@ /// /// Represents "none" SSH_MSG_USERAUTH_REQUEST message. /// - internal class RequestMessageNone : RequestMessage + internal sealed class RequestMessageNone : RequestMessage { /// /// Initializes a new instance of the class. diff --git a/src/Renci.SshNet/Messages/Authentication/RequestMessagePassword.cs b/src/Renci.SshNet/Messages/Authentication/RequestMessagePassword.cs index 881617b85..603342c67 100644 --- a/src/Renci.SshNet/Messages/Authentication/RequestMessagePassword.cs +++ b/src/Renci.SshNet/Messages/Authentication/RequestMessagePassword.cs @@ -3,7 +3,7 @@ /// /// Represents "password" SSH_MSG_USERAUTH_REQUEST message. /// - internal class RequestMessagePassword : RequestMessage + internal sealed class RequestMessagePassword : RequestMessage { /// /// Gets authentication password. diff --git a/src/Renci.SshNet/Messages/Connection/CancelTcpIpForwardGlobalRequestMessage.cs b/src/Renci.SshNet/Messages/Connection/CancelTcpIpForwardGlobalRequestMessage.cs index eaf8c6be2..0b3431c06 100644 --- a/src/Renci.SshNet/Messages/Connection/CancelTcpIpForwardGlobalRequestMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/CancelTcpIpForwardGlobalRequestMessage.cs @@ -2,12 +2,12 @@ namespace Renci.SshNet.Messages.Connection { - internal class CancelTcpIpForwardGlobalRequestMessage : GlobalRequestMessage + internal sealed class CancelTcpIpForwardGlobalRequestMessage : GlobalRequestMessage { private byte[] _addressToBind; public CancelTcpIpForwardGlobalRequestMessage(string addressToBind, uint portToBind) - : base(Ascii.GetBytes("cancel-tcpip-forward"), true) + : base(Ascii.GetBytes("cancel-tcpip-forward"), wantReply: true) { AddressToBind = addressToBind; PortToBind = portToBind; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfo.cs index 7df594542..6901f3241 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfo.cs @@ -3,7 +3,7 @@ /// /// Represents "env" type channel request information /// - internal class EnvironmentVariableRequestInfo : RequestInfo + internal sealed class EnvironmentVariableRequestInfo : RequestInfo { private byte[] _variableName; private byte[] _variableValue; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitSignalRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitSignalRequestInfo.cs index 512f3b97d..114bd577f 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitSignalRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitSignalRequestInfo.cs @@ -3,7 +3,7 @@ /// /// Represents "exit-signal" type channel request information /// - internal class ExitSignalRequestInfo : RequestInfo + internal sealed class ExitSignalRequestInfo : RequestInfo { private byte[] _signalName; private byte[] _errorMessage; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitStatusRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitStatusRequestInfo.cs index 96cc1d061..9aa92f96d 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitStatusRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitStatusRequestInfo.cs @@ -3,7 +3,7 @@ /// /// Represents "exit-status" type channel request information /// - internal class ExitStatusRequestInfo : RequestInfo + internal sealed class ExitStatusRequestInfo : RequestInfo { /// /// Channel request name. diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs index af57bb2d7..fbe5a11dd 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs @@ -7,7 +7,7 @@ namespace Renci.SshNet.Messages.Connection /// /// Represents "pty-req" type channel request information. /// - internal class PseudoTerminalRequestInfo : RequestInfo + internal sealed class PseudoTerminalRequestInfo : RequestInfo { /// /// Channel request name. diff --git a/src/Renci.SshNet/Messages/Connection/TcpIpForwardGlobalRequestMessage.cs b/src/Renci.SshNet/Messages/Connection/TcpIpForwardGlobalRequestMessage.cs index fdfbfb8df..edddcb567 100644 --- a/src/Renci.SshNet/Messages/Connection/TcpIpForwardGlobalRequestMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/TcpIpForwardGlobalRequestMessage.cs @@ -7,7 +7,7 @@ internal sealed class TcpIpForwardGlobalRequestMessage : GlobalRequestMessage private byte[] _addressToBind; public TcpIpForwardGlobalRequestMessage(string addressToBind, uint portToBind) - : base(Ascii.GetBytes("tcpip-forward"), true) + : base(Ascii.GetBytes("tcpip-forward"), wantReply: true) { AddressToBind = addressToBind; PortToBind = portToBind; diff --git a/src/Renci.SshNet/Netconf/NetConfSession.cs b/src/Renci.SshNet/Netconf/NetConfSession.cs index 6e6f8c6c8..f1252f539 100644 --- a/src/Renci.SshNet/Netconf/NetConfSession.cs +++ b/src/Renci.SshNet/Netconf/NetConfSession.cs @@ -9,7 +9,7 @@ namespace Renci.SshNet.NetConf { - internal class NetConfSession : SubsystemSession, INetConfSession + internal sealed class NetConfSession : SubsystemSession, INetConfSession { private const string Prompt = "]]>]]>"; diff --git a/src/Renci.SshNet/NoneAuthenticationMethod.cs b/src/Renci.SshNet/NoneAuthenticationMethod.cs index 71e100175..99d025249 100644 --- a/src/Renci.SshNet/NoneAuthenticationMethod.cs +++ b/src/Renci.SshNet/NoneAuthenticationMethod.cs @@ -12,7 +12,7 @@ namespace Renci.SshNet public class NoneAuthenticationMethod : AuthenticationMethod, IDisposable { private AuthenticationResult _authenticationResult = AuthenticationResult.Failure; - private EventWaitHandle _authenticationCompleted = new AutoResetEvent(false); + private EventWaitHandle _authenticationCompleted = new AutoResetEvent(initialState: false); private bool _isDisposed; /// diff --git a/src/Renci.SshNet/PasswordAuthenticationMethod.cs b/src/Renci.SshNet/PasswordAuthenticationMethod.cs index 5c7e8aaa9..ffa8213d8 100644 --- a/src/Renci.SshNet/PasswordAuthenticationMethod.cs +++ b/src/Renci.SshNet/PasswordAuthenticationMethod.cs @@ -18,7 +18,7 @@ public class PasswordAuthenticationMethod : AuthenticationMethod, IDisposable private readonly byte[] _password; private AuthenticationResult _authenticationResult = AuthenticationResult.Failure; private Session _session; - private EventWaitHandle _authenticationCompleted = new AutoResetEvent(false); + private EventWaitHandle _authenticationCompleted = new AutoResetEvent(initialState: false); private Exception _exception; private bool _isDisposed; diff --git a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs index 1606ef757..960a68b20 100644 --- a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs +++ b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs @@ -15,7 +15,7 @@ namespace Renci.SshNet public class PrivateKeyAuthenticationMethod : AuthenticationMethod, IDisposable { private AuthenticationResult _authenticationResult = AuthenticationResult.Failure; - private EventWaitHandle _authenticationCompleted = new ManualResetEvent(false); + private EventWaitHandle _authenticationCompleted = new ManualResetEvent(initialState: false); private bool _isSignatureRequired; private bool _isDisposed; diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index e00a27fcd..3a2dbe049 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -400,7 +400,7 @@ private static byte[] DecryptKey(CipherInfo cipherInfo, byte[] cipherData, strin /// /// The OpenSSH V1 key. /// - private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) + private static Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) { var keyReader = new SshDataReader(keyFileData); @@ -424,9 +424,9 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) var rounds = 0; if (kdfOptionsLen > 0) { - var saltLength = (int)keyReader.ReadUInt32(); + var saltLength = (int) keyReader.ReadUInt32(); salt = keyReader.ReadBytes(saltLength); - rounds = (int)keyReader.ReadUInt32(); + rounds = (int) keyReader.ReadUInt32(); } // number of public keys, only supporting 1 for now @@ -440,7 +440,7 @@ private Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) _ = keyReader.ReadString(Encoding.UTF8); // possibly encrypted private key - var privateKeyLength = (int)keyReader.ReadUInt32(); + var privateKeyLength = (int) keyReader.ReadUInt32(); var privateKeyBytes = keyReader.ReadBytes(privateKeyLength); // decrypt private key if necessary @@ -602,7 +602,7 @@ protected virtual void Dispose(bool disposing) Dispose(disposing: false); } - private class SshDataReader : SshData + private sealed class SshDataReader : SshData { public SshDataReader(byte[] data) { diff --git a/src/Renci.SshNet/RemotePathDoubleQuoteTransformation.cs b/src/Renci.SshNet/RemotePathDoubleQuoteTransformation.cs index 68abce256..74413eac1 100644 --- a/src/Renci.SshNet/RemotePathDoubleQuoteTransformation.cs +++ b/src/Renci.SshNet/RemotePathDoubleQuoteTransformation.cs @@ -6,7 +6,7 @@ namespace Renci.SshNet /// /// Encloses a path in double quotes, and escapes any embedded double quote with a backslash. /// - internal class RemotePathDoubleQuoteTransformation : IRemotePathTransformation + internal sealed class RemotePathDoubleQuoteTransformation : IRemotePathTransformation { /// /// Encloses a path in double quotes, and escapes any embedded double quote with a backslash. diff --git a/src/Renci.SshNet/RemotePathNoneTransformation.cs b/src/Renci.SshNet/RemotePathNoneTransformation.cs index 31dea7a87..d1937514f 100644 --- a/src/Renci.SshNet/RemotePathNoneTransformation.cs +++ b/src/Renci.SshNet/RemotePathNoneTransformation.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet /// /// Performs no transformation. /// - internal class RemotePathNoneTransformation : IRemotePathTransformation + internal sealed class RemotePathNoneTransformation : IRemotePathTransformation { /// /// Returns the specified path without applying a transformation. diff --git a/src/Renci.SshNet/RemotePathShellQuoteTransformation.cs b/src/Renci.SshNet/RemotePathShellQuoteTransformation.cs index 9f247ccff..7d02d29d6 100644 --- a/src/Renci.SshNet/RemotePathShellQuoteTransformation.cs +++ b/src/Renci.SshNet/RemotePathShellQuoteTransformation.cs @@ -6,7 +6,7 @@ namespace Renci.SshNet /// /// Quotes a path in a way to be suitable to be used with a shell-based server. /// - internal class RemotePathShellQuoteTransformation : IRemotePathTransformation + internal sealed class RemotePathShellQuoteTransformation : IRemotePathTransformation { /// /// Quotes a path in a way to be suitable to be used with a shell-based server. diff --git a/src/Renci.SshNet/Security/BouncyCastle/.editorconfig b/src/Renci.SshNet/Security/BouncyCastle/.editorconfig index 265666760..9440813d4 100644 --- a/src/Renci.SshNet/Security/BouncyCastle/.editorconfig +++ b/src/Renci.SshNet/Security/BouncyCastle/.editorconfig @@ -2,6 +2,5 @@ generated_code = true -# IDE0005: Remove unnecessary using directives -# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0005 -dotnet_diagnostic.IDE0005.severity = none +# Do not reported any diagnostics for "imported" code +dotnet_analyzer_diagnostic.severity = none diff --git a/src/Renci.SshNet/Security/Chaos.NaCl/.editorconfig b/src/Renci.SshNet/Security/Chaos.NaCl/.editorconfig index 265666760..9440813d4 100644 --- a/src/Renci.SshNet/Security/Chaos.NaCl/.editorconfig +++ b/src/Renci.SshNet/Security/Chaos.NaCl/.editorconfig @@ -2,6 +2,5 @@ generated_code = true -# IDE0005: Remove unnecessary using directives -# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0005 -dotnet_diagnostic.IDE0005.severity = none +# Do not reported any diagnostics for "imported" code +dotnet_analyzer_diagnostic.severity = none diff --git a/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs b/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs index 5a06d7a37..62050068d 100644 --- a/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs @@ -66,11 +66,11 @@ protected BlockCipher(byte[] key, byte blockSize, CipherMode mode, CipherPadding /// /// Encrypts the specified data. /// - /// The data. - /// The zero-based offset in at which to begin encrypting. - /// The number of bytes to encrypt from . + /// The data. + /// The zero-based offset in at which to begin encrypting. + /// The number of bytes to encrypt from . /// Encrypted data - public override byte[] Encrypt(byte[] data, int offset, int length) + public override byte[] Encrypt(byte[] input, int offset, int length) { if (length % _blockSize > 0) { @@ -80,7 +80,7 @@ public override byte[] Encrypt(byte[] data, int offset, int length) } var paddingLength = _blockSize - (length % _blockSize); - data = _padding.Pad(data, offset, length, paddingLength); + input = _padding.Pad(input, offset, length, paddingLength); length += paddingLength; offset = 0; } @@ -92,11 +92,11 @@ public override byte[] Encrypt(byte[] data, int offset, int length) { if (_mode is null) { - writtenBytes += EncryptBlock(data, offset + (i * _blockSize), _blockSize, output, i * _blockSize); + writtenBytes += EncryptBlock(input, offset + (i * _blockSize), _blockSize, output, i * _blockSize); } else { - writtenBytes += _mode.EncryptBlock(data, offset + (i * _blockSize), _blockSize, output, i * _blockSize); + writtenBytes += _mode.EncryptBlock(input, offset + (i * _blockSize), _blockSize, output, i * _blockSize); } } @@ -111,23 +111,23 @@ public override byte[] Encrypt(byte[] data, int offset, int length) /// /// Decrypts the specified data. /// - /// The data. + /// The data. /// Decrypted data - public override byte[] Decrypt(byte[] data) + public override byte[] Decrypt(byte[] input) { - return Decrypt(data, 0, data.Length); + return Decrypt(input, 0, input.Length); } /// /// Decrypts the specified input. /// - /// The input. - /// The zero-based offset in at which to begin decrypting. - /// The number of bytes to decrypt from . + /// The input. + /// The zero-based offset in at which to begin decrypting. + /// The number of bytes to decrypt from . /// /// The decrypted data. /// - public override byte[] Decrypt(byte[] data, int offset, int length) + public override byte[] Decrypt(byte[] input, int offset, int length) { if (length % _blockSize > 0) { @@ -136,9 +136,9 @@ public override byte[] Decrypt(byte[] data, int offset, int length) throw new ArgumentException("data"); } - data = _padding.Pad(_blockSize, data, offset, length); + input = _padding.Pad(_blockSize, input, offset, length); offset = 0; - length = data.Length; + length = input.Length; } var output = new byte[length]; @@ -148,11 +148,11 @@ public override byte[] Decrypt(byte[] data, int offset, int length) { if (_mode is null) { - writtenBytes += DecryptBlock(data, offset + (i * _blockSize), _blockSize, output, i * _blockSize); + writtenBytes += DecryptBlock(input, offset + (i * _blockSize), _blockSize, output, i * _blockSize); } else { - writtenBytes += _mode.DecryptBlock(data, offset + (i * _blockSize), _blockSize, output, i * _blockSize); + writtenBytes += _mode.DecryptBlock(input, offset + (i * _blockSize), _blockSize, output, i * _blockSize); } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs index 29e4c42e7..19fd1cd7f 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs @@ -606,7 +606,7 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC throw new IndexOutOfRangeException("output buffer too short"); } - _encryptionKey ??= GenerateWorkingKey(true, Key); + _encryptionKey ??= GenerateWorkingKey(isEncryption: true, Key); UnPackBlock(inputBuffer, inputOffset); @@ -652,7 +652,7 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC throw new IndexOutOfRangeException("output buffer too short"); } - _decryptionKey ??= GenerateWorkingKey(false, Key); + _decryptionKey ??= GenerateWorkingKey(isEncryption: false, Key); UnPackBlock(inputBuffer, inputOffset); diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs index fc2174bf9..9a2562878 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs @@ -18,8 +18,6 @@ public sealed class Arc4Cipher : StreamCipher private int _y; - private byte[] _workingKey; - /// /// Gets the minimum data size. /// @@ -40,12 +38,10 @@ public override byte MinimumSize public Arc4Cipher(byte[] key, bool dischargeFirstBytes) : base(key) { - _workingKey = key; - SetKey(_workingKey); - // The first 1536 bytes of keystream - // generated by the cipher MUST be discarded, and the first byte of the - // first encrypted packet MUST be encrypted using the 1537th byte of - // keystream. + SetKey(key); + + // The first 1536 bytes of keystream generated by the cipher MUST be discarded, and the first byte of the + // first encrypted packet MUST be encrypted using the 1537th byte of keystream. if (dischargeFirstBytes) { _ = Encrypt(new byte[1536]); @@ -159,8 +155,6 @@ private int ProcessBytes(byte[] inputBuffer, int inputOffset, int inputCount, by private void SetKey(byte[] keyBytes) { - _workingKey = keyBytes; - _x = 0; _y = 0; diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs index 1fbe5bc4b..29097eea7 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs @@ -245,7 +245,7 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC throw new IndexOutOfRangeException("output buffer too short"); } - _encryptionKey ??= GenerateWorkingKey(true, Key); + _encryptionKey ??= GenerateWorkingKey(encrypting: true, Key); DesFunc(_encryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset); @@ -275,7 +275,7 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC throw new IndexOutOfRangeException("output buffer too short"); } - _decryptionKey ??= GenerateWorkingKey(false, Key); + _decryptionKey ??= GenerateWorkingKey(encrypting: false, Key); DesFunc(_decryptionKey, inputBuffer, inputOffset, outputBuffer, outputOffset); diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs index d3644ba3b..fda7fc5b5 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs @@ -30,11 +30,11 @@ public RsaCipher(RsaKey key) /// /// Encrypts the specified data. /// - /// The data. - /// The zero-based offset in at which to begin encrypting. - /// The number of bytes to encrypt from . + /// The data. + /// The zero-based offset in at which to begin encrypting. + /// The number of bytes to encrypt from . /// Encrypted data. - public override byte[] Encrypt(byte[] data, int offset, int length) + public override byte[] Encrypt(byte[] input, int offset, int length) { // Calculate signature var bitLength = _key.Modulus.BitLength; @@ -47,7 +47,7 @@ public override byte[] Encrypt(byte[] data, int offset, int length) paddedBlock[i] = 0xFF; } - Buffer.BlockCopy(data, offset, paddedBlock, paddedBlock.Length - length, length); + Buffer.BlockCopy(input, offset, paddedBlock, paddedBlock.Length - length, length); return Transform(paddedBlock); } @@ -55,31 +55,31 @@ public override byte[] Encrypt(byte[] data, int offset, int length) /// /// Decrypts the specified data. /// - /// The data. + /// The data. /// /// The decrypted data. /// /// Only block type 01 or 02 are supported. /// Thrown when decrypted block type is not supported. - public override byte[] Decrypt(byte[] data) + public override byte[] Decrypt(byte[] input) { - return Decrypt(data, 0, data.Length); + return Decrypt(input, 0, input.Length); } /// /// Decrypts the specified input. /// - /// The input. - /// The zero-based offset in at which to begin decrypting. - /// The number of bytes to decrypt from . + /// The input. + /// The zero-based offset in at which to begin decrypting. + /// The number of bytes to decrypt from . /// /// The decrypted data. /// /// Only block type 01 or 02 are supported. /// Thrown when decrypted block type is not supported. - public override byte[] Decrypt(byte[] data, int offset, int length) + public override byte[] Decrypt(byte[] input, int offset, int length) { - var paddedBlock = Transform(data, offset, length); + var paddedBlock = Transform(input, offset, length); if (paddedBlock[0] is not 1 and not 2) { diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs index 3d52e2a26..644d44720 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs @@ -57,16 +57,15 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC Buffer.BlockCopy(Key, 0, part1, 0, 8); Buffer.BlockCopy(Key, 8, part2, 0, 8); - _encryptionKey1 = GenerateWorkingKey(true, part1); - - _encryptionKey2 = GenerateWorkingKey(false, part2); + _encryptionKey1 = GenerateWorkingKey(encrypting: true, part1); + _encryptionKey2 = GenerateWorkingKey(encrypting: false, part2); if (Key.Length == 24) { var part3 = new byte[8]; Buffer.BlockCopy(Key, 16, part3, 0, 8); - _encryptionKey3 = GenerateWorkingKey(true, part3); + _encryptionKey3 = GenerateWorkingKey(encrypting: true, part3); } else { @@ -114,15 +113,15 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC Buffer.BlockCopy(Key, 0, part1, 0, 8); Buffer.BlockCopy(Key, 8, part2, 0, 8); - _decryptionKey1 = GenerateWorkingKey(false, part1); - _decryptionKey2 = GenerateWorkingKey(true, part2); + _decryptionKey1 = GenerateWorkingKey(encrypting: false, part1); + _decryptionKey2 = GenerateWorkingKey(encrypting: true, part2); if (Key.Length == 24) { var part3 = new byte[8]; Buffer.BlockCopy(Key, 16, part3, 0, 8); - _decryptionKey3 = GenerateWorkingKey(false, part3); + _decryptionKey3 = GenerateWorkingKey(encrypting: false, part3); } else { diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs index 48446c52d..93fc6ba4a 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs @@ -108,7 +108,7 @@ protected virtual void Dispose(bool disposing) } } - internal class SshDataSignature : SshData + internal sealed class SshDataSignature : SshData { private readonly int _signature_size; diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs index 3de4beac5..0958ef0ce 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -28,7 +28,7 @@ public class EcdsaKey : Key, IDisposable #if NETFRAMEWORK private CngKey _key; - internal enum KeyBlobMagicNumber : int + internal enum KeyBlobMagicNumber { BCRYPT_ECDSA_PUBLIC_P256_MAGIC = 0x31534345, BCRYPT_ECDSA_PRIVATE_P256_MAGIC = 0x32534345, @@ -180,7 +180,7 @@ public override BigInteger[] Public } #pragma warning restore IDE0010 // Add missing cases #else - var parameter = Ecdsa.ExportParameters(false); + var parameter = Ecdsa.ExportParameters(includePrivateParameters: false); qx = parameter.Q.X; qy = parameter.Q.Y; switch (parameter.Curve.Oid.FriendlyName) @@ -218,7 +218,7 @@ public override BigInteger[] Public var curve_oid = GetCurveOid(curve_s); var publickey = value[1].ToByteArray().Reverse(); - Import(curve_oid, publickey, null); + Import(curve_oid, publickey, privatekey: null); } } @@ -278,7 +278,7 @@ public EcdsaKey(byte[] data) var construct = der.ReadBytes(der.ReadLength()); // object length // curve OID - var curve_der = new DerData(construct, true); + var curve_der = new DerData(construct, construct: true); var curve = curve_der.ReadObject(); // Construct @@ -297,7 +297,7 @@ public EcdsaKey(byte[] data) construct = der.ReadBytes(der.ReadLength()); // object length // PublicKey - var pubkey_der = new DerData(construct, true); + var pubkey_der = new DerData(construct, construct: true); var pubkey = pubkey_der.ReadBitString().TrimLeadingZeros(); Import(OidByteArrayToString(curve), pubkey, privatekey); @@ -306,7 +306,8 @@ public EcdsaKey(byte[] data) private void Import(string curve_oid, byte[] publickey, byte[] privatekey) { #if NETFRAMEWORK - var curve_magic = KeyBlobMagicNumber.BCRYPT_ECDH_PRIVATE_GENERIC_MAGIC; + KeyBlobMagicNumber curve_magic; + switch (GetCurveName(curve_oid)) { case "nistp256": @@ -426,7 +427,7 @@ private static string GetCurveOid(string curve_s) } #if NETFRAMEWORK - private string GetCurveName(string oid) + private static string GetCurveName(string oid) { switch (oid) { diff --git a/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs index 25a375f6b..9af398b46 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs @@ -44,7 +44,7 @@ protected override byte[] Hash(byte[] input) /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } @@ -78,7 +78,7 @@ protected virtual void Dispose(bool disposing) /// ~RsaDigitalSignature() { - Dispose(false); + Dispose(disposing: false); } #endregion diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs index 6d0180114..dbb5ebb02 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs @@ -244,7 +244,7 @@ private static BigInteger PrimeExponent(BigInteger privateExponent, BigInteger p /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } @@ -278,7 +278,7 @@ protected virtual void Dispose(bool disposing) /// ~RsaKey() { - Dispose(false); + Dispose(disposing: false); } } } diff --git a/src/Renci.SshNet/Security/GroupExchangeHashData.cs b/src/Renci.SshNet/Security/GroupExchangeHashData.cs index 12b5fbf11..82b889bb8 100644 --- a/src/Renci.SshNet/Security/GroupExchangeHashData.cs +++ b/src/Renci.SshNet/Security/GroupExchangeHashData.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Security { - internal class GroupExchangeHashData : SshData + internal sealed class GroupExchangeHashData : SshData { private byte[] _serverVersion; private byte[] _clientVersion; diff --git a/src/Renci.SshNet/Security/KeyExchange.cs b/src/Renci.SshNet/Security/KeyExchange.cs index 194358271..771ac6bf4 100644 --- a/src/Renci.SshNet/Security/KeyExchange.cs +++ b/src/Renci.SshNet/Security/KeyExchange.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Security.Cryptography; + using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Compression; @@ -483,7 +484,7 @@ protected override void SaveData() /// public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } @@ -501,7 +502,7 @@ protected virtual void Dispose(bool disposing) /// ~KeyExchange() { - Dispose(false); + Dispose(disposing: false); } #endregion diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs index 3302d9a94..2e286345c 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeSha256.cs @@ -29,15 +29,15 @@ protected override int HashSize /// /// Hashes the specified data bytes. /// - /// Data to hash. + /// Data to hash. /// /// The hash of the data. /// - protected override byte[] Hash(byte[] hashBytes) + protected override byte[] Hash(byte[] hashData) { using (var sha256 = CryptoAbstraction.CreateSHA256()) { - return sha256.ComputeHash(hashBytes); + return sha256.ComputeHash(hashData); } } } diff --git a/src/Renci.SshNet/ServiceFactory.cs b/src/Renci.SshNet/ServiceFactory.cs index 210df0229..16568faf2 100644 --- a/src/Renci.SshNet/ServiceFactory.cs +++ b/src/Renci.SshNet/ServiceFactory.cs @@ -122,10 +122,10 @@ public ISftpFileReader CreateSftpFileReader(string fileName, ISftpSession sftpSe // Issue #292: Avoid overlapping SSH_FXP_OPEN and SSH_FXP_LSTAT requests for the same file as this // causes a performance degradation on Sun SSH - var openAsyncResult = sftpSession.BeginOpen(fileName, Flags.Read, null, null); + var openAsyncResult = sftpSession.BeginOpen(fileName, Flags.Read, callback: null, state: null); var handle = sftpSession.EndOpen(openAsyncResult); - var statAsyncResult = sftpSession.BeginLStat(fileName, null, null); + var statAsyncResult = sftpSession.BeginLStat(fileName, callback: null, state: null); long? fileSize; int maxPendingReads; diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index 02013bd22..9fec6bd7e 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -870,23 +870,6 @@ void ISession.WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout) WaitOnHandle(waitHandle, timeout); } - /// - /// Waits for the specified handle or the exception handle for the receive thread - /// to signal within the connection timeout. - /// - /// The wait handle. - /// A received package was invalid or failed the message integrity check. - /// None of the handles are signaled in time and the session is not disconnecting. - /// A socket error was signaled while receiving messages from the server. - /// - /// When neither handles are signaled in time and the session is not closing, then the - /// session is disconnected. - /// - internal void WaitOnHandle(WaitHandle waitHandle) - { - WaitOnHandle(waitHandle, ConnectionInfo.Timeout); - } - /// /// Waits for the specified to receive a signal, using a /// to specify the time interval. @@ -965,6 +948,23 @@ private WaitResult TryWait(WaitHandle waitHandle, TimeSpan timeout, out Exceptio } } + /// + /// Waits for the specified handle or the exception handle for the receive thread + /// to signal within the connection timeout. + /// + /// The wait handle. + /// A received package was invalid or failed the message integrity check. + /// None of the handles are signaled in time and the session is not disconnecting. + /// A socket error was signaled while receiving messages from the server. + /// + /// When neither handles are signaled in time and the session is not closing, then the + /// session is disconnected. + /// + internal void WaitOnHandle(WaitHandle waitHandle) + { + WaitOnHandle(waitHandle, ConnectionInfo.Timeout); + } + /// /// Waits for the specified handle or the exception handle for the receive thread /// to signal within the specified timeout. @@ -1869,8 +1869,7 @@ private void MessageListener() var message = ReceiveMessage(socket); if (message is null) { - // connection with SSH server was closed; - // break out of the message loop + // Connection with SSH server was closed, so break out of the message loop break; } diff --git a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/FStatVfsRequest.cs b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/FStatVfsRequest.cs index 49341e89a..685c03692 100644 --- a/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/FStatVfsRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/ExtendedRequests/FStatVfsRequest.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Sftp.Requests { - internal class FStatVfsRequest : SftpExtendedRequest + internal sealed class FStatVfsRequest : SftpExtendedRequest { private readonly Action _extendedReplyAction; diff --git a/src/Renci.SshNet/Sftp/Responses/SftpExtendedReplyResponse.cs b/src/Renci.SshNet/Sftp/Responses/SftpExtendedReplyResponse.cs index 1a7048ec5..bbd41680f 100644 --- a/src/Renci.SshNet/Sftp/Responses/SftpExtendedReplyResponse.cs +++ b/src/Renci.SshNet/Sftp/Responses/SftpExtendedReplyResponse.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.Sftp.Responses { - internal class SftpExtendedReplyResponse : SftpResponse + internal sealed class SftpExtendedReplyResponse : SftpResponse { public override SftpMessageTypes SftpMessageType { diff --git a/src/Renci.SshNet/Sftp/SftpFileReader.cs b/src/Renci.SshNet/Sftp/SftpFileReader.cs index ca8ed29d1..9d44bb330 100644 --- a/src/Renci.SshNet/Sftp/SftpFileReader.cs +++ b/src/Renci.SshNet/Sftp/SftpFileReader.cs @@ -8,7 +8,7 @@ namespace Renci.SshNet.Sftp { - internal class SftpFileReader : ISftpFileReader + internal sealed class SftpFileReader : ISftpFileReader { private const int ReadAheadWaitTimeoutInMilliseconds = 1000; @@ -64,8 +64,8 @@ public SftpFileReader(byte[] handle, ISftpSession sftpSession, uint chunkSize, i _semaphore = new SemaphoreLight(maxPendingReads); _queue = new Dictionary(maxPendingReads); _readLock = new object(); - _readAheadCompleted = new ManualResetEvent(false); - _disposingWaitHandle = new ManualResetEvent(false); + _readAheadCompleted = new ManualResetEvent(initialState: false); + _disposingWaitHandle = new ManualResetEvent(initialState: false); _waitHandles = _sftpSession.CreateWaitHandleArray(_disposingWaitHandle, _semaphore.AvailableWaitHandle); StartReadAhead(); @@ -78,7 +78,7 @@ public byte[] Read() throw new ObjectDisposedException(GetType().FullName); } - if (_exception != null) + if (_exception is not null) { throw _exception; } @@ -133,9 +133,9 @@ public byte[] Read() return data; } - // when we received an EOF for the next chunk and the size of the file is known, then - // we only complete the current chunk if we haven't already read up to the file size; - // this way we save an extra round-trip to the server + // When we received an EOF for the next chunk and the size of the file is known, then + // we only complete the current chunk if we haven't already read up to the file size. + // This way we save an extra round-trip to the server. if (data.Length == 0 && _fileSize.HasValue && _offset == (ulong) _fileSize.Value) { // avoid future reads @@ -214,12 +214,12 @@ public byte[] Read() ~SftpFileReader() { - Dispose(false); + Dispose(disposing: false); } public void Dispose() { - Dispose(true); + Dispose(disposing: true); GC.SuppressFinalize(this); } @@ -227,7 +227,7 @@ public void Dispose() /// Releases unmanaged and - optionally - managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. - protected void Dispose(bool disposing) + private void Dispose(bool disposing) { if (_disposingOrDisposed) { @@ -266,7 +266,7 @@ protected void Dispose(bool disposing) { try { - var closeAsyncResult = _sftpSession.BeginClose(_handle, null, null); + var closeAsyncResult = _sftpSession.BeginClose(_handle, callback: null, state: null); _sftpSession.EndClose(closeAsyncResult); } catch (Exception ex) @@ -329,7 +329,7 @@ private void StartReadAhead() // mode to avoid having multiple read-aheads that read beyond EOF if (_fileSize != null && (long) _readAheadOffset > _fileSize.Value) { - var asyncResult = _sftpSession.BeginRead(_handle, _readAheadOffset, _chunkSize, null, bufferedRead); + var asyncResult = _sftpSession.BeginRead(_handle, _readAheadOffset, _chunkSize, callback: null, bufferedRead); var data = _sftpSession.EndRead(asyncResult); ReadCompletedCore(bufferedRead, data); } @@ -421,8 +421,8 @@ private void ReadCompletedCore(BufferedRead bufferedRead, byte[] data) // add item to queue _queue.Add(bufferedRead.ChunkIndex, bufferedRead); - // signal that a chunk has been read or EOF has been reached; - // in both cases, Read() will eventually also unblock the "read-ahead" thread + // Signal that a chunk has been read or EOF has been reached. + // In both cases, Read() will eventually also unblock the "read-ahead" thread. Monitor.PulseAll(_readLock); } diff --git a/src/Renci.SshNet/Sftp/SftpFileStream.cs b/src/Renci.SshNet/Sftp/SftpFileStream.cs index 26e22ee88..a17d5b8ee 100644 --- a/src/Renci.SshNet/Sftp/SftpFileStream.cs +++ b/src/Renci.SshNet/Sftp/SftpFileStream.cs @@ -193,8 +193,8 @@ private SftpFileStream(ISftpSession session, string path, FileAccess access, int * or SSH_FXP_WRITE message. */ - _readBufferSize = (int) session.CalculateOptimalReadLength((uint)bufferSize); - _writeBufferSize = (int) session.CalculateOptimalWriteLength((uint)bufferSize, _handle); + _readBufferSize = (int) session.CalculateOptimalReadLength((uint) bufferSize); + _writeBufferSize = (int) session.CalculateOptimalWriteLength((uint) bufferSize, _handle); _position = position; } diff --git a/src/Renci.SshNet/Sftp/SftpSession.cs b/src/Renci.SshNet/Sftp/SftpSession.cs index c43a7af96..77355d4a5 100644 --- a/src/Renci.SshNet/Sftp/SftpSession.cs +++ b/src/Renci.SshNet/Sftp/SftpSession.cs @@ -11,7 +11,7 @@ namespace Renci.SshNet.Sftp { - internal class SftpSession : SubsystemSession, ISftpSession + internal sealed class SftpSession : SubsystemSession, ISftpSession { internal const int MaximumSupportedVersion = 3; private const int MinimumSupportedVersion = 0; @@ -19,14 +19,10 @@ internal class SftpSession : SubsystemSession, ISftpSession private readonly Dictionary _requests = new Dictionary(); private readonly ISftpResponseFactory _sftpResponseFactory; private readonly List _data = new List(32 * 1024); + private readonly Encoding _encoding; private EventWaitHandle _sftpVersionConfirmed = new AutoResetEvent(initialState: false); private IDictionary _supportedExtensions; - /// - /// Gets the character encoding to use. - /// - protected Encoding Encoding { get; private set; } - /// /// Gets the remote working directory. /// @@ -66,7 +62,7 @@ public uint NextRequestId public SftpSession(ISession session, int operationTimeout, Encoding encoding, ISftpResponseFactory sftpResponseFactory) : base(session, "sftp", operationTimeout) { - Encoding = encoding; + _encoding = encoding; _sftpResponseFactory = sftpResponseFactory; } @@ -363,7 +359,7 @@ protected override void OnDataReceived(byte[] data) private bool TryLoadSftpMessage(byte[] packetData, int offset, int count) { // Create SFTP message - var response = _sftpResponseFactory.Create(ProtocolVersion, packetData[offset], Encoding); + var response = _sftpResponseFactory.Create(ProtocolVersion, packetData[offset], _encoding); // Load message data into it response.Load(packetData, offset + 1, count - 1); @@ -433,7 +429,7 @@ public byte[] RequestOpen(string path, Flags flags, bool nullOnError = false) var request = new SftpOpenRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, flags, response => { @@ -470,7 +466,7 @@ public async Task RequestOpenAsync(string path, Flags flags, Cancellatio SendRequest(new SftpOpenRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, flags, response => tcs.TrySetResult(response.Handle), response => tcs.TrySetException(GetSftpException(response)))); @@ -496,7 +492,7 @@ public SftpOpenAsyncResult BeginOpen(string path, Flags flags, AsyncCallback cal var request = new SftpOpenRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, flags, response => { @@ -624,7 +620,7 @@ public SftpCloseAsyncResult BeginClose(byte[] handle, AsyncCallback callback, ob handle, response => { - asyncResult.SetAsCompleted(GetSftpException(response), false); + asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false); }); SendRequest(request); @@ -919,7 +915,7 @@ public SftpFileAttributes RequestLStat(string path) var request = new SftpLStatRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => { attributes = response.Attributes; @@ -960,7 +956,7 @@ public SFtpStatAsyncResult BeginLStat(string path, AsyncCallback callback, objec var request = new SftpLStatRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => { asyncResult.SetAsCompleted(response.Attributes, completedSynchronously: false); @@ -1080,7 +1076,7 @@ public void RequestSetStat(string path, SftpFileAttributes attributes) var request = new SftpSetStatRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, attributes, response => { @@ -1148,7 +1144,7 @@ public byte[] RequestOpenDir(string path, bool nullOnError = false) var request = new SftpOpenDirRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => { handle = response.Handle; @@ -1184,7 +1180,7 @@ public async Task RequestOpenDirAsync(string path, CancellationToken can SendRequest(new SftpOpenDirRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => tcs.TrySetResult(response.Handle), response => tcs.TrySetException(GetSftpException(response)))); @@ -1277,7 +1273,7 @@ public void RequestRemove(string path) var request = new SftpRemoveRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => { exception = GetSftpException(response); @@ -1306,7 +1302,7 @@ public async Task RequestRemoveAsync(string path, CancellationToken cancellation SendRequest(new SftpRemoveRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => { if (response.StatusCode == StatusCodes.Ok) @@ -1336,7 +1332,7 @@ public void RequestMkDir(string path) var request = new SftpMkDirRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => { exception = GetSftpException(response); @@ -1367,7 +1363,7 @@ public void RequestRmDir(string path) var request = new SftpRmDirRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => { exception = GetSftpException(response); @@ -1404,7 +1400,7 @@ internal KeyValuePair[] RequestRealPath(string path, var request = new SftpRealPathRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => { result = response.Files; @@ -1440,7 +1436,7 @@ internal async Task[]> RequestRealPathA SendRequest(new SftpRealPathRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => tcs.TrySetResult(response.Files), response => { @@ -1474,7 +1470,7 @@ public SftpRealPathAsyncResult BeginRealPath(string path, AsyncCallback callback var request = new SftpRealPathRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => asyncResult.SetAsCompleted(response.Files[0].Key, completedSynchronously: false), response => asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false)); SendRequest(request); @@ -1533,7 +1529,7 @@ public SftpFileAttributes RequestStat(string path, bool nullOnError = false) var request = new SftpStatRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => { attributes = response.Attributes; @@ -1574,7 +1570,7 @@ public SFtpStatAsyncResult BeginStat(string path, AsyncCallback callback, object var request = new SftpStatRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => asyncResult.SetAsCompleted(response.Attributes, completedSynchronously: false), response => asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false)); SendRequest(request); @@ -1634,7 +1630,7 @@ public void RequestRename(string oldPath, string newPath) NextRequestId, oldPath, newPath, - Encoding, + _encoding, response => { exception = GetSftpException(response); @@ -1664,7 +1660,7 @@ public async Task RequestRenameAsync(string oldPath, string newPath, Cancellatio NextRequestId, oldPath, newPath, - Encoding, + _encoding, response => { if (response.StatusCode == StatusCodes.Ok) @@ -1703,7 +1699,7 @@ internal KeyValuePair[] RequestReadLink(string path, var request = new SftpReadLinkRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => { result = response.Files; @@ -1748,7 +1744,7 @@ public void RequestSymLink(string linkpath, string targetpath) NextRequestId, linkpath, targetpath, - Encoding, + _encoding, response => { exception = GetSftpException(response); @@ -1786,7 +1782,7 @@ public void RequestPosixRename(string oldPath, string newPath) NextRequestId, oldPath, newPath, - Encoding, + _encoding, response => { exception = GetSftpException(response); @@ -1833,7 +1829,7 @@ public SftpFileSytemInformation RequestStatVfs(string path, bool nullOnError = f var request = new StatVfsRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => { information = response.GetReply().Information; @@ -1879,7 +1875,7 @@ public async Task RequestStatVfsAsync(string path, Can SendRequest(new StatVfsRequest(ProtocolVersion, NextRequestId, path, - Encoding, + _encoding, response => tcs.TrySetResult(response.GetReply().Information), response => tcs.TrySetException(GetSftpException(response)))); diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 8190df20c..9fe19235a 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -18,7 +18,7 @@ namespace Renci.SshNet /// public class SftpClient : BaseClient, ISftpClient { - private static readonly Encoding Utf8NoBOM = new UTF8Encoding(false, true); + private static readonly Encoding Utf8NoBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true); /// /// Holds the instance that is used to communicate to the @@ -171,7 +171,7 @@ internal ISftpSession SftpSession /// The connection info. /// is null. public SftpClient(ConnectionInfo connectionInfo) - : this(connectionInfo, false) + : this(connectionInfo, ownsConnectionInfo: false) { } @@ -187,7 +187,7 @@ public SftpClient(ConnectionInfo connectionInfo) /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] public SftpClient(string host, int port, string username, string password) - : this(new PasswordConnectionInfo(host, port, username, password), true) + : this(new PasswordConnectionInfo(host, port, username, password), ownsConnectionInfo: true) { } @@ -216,7 +216,7 @@ public SftpClient(string host, string username, string password) /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] public SftpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) - : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), true) + : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -443,7 +443,7 @@ public async Task DeleteFileAsync(string path, CancellationToken cancellationTok /// The method was called after the client was disposed. public void RenameFile(string oldPath, string newPath) { - RenameFile(oldPath, newPath, false); + RenameFile(oldPath, newPath, isPosix: false); } /// @@ -464,12 +464,12 @@ public async Task RenameFileAsync(string oldPath, string newPath, CancellationTo if (oldPath is null) { - throw new ArgumentNullException("oldPath"); + throw new ArgumentNullException(nameof(oldPath)); } if (newPath is null) { - throw new ArgumentNullException("newPath"); + throw new ArgumentNullException(nameof(newPath)); } if (_sftpSession is null) @@ -501,12 +501,12 @@ public void RenameFile(string oldPath, string newPath, bool isPosix) if (oldPath is null) { - throw new ArgumentNullException("oldPath"); + throw new ArgumentNullException(nameof(oldPath)); } if (newPath is null) { - throw new ArgumentNullException("newPath"); + throw new ArgumentNullException(nameof(newPath)); } if (_sftpSession is null) @@ -604,7 +604,7 @@ public async Task> ListDirectoryAsync(string path, Cancel if (path is null) { - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(path)); } if (_sftpSession is null) @@ -675,11 +675,11 @@ public IAsyncResult BeginListDirectory(string path, AsyncCallback asyncCallback, listCallback?.Invoke(count); }); - asyncResult.SetAsCompleted(result, false); + asyncResult.SetAsCompleted(result, completedSynchronously: false); } catch (Exception exp) { - asyncResult.SetAsCompleted(exp, false); + asyncResult.SetAsCompleted(exp, completedSynchronously: false); } }); @@ -722,7 +722,7 @@ public ISftpFile Get(string path) if (path is null) { - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(path)); } if (_sftpSession is null) @@ -813,7 +813,7 @@ public void DownloadFile(string path, Stream output, Action downloadCallb { CheckDisposed(); - InternalDownloadFile(path, output, null, downloadCallback); + InternalDownloadFile(path, output, asyncResult: null, downloadCallback); } /// @@ -835,7 +835,7 @@ public void DownloadFile(string path, Stream output, Action downloadCallb /// public IAsyncResult BeginDownloadFile(string path, Stream output) { - return BeginDownloadFile(path, output, null, null); + return BeginDownloadFile(path, output, asyncCallback: null, state: null); } /// @@ -858,7 +858,7 @@ public IAsyncResult BeginDownloadFile(string path, Stream output) /// public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback asyncCallback) { - return BeginDownloadFile(path, output, asyncCallback, null); + return BeginDownloadFile(path, output, asyncCallback, state: null); } /// @@ -889,7 +889,7 @@ public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback if (output is null) { - throw new ArgumentNullException("output"); + throw new ArgumentNullException(nameof(output)); } var asyncResult = new SftpDownloadAsyncResult(asyncCallback, state); @@ -905,11 +905,11 @@ public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback downloadCallback?.Invoke(offset); }); - asyncResult.SetAsCompleted(null, false); + asyncResult.SetAsCompleted(exception: null, completedSynchronously: false); } catch (Exception exp) { - asyncResult.SetAsCompleted(exp, false); + asyncResult.SetAsCompleted(exp, completedSynchronously: false); } }); @@ -953,7 +953,7 @@ public void EndDownloadFile(IAsyncResult asyncResult) /// public void UploadFile(Stream input, string path, Action uploadCallback = null) { - UploadFile(input, path, true, uploadCallback); + UploadFile(input, path, canOverride: true, uploadCallback); } /// @@ -987,7 +987,7 @@ public void UploadFile(Stream input, string path, bool canOverride, Action @@ -1014,7 +1014,7 @@ public void UploadFile(Stream input, string path, bool canOverride, Action public IAsyncResult BeginUploadFile(Stream input, string path) { - return BeginUploadFile(input, path, true, null, null); + return BeginUploadFile(input, path, canOverride: true, asyncCallback: null, state: null); } /// @@ -1042,7 +1042,7 @@ public IAsyncResult BeginUploadFile(Stream input, string path) /// public IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback asyncCallback) { - return BeginUploadFile(input, path, true, asyncCallback, null); + return BeginUploadFile(input, path, canOverride: true, asyncCallback, state: null); } /// @@ -1072,7 +1072,7 @@ public IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback asy /// public IAsyncResult BeginUploadFile(Stream input, string path, AsyncCallback asyncCallback, object state, Action uploadCallback = null) { - return BeginUploadFile(input, path, true, asyncCallback, state, uploadCallback); + return BeginUploadFile(input, path, canOverride: true, asyncCallback, state, uploadCallback); } /// @@ -1106,7 +1106,7 @@ public IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride, if (input is null) { - throw new ArgumentNullException("input"); + throw new ArgumentNullException(nameof(input)); } if (path.IsNullOrWhiteSpace()) @@ -1132,18 +1132,16 @@ public IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride, try { InternalUploadFile(input, path, flags, asyncResult, offset => - { - asyncResult.Update(offset); - - uploadCallback?.Invoke(offset); - - }); + { + asyncResult.Update(offset); + uploadCallback?.Invoke(offset); + }); - asyncResult.SetAsCompleted(null, false); + asyncResult.SetAsCompleted(exception: null, completedSynchronously: false); } catch (Exception exp) { - asyncResult.SetAsCompleted(exp, false); + asyncResult.SetAsCompleted(exception: exp, completedSynchronously: false); } }); @@ -1186,7 +1184,7 @@ public SftpFileSytemInformation GetStatus(string path) if (path is null) { - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(path)); } if (_sftpSession is null) @@ -1217,7 +1215,7 @@ public async Task GetStatusAsync(string path, Cancella if (path is null) { - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(path)); } if (_sftpSession is null) @@ -1251,7 +1249,7 @@ public void AppendAllLines(string path, IEnumerable contents) if (contents is null) { - throw new ArgumentNullException("contents"); + throw new ArgumentNullException(nameof(contents)); } using (var stream = AppendText(path)) @@ -1279,7 +1277,7 @@ public void AppendAllLines(string path, IEnumerable contents, Encoding e if (contents is null) { - throw new ArgumentNullException("contents"); + throw new ArgumentNullException(nameof(contents)); } using (var stream = AppendText(path, encoding)) @@ -1366,7 +1364,7 @@ public StreamWriter AppendText(string path, Encoding encoding) if (encoding is null) { - throw new ArgumentNullException("encoding"); + throw new ArgumentNullException(nameof(encoding)); } return new StreamWriter(new SftpFileStream(_sftpSession, path, FileMode.Append, FileAccess.Write, (int) _bufferSize), encoding); @@ -1604,7 +1602,7 @@ public Task OpenAsync(string path, FileMode mode, FileAccess acc if (path is null) { - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(path)); } if (_sftpSession is null) @@ -2105,7 +2103,7 @@ public IEnumerable SynchronizeDirectories(string sourcePath, string de { if (sourcePath is null) { - throw new ArgumentNullException("sourcePath"); + throw new ArgumentNullException(nameof(sourcePath)); } if (destinationPath.IsNullOrWhiteSpace()) @@ -2113,7 +2111,7 @@ public IEnumerable SynchronizeDirectories(string sourcePath, string de throw new ArgumentException("destinationPath"); } - return InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, null); + return InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asynchResult: null); } /// @@ -2134,7 +2132,7 @@ public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destin { if (sourcePath is null) { - throw new ArgumentNullException("sourcePath"); + throw new ArgumentNullException(nameof(sourcePath)); } if (destinationPath.IsNullOrWhiteSpace()) @@ -2145,18 +2143,18 @@ public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destin var asyncResult = new SftpSynchronizeDirectoriesAsyncResult(asyncCallback, state); ThreadAbstraction.ExecuteThread(() => - { - try { - var result = InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asyncResult); + try + { + var result = InternalSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asyncResult); - asyncResult.SetAsCompleted(result, false); - } - catch (Exception exp) - { - asyncResult.SetAsCompleted(exp, false); - } - }); + asyncResult.SetAsCompleted(result, completedSynchronously: false); + } + catch (Exception exp) + { + asyncResult.SetAsCompleted(exp, completedSynchronously: false); + } + }); return asyncResult; } @@ -2201,7 +2199,7 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, #region Existing Files at The Destination - var destFiles = InternalListDirectory(destinationPath, null); + var destFiles = InternalListDirectory(destinationPath, listCallback: null); var destDict = new Dictionary(); foreach (var destFile in destFiles) { @@ -2241,7 +2239,7 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, { using (var file = File.OpenRead(localFile.FullName)) { - InternalUploadFile(file, remoteFileName, uploadFlag, null, null); + InternalUploadFile(file, remoteFileName, uploadFlag, asyncResult: null, uploadCallback: null); } uploadedFiles.Add(localFile); @@ -2278,7 +2276,7 @@ private IEnumerable InternalListDirectory(string path, Action li { if (path is null) { - throw new ArgumentNullException("path"); + throw new ArgumentNullException(nameof(path)); } if (_sftpSession is null) @@ -2301,7 +2299,7 @@ private IEnumerable InternalListDirectory(string path, Action li var files = _sftpSession.RequestReadDir(handle); - while (files != null) + while (files is not null) { foreach (var f in files) { @@ -2311,7 +2309,7 @@ private IEnumerable InternalListDirectory(string path, Action li } // Call callback to report number of files read - if (listCallback != null) + if (listCallback is not null) { // Execute callback on different thread ThreadAbstraction.ExecuteThread(() => listCallback(result.Count)); @@ -2339,7 +2337,7 @@ private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncR { if (output is null) { - throw new ArgumentNullException("output"); + throw new ArgumentNullException(nameof(output)); } if (path.IsNullOrWhiteSpace()) @@ -2360,8 +2358,8 @@ private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncR while (true) { - // Cancel download - if (asyncResult != null && asyncResult.IsDownloadCanceled) + // Cancel download + if (asyncResult is not null && asyncResult.IsDownloadCanceled) { break; } @@ -2376,7 +2374,7 @@ private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncR totalBytesRead += (ulong) data.Length; - if (downloadCallback != null) + if (downloadCallback is not null) { // copy offset to ensure it's not modified between now and execution of callback var downloadOffset = totalBytesRead; @@ -2403,7 +2401,7 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo { if (input is null) { - throw new ArgumentNullException("input"); + throw new ArgumentNullException(nameof(input)); } if (path.IsNullOrWhiteSpace()) @@ -2427,12 +2425,12 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo var bytesRead = input.Read(buffer, 0, buffer.Length); var expectedResponses = 0; - var responseReceivedWaitHandle = new AutoResetEvent(false); + var responseReceivedWaitHandle = new AutoResetEvent(initialState: false); do { - // Cancel upload - if (asyncResult != null && asyncResult.IsUploadCanceled) + // Cancel upload + if (asyncResult is not null && asyncResult.IsUploadCanceled) { break; } @@ -2441,7 +2439,7 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo { var writtenBytes = offset + (ulong) bytesRead; - _sftpSession.RequestWrite(handle, offset, buffer, 0, bytesRead, null, s => + _sftpSession.RequestWrite(handle, offset, buffer, offset: 0, bytesRead, wait: null, s => { if (s.StatusCode == StatusCodes.Ok) { @@ -2449,7 +2447,7 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo _ = responseReceivedWaitHandle.Set(); // Call callback to report number of bytes written - if (uploadCallback != null) + if (uploadCallback is not null) { // Execute callback on different thread ThreadAbstraction.ExecuteThread(() => uploadCallback(writtenBytes)); @@ -2494,7 +2492,7 @@ protected override void OnDisconnecting() // disconnect, dispose and dereference the SFTP session since we create a new SFTP session // on each connect var sftpSession = _sftpSession; - if (sftpSession != null) + if (sftpSession is not null) { _sftpSession = null; sftpSession.Dispose(); @@ -2512,7 +2510,7 @@ protected override void Dispose(bool disposing) if (disposing) { var sftpSession = _sftpSession; - if (sftpSession != null) + if (sftpSession is not null) { _sftpSession = null; sftpSession.Dispose(); diff --git a/src/Renci.SshNet/Shell.cs b/src/Renci.SshNet/Shell.cs index 892c530b4..0990ae812 100644 --- a/src/Renci.SshNet/Shell.cs +++ b/src/Renci.SshNet/Shell.cs @@ -102,7 +102,7 @@ public void Start() throw new SshException("Shell is started."); } - Starting?.Invoke(this, new EventArgs()); + Starting?.Invoke(this, EventArgs.Empty); _channel = _session.CreateChannelSession(); _channel.DataReceived += Channel_DataReceived; @@ -196,7 +196,7 @@ private void Channel_DataReceived(object sender, ChannelDataEventArgs e) private void Channel_Closed(object sender, ChannelEventArgs e) { - if (Stopping != null) + if (Stopping is not null) { // Handle event on different thread ThreadAbstraction.ExecuteThread(() => Stopping(this, EventArgs.Empty)); @@ -272,21 +272,21 @@ protected virtual void Dispose(bool disposing) UnsubscribeFromSessionEvents(_session); var channelClosedWaitHandle = _channelClosedWaitHandle; - if (channelClosedWaitHandle != null) + if (channelClosedWaitHandle is not null) { channelClosedWaitHandle.Dispose(); _channelClosedWaitHandle = null; } var channel = _channel; - if (channel != null) + if (channel is not null) { channel.Dispose(); _channel = null; } var dataReaderTaskCompleted = _dataReaderTaskCompleted; - if (dataReaderTaskCompleted != null) + if (dataReaderTaskCompleted is not null) { dataReaderTaskCompleted.Dispose(); _dataReaderTaskCompleted = null; diff --git a/src/Renci.SshNet/SshClient.cs b/src/Renci.SshNet/SshClient.cs index 5ed7036c5..fb8bb37f0 100644 --- a/src/Renci.SshNet/SshClient.cs +++ b/src/Renci.SshNet/SshClient.cs @@ -336,7 +336,7 @@ public Shell CreateShell(Stream input, Stream output, Stream extendedOutput, str /// Client is not connected. public Shell CreateShell(Stream input, Stream output, Stream extendedOutput) { - return CreateShell(input, output, extendedOutput, string.Empty, 0, 0, 0, 0, null, 1024); + return CreateShell(input, output, extendedOutput, string.Empty, 0, 0, 0, 0, terminalModes: null, 1024); } /// @@ -405,7 +405,7 @@ public Shell CreateShell(Encoding encoding, string input, Stream output, Stream /// Client is not connected. public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput) { - return CreateShell(encoding, input, output, extendedOutput, string.Empty, 0, 0, 0, 0, null, 1024); + return CreateShell(encoding, input, output, extendedOutput, string.Empty, 0, 0, 0, 0, terminalModes: null, 1024); } /// @@ -433,7 +433,7 @@ public Shell CreateShell(Encoding encoding, string input, Stream output, Stream /// public ShellStream CreateShellStream(string terminalName, uint columns, uint rows, uint width, uint height, int bufferSize) { - return CreateShellStream(terminalName, columns, rows, width, height, bufferSize, null); + return CreateShellStream(terminalName, columns, rows, width, height, bufferSize, terminalModeValues: null); } /// diff --git a/src/Renci.SshNet/SshCommand.cs b/src/Renci.SshNet/SshCommand.cs index 30a6bfe54..13c00992a 100644 --- a/src/Renci.SshNet/SshCommand.cs +++ b/src/Renci.SshNet/SshCommand.cs @@ -150,7 +150,7 @@ internal SshCommand(ISession session, string commandText, Encoding encoding) CommandText = commandText; _encoding = encoding; CommandTimeout = Session.InfiniteTimeSpan; - _sessionErrorOccuredWaitHandle = new AutoResetEvent(false); + _sessionErrorOccuredWaitHandle = new AutoResetEvent(initialState: false); _session.Disconnected += Session_Disconnected; _session.ErrorOccured += Session_ErrorOccured; @@ -172,7 +172,7 @@ internal SshCommand(ISession session, string commandText, Encoding encoding) /// Operation has timed out. public IAsyncResult BeginExecute() { - return BeginExecute(null, null); + return BeginExecute(callback: null, state: null); } /// @@ -189,7 +189,7 @@ public IAsyncResult BeginExecute() /// Operation has timed out. public IAsyncResult BeginExecute(AsyncCallback callback) { - return BeginExecute(callback, null); + return BeginExecute(callback, state: null); } /// @@ -216,13 +216,13 @@ public IAsyncResult BeginExecute(AsyncCallback callback, object state) // Create new AsyncResult object _asyncResult = new CommandAsyncResult { - AsyncWaitHandle = new ManualResetEvent(false), + AsyncWaitHandle = new ManualResetEvent(initialState: false), IsCompleted = false, AsyncState = state, }; // When command re-executed again, create a new channel - if (_channel != null) + if (_channel is not null) { throw new SshException("Invalid operation."); } @@ -233,14 +233,14 @@ public IAsyncResult BeginExecute(AsyncCallback callback, object state) } var outputStream = OutputStream; - if (outputStream != null) + if (outputStream is not null) { outputStream.Dispose(); OutputStream = null; } var extendedOutputStream = ExtendedOutputStream; - if (extendedOutputStream != null) + if (extendedOutputStream is not null) { extendedOutputStream.Dispose(); ExtendedOutputStream = null; @@ -333,7 +333,7 @@ public string EndExecute(IAsyncResult asyncResult) /// Operation has timed out. public string Execute() { - return EndExecute(BeginExecute(null, null)); + return EndExecute(BeginExecute(callback: null, state: null)); } /// @@ -341,7 +341,7 @@ public string Execute() /// public void CancelAsync() { - if (_channel != null && _channel.IsOpen && _asyncResult != null) + if (_channel is not null && _channel.IsOpen && _asyncResult is not null) { // TODO: check with Oleg if we shouldn't dispose the channel and uninitialize it ? _channel.Dispose(); @@ -407,7 +407,7 @@ private void Channel_Closed(object sender, ChannelEventArgs e) _asyncResult.IsCompleted = true; - if (_callback != null) + if (_callback is not null) { // Execute callback on different thread ThreadAbstraction.ExecuteThread(() => _callback(_asyncResult)); diff --git a/src/Renci.SshNet/SubsystemSession.cs b/src/Renci.SshNet/SubsystemSession.cs index 2c2b66c06..b89d30fd1 100644 --- a/src/Renci.SshNet/SubsystemSession.cs +++ b/src/Renci.SshNet/SubsystemSession.cs @@ -23,9 +23,9 @@ internal abstract class SubsystemSession : ISubsystemSession private ISession _session; private IChannelSession _channel; private Exception _exception; - private EventWaitHandle _errorOccuredWaitHandle = new ManualResetEvent(false); - private EventWaitHandle _sessionDisconnectedWaitHandle = new ManualResetEvent(false); - private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(false); + private EventWaitHandle _errorOccuredWaitHandle = new ManualResetEvent(initialState: false); + private EventWaitHandle _sessionDisconnectedWaitHandle = new ManualResetEvent(initialState: false); + private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(initialState: false); private bool _isDisposed; /// @@ -70,7 +70,7 @@ internal IChannelSession Channel /// public bool IsOpen { - get { return _channel != null && _channel.IsOpen; } + get { return _channel is not null && _channel.IsOpen; } } /// @@ -149,7 +149,7 @@ public void Disconnect() UnsubscribeFromSessionEvents(_session); var channel = _channel; - if (channel != null) + if (channel is not null) { _channel = null; channel.DataReceived -= Channel_DataReceived; From a4dbf7763a7bea8577619efb9a841b5170fbe357 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Tue, 6 Jun 2023 23:09:12 +0200 Subject: [PATCH 23/96] Replace Array.Empty with Array.Empty() (#1137) --- .../Classes/Common/ExtensionsTest_Concat.cs | 8 ++++---- ...eadLessBytesFromServerThanCountAndEqualToBufferSize.cs | 2 +- ...adLessBytesFromServerThanCountAndLessThanBufferSize.cs | 4 ++-- ...taInReaderBufferAndReadMoreBytesFromServerThanCount.cs | 2 +- ...eadLessBytesFromServerThanCountAndEqualToBufferSize.cs | 2 +- ...adLessBytesFromServerThanCountAndLessThanBufferSize.cs | 4 ++-- ...taInReaderBufferAndReadMoreBytesFromServerThanCount.cs | 2 +- ...etLength_DataInReadBuffer_NewLengthLessThanPosition.cs | 2 +- ...tLength_DataInWriteBuffer_NewLengthLessThanPosition.cs | 2 +- src/Renci.SshNet/Common/Array.cs | 7 ------- src/Renci.SshNet/Common/Extensions.cs | 4 ++-- src/Renci.SshNet/Connection/Socks4Connector.cs | 2 +- .../Authentication/RequestMessageKeyboardInteractive.cs | 6 +++--- src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs | 5 ++--- src/Renci.SshNet/Sftp/Responses/SftpNameResponse.cs | 7 +++---- src/Renci.SshNet/Sftp/SftpSession.cs | 6 +++--- 16 files changed, 28 insertions(+), 37 deletions(-) delete mode 100644 src/Renci.SshNet/Common/Array.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs index ab15e0109..1b3785f8f 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs @@ -22,7 +22,7 @@ public void Init() [TestMethod] public void ShouldReturnSecondWhenFirstIsEmpty() { - var first = Array.Empty; + var first = Array.Empty(); var second = CreateBuffer(16); var actual = Extensions.Concat(first, second); @@ -47,7 +47,7 @@ public void ShouldReturnSecondWhenFirstIsNull() public void ShouldReturnFirstWhenSecondIsEmpty() { var first = CreateBuffer(16); - var second = Array.Empty; + var second = Array.Empty(); var actual = Extensions.Concat(first, second); @@ -101,7 +101,7 @@ public void ShouldConcatSecondToFirstWhenBothAreNotEmpty() [TestCategory("Performance")] public void Performance_LargeArray_FirstEmpty() { - var first = Array.Empty; + var first = Array.Empty(); var second = CreateBuffer(50000); const int runs = 10000; @@ -115,7 +115,7 @@ public void Performance_LargeArray_FirstEmpty() public void Performance_LargeArray_SecondEmpty() { var first = CreateBuffer(50000); - var second = Array.Empty; + var second = Array.Empty(); const int runs = 10000; Performance(first, second, runs); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs index d3b5983be..ef8dbebe1 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs @@ -138,7 +138,7 @@ public async Task ReadShouldReturnAllRemaningBytesFromReadBufferWhenCountIsEqual public async Task ReadShouldReturnAllRemaningBytesFromReadBufferAndReadAgainWhenCountIsGreaterThanNumberOfRemainingBytesAndNewReadReturnsZeroBytes() { SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestReadAsync(_handle, (ulong)(_serverData1Length + _serverData2Length), _readBufferSize, default)).ReturnsAsync(Array.Empty); + SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestReadAsync(_handle, (ulong)(_serverData1Length + _serverData2Length), _readBufferSize, default)).ReturnsAsync(Array.Empty()); var numberOfBytesRemainingInReadBuffer = _serverData1Length + _serverData2Length - _numberOfBytesToRead; diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs index 29121639c..9d07681a6 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs @@ -118,7 +118,7 @@ public async Task SubsequentReadShouldReadAgainFromCurrentPositionFromServerAndR SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); SftpSessionMock.InSequence(MockSequence) .Setup(p => p.RequestReadAsync(_handle, (ulong) _actual, _readBufferSize, default)) - .ReturnsAsync(Array.Empty); + .ReturnsAsync(Array.Empty()); var buffer = _originalBuffer.Copy(); var actual = await _target.ReadAsync(buffer, 0, buffer.Length); @@ -136,7 +136,7 @@ public async Task SubsequentReadShouldReadAgainFromCurrentPositionFromServerAndN SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); SftpSessionMock.InSequence(MockSequence) .Setup(p => p.RequestReadAsync(_handle, (ulong)_actual, _readBufferSize, default)) - .ReturnsAsync(Array.Empty); + .ReturnsAsync(Array.Empty()); SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); await _target.ReadAsync(new byte[10], 0, 10); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs index d95ffd0a0..83ae8d42b 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs @@ -124,7 +124,7 @@ public async Task SubsequentReadShouldReturnAllRemaningBytesFromReadBufferWhenCo public async Task SubsequentReadShouldReturnAllRemaningBytesFromReadBufferAndReadAgainWhenCountIsGreaterThanNumberOfRemainingBytesAndNewReadReturnsZeroBytes() { SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestReadAsync(_handle, (ulong)(_serverData.Length), _readBufferSize, default)).ReturnsAsync(Array.Empty); + SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestReadAsync(_handle, (ulong)(_serverData.Length), _readBufferSize, default)).ReturnsAsync(Array.Empty()); var buffer = new byte[_numberOfBytesToWriteToReadBuffer + 1]; diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs index 5f6f24be9..3932c28a9 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs @@ -136,7 +136,7 @@ public void ReadShouldReturnAllRemaningBytesFromReadBufferWhenCountIsEqualToNumb public void ReadShouldReturnAllRemaningBytesFromReadBufferAndReadAgainWhenCountIsGreaterThanNumberOfRemainingBytesAndNewReadReturnsZeroBytes() { SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, (ulong)(_serverData1Length + _serverData2Length), _readBufferSize)).Returns(Array.Empty); + SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, (ulong)(_serverData1Length + _serverData2Length), _readBufferSize)).Returns(Array.Empty()); var numberOfBytesRemainingInReadBuffer = _serverData1Length + _serverData2Length - _numberOfBytesToRead; diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs index 85a6679b8..794f6c7b0 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs @@ -116,7 +116,7 @@ public void SubsequentReadShouldReadAgainFromCurrentPositionFromServerAndReturnZ SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); SftpSessionMock.InSequence(MockSequence) .Setup(p => p.RequestRead(_handle, (ulong) _actual, _readBufferSize)) - .Returns(Array.Empty); + .Returns(Array.Empty()); var buffer = _originalBuffer.Copy(); var actual = _target.Read(buffer, 0, buffer.Length); @@ -134,7 +134,7 @@ public void SubsequentReadShouldReadAgainFromCurrentPositionFromServerAndNotUpda SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); SftpSessionMock.InSequence(MockSequence) .Setup(p => p.RequestRead(_handle, (ulong)_actual, _readBufferSize)) - .Returns(Array.Empty); + .Returns(Array.Empty()); SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); _target.Read(new byte[10], 0, 10); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs index 97c66422b..1f6f2cf5c 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs @@ -122,7 +122,7 @@ public void SubsequentReadShouldReturnAllRemaningBytesFromReadBufferWhenCountIsE public void SubsequentReadShouldReturnAllRemaningBytesFromReadBufferAndReadAgainWhenCountIsGreaterThanNumberOfRemainingBytesAndNewReadReturnsZeroBytes() { SftpSessionMock.InSequence(MockSequence).Setup(p => p.IsOpen).Returns(true); - SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, (ulong)(_serverData.Length), _readBufferSize)).Returns(Array.Empty); + SftpSessionMock.InSequence(MockSequence).Setup(p => p.RequestRead(_handle, (ulong)(_serverData.Length), _readBufferSize)).Returns(Array.Empty()); var buffer = new byte[_numberOfBytesToWriteToReadBuffer + 1]; diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs index a61163392..0709896d1 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs @@ -137,7 +137,7 @@ public void ReadShouldStartFromEndOfStream() SftpSessionMock.InSequence(_sequence).Setup(p => p.IsOpen).Returns(true); SftpSessionMock.InSequence(_sequence) .Setup(p => p.RequestRead(_handle, (uint) _length, _readBufferSize)) - .Returns(Array.Empty); + .Returns(Array.Empty()); var byteRead = _sftpFileStream.ReadByte(); diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs index 96ad14b18..42a3ce841 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs @@ -160,7 +160,7 @@ public void ReadShouldStartFromEndOfStream() SftpSessionMock.InSequence(_sequence).Setup(p => p.IsOpen).Returns(true); SftpSessionMock.InSequence(_sequence) .Setup(p => p.RequestRead(_handle, (uint) _length, _readBufferSize)) - .Returns(Array.Empty); + .Returns(Array.Empty()); var byteRead = _sftpFileStream.ReadByte(); diff --git a/src/Renci.SshNet/Common/Array.cs b/src/Renci.SshNet/Common/Array.cs deleted file mode 100644 index c11c3565a..000000000 --- a/src/Renci.SshNet/Common/Array.cs +++ /dev/null @@ -1,7 +0,0 @@ -锘縩amespace Renci.SshNet.Common -{ - internal static class Array - { - public static readonly T[] Empty = new T[0]; - } -} diff --git a/src/Renci.SshNet/Common/Extensions.cs b/src/Renci.SshNet/Common/Extensions.cs index 8fed310c1..d5c454c70 100644 --- a/src/Renci.SshNet/Common/Extensions.cs +++ b/src/Renci.SshNet/Common/Extensions.cs @@ -180,7 +180,7 @@ public static byte[] Take(this byte[] value, int offset, int count) if (count == 0) { - return Array.Empty; + return Array.Empty(); } if (offset == 0 && value.Length == count) @@ -215,7 +215,7 @@ public static byte[] Take(this byte[] value, int count) if (count == 0) { - return Array.Empty; + return Array.Empty(); } if (value.Length == count) diff --git a/src/Renci.SshNet/Connection/Socks4Connector.cs b/src/Renci.SshNet/Connection/Socks4Connector.cs index 046d0549b..4da6bf773 100644 --- a/src/Renci.SshNet/Connection/Socks4Connector.cs +++ b/src/Renci.SshNet/Connection/Socks4Connector.cs @@ -124,7 +124,7 @@ private static byte[] GetProxyUserBytes(string proxyUser) { if (proxyUser == null) { - return Array.Empty; + return Array.Empty(); } return Encoding.ASCII.GetBytes(proxyUser); diff --git a/src/Renci.SshNet/Messages/Authentication/RequestMessageKeyboardInteractive.cs b/src/Renci.SshNet/Messages/Authentication/RequestMessageKeyboardInteractive.cs index 0b9b0fb68..6175511ed 100644 --- a/src/Renci.SshNet/Messages/Authentication/RequestMessageKeyboardInteractive.cs +++ b/src/Renci.SshNet/Messages/Authentication/RequestMessageKeyboardInteractive.cs @@ -1,4 +1,4 @@ -锘縰sing Renci.SshNet.Common; +锘縰sing System; namespace Renci.SshNet.Messages.Authentication { @@ -44,8 +44,8 @@ protected override int BufferCapacity public RequestMessageKeyboardInteractive(ServiceName serviceName, string username) : base(serviceName, username, "keyboard-interactive") { - Language = Array.Empty; - SubMethods = Array.Empty; + Language = Array.Empty(); + SubMethods = Array.Empty(); } /// diff --git a/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs b/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs index 7c9fa247c..5fc009a37 100644 --- a/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs @@ -1,7 +1,6 @@ 锘縰sing System; using System.Globalization; using Renci.SshNet.Abstractions; -using Renci.SshNet.Common; namespace Renci.SshNet.Messages.Transport { @@ -23,7 +22,7 @@ public class IgnoreMessage : Message /// public IgnoreMessage() { - Data = Array.Empty; + Data = Array.Empty(); } /// @@ -71,7 +70,7 @@ protected override void LoadData() if (dataLength > (DataStream.Length - DataStream.Position)) { DiagnosticAbstraction.Log("SSH_MSG_IGNORE: Length exceeds data bytes, data ignored."); - Data = Array.Empty; + Data = Array.Empty(); } else { diff --git a/src/Renci.SshNet/Sftp/Responses/SftpNameResponse.cs b/src/Renci.SshNet/Sftp/Responses/SftpNameResponse.cs index 059831052..2bdf67891 100644 --- a/src/Renci.SshNet/Sftp/Responses/SftpNameResponse.cs +++ b/src/Renci.SshNet/Sftp/Responses/SftpNameResponse.cs @@ -1,8 +1,7 @@ -锘縰sing System.Collections.Generic; +锘縰sing System; +using System.Collections.Generic; using System.Text; -using Renci.SshNet.Common; - namespace Renci.SshNet.Sftp.Responses { internal sealed class SftpNameResponse : SftpResponse @@ -21,7 +20,7 @@ public override SftpMessageTypes SftpMessageType public SftpNameResponse(uint protocolVersion, Encoding encoding) : base(protocolVersion) { - Files = Array>.Empty; + Files = Array.Empty>(); Encoding = encoding; } diff --git a/src/Renci.SshNet/Sftp/SftpSession.cs b/src/Renci.SshNet/Sftp/SftpSession.cs index 77355d4a5..d797378d3 100644 --- a/src/Renci.SshNet/Sftp/SftpSession.cs +++ b/src/Renci.SshNet/Sftp/SftpSession.cs @@ -690,7 +690,7 @@ public SftpReadAsyncResult BeginRead(byte[] handle, ulong offset, uint length, A } else { - asyncResult.SetAsCompleted(Array.Empty, completedSynchronously: false); + asyncResult.SetAsCompleted(Array.Empty(), completedSynchronously: false); } }); SendRequest(request); @@ -767,7 +767,7 @@ public byte[] RequestRead(byte[] handle, ulong offset, uint length) } else { - data = Array.Empty; + data = Array.Empty(); } _ = wait.Set(); @@ -804,7 +804,7 @@ public async Task RequestReadAsync(byte[] handle, ulong offset, uint len { if (response.StatusCode == StatusCodes.Eof) { - _ = tcs.TrySetResult(Array.Empty); + _ = tcs.TrySetResult(Array.Empty()); } else { From 457789947c284fc8cd377e9be400af7356e086b4 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Mon, 12 Jun 2023 23:21:25 +0200 Subject: [PATCH 24/96] Replace IsNullOrWhiteSpace extension (#1142) --- src/Renci.SshNet/AuthenticationMethod.cs | 4 +--- src/Renci.SshNet/Common/Extensions.cs | 25 ----------------------- src/Renci.SshNet/ScpClient.cs | 2 +- src/Renci.SshNet/SftpClient.cs | 26 ++++++++++++------------ 4 files changed, 15 insertions(+), 42 deletions(-) diff --git a/src/Renci.SshNet/AuthenticationMethod.cs b/src/Renci.SshNet/AuthenticationMethod.cs index 51e49b7ad..99a5e102f 100644 --- a/src/Renci.SshNet/AuthenticationMethod.cs +++ b/src/Renci.SshNet/AuthenticationMethod.cs @@ -1,7 +1,5 @@ 锘縰sing System; -using Renci.SshNet.Common; - namespace Renci.SshNet { /// @@ -34,7 +32,7 @@ public abstract class AuthenticationMethod : IAuthenticationMethod /// is whitespace or null. protected AuthenticationMethod(string username) { - if (username.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(username)) { throw new ArgumentException("username"); } diff --git a/src/Renci.SshNet/Common/Extensions.cs b/src/Renci.SshNet/Common/Extensions.cs index d5c454c70..d734ffd8b 100644 --- a/src/Renci.SshNet/Common/Extensions.cs +++ b/src/Renci.SshNet/Common/Extensions.cs @@ -15,31 +15,6 @@ namespace Renci.SshNet.Common /// internal static partial class Extensions { - /// - /// Determines whether the specified value is null or white space. - /// - /// The value. - /// - /// true if is null or white space; otherwise, false. - /// - public static bool IsNullOrWhiteSpace(this string value) - { - if (string.IsNullOrEmpty(value)) - { - return true; - } - - for (var i = 0; i < value.Length; i++) - { - if (!char.IsWhiteSpace(value[i])) - { - return false; - } - } - - return true; - } - internal static byte[] ToArray(this ServiceName serviceName) { switch (serviceName) diff --git a/src/Renci.SshNet/ScpClient.cs b/src/Renci.SshNet/ScpClient.cs index 7269e81c3..177a83bb5 100644 --- a/src/Renci.SshNet/ScpClient.cs +++ b/src/Renci.SshNet/ScpClient.cs @@ -243,7 +243,7 @@ public void Upload(Stream source, string path) /// The secure copy execution request was rejected by the server. public void Download(string filename, Stream destination) { - if (filename.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(filename)) { throw new ArgumentException(Message); } diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 9fe19235a..a275413a1 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -326,7 +326,7 @@ public void CreateDirectory(string path) { CheckDisposed(); - if (path.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException(path); } @@ -355,7 +355,7 @@ public void DeleteDirectory(string path) { CheckDisposed(); - if (path.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("path"); } @@ -384,7 +384,7 @@ public void DeleteFile(string path) { CheckDisposed(); - if (path.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("path"); } @@ -415,7 +415,7 @@ public async Task DeleteFileAsync(string path, CancellationToken cancellationTok { CheckDisposed(); - if (path.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("path"); } @@ -542,12 +542,12 @@ public void SymbolicLink(string path, string linkPath) { CheckDisposed(); - if (path.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("path"); } - if (linkPath.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(linkPath)) { throw new ArgumentException("linkPath"); } @@ -753,7 +753,7 @@ public bool Exists(string path) { CheckDisposed(); - if (path.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("path"); } @@ -882,7 +882,7 @@ public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback { CheckDisposed(); - if (path.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("path"); } @@ -1109,7 +1109,7 @@ public IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride, throw new ArgumentNullException(nameof(input)); } - if (path.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("path"); } @@ -2106,7 +2106,7 @@ public IEnumerable SynchronizeDirectories(string sourcePath, string de throw new ArgumentNullException(nameof(sourcePath)); } - if (destinationPath.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(destinationPath)) { throw new ArgumentException("destinationPath"); } @@ -2135,7 +2135,7 @@ public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destin throw new ArgumentNullException(nameof(sourcePath)); } - if (destinationPath.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(destinationPath)) { throw new ArgumentException("destDir"); } @@ -2340,7 +2340,7 @@ private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncR throw new ArgumentNullException(nameof(output)); } - if (path.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("path"); } @@ -2404,7 +2404,7 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo throw new ArgumentNullException(nameof(input)); } - if (path.IsNullOrWhiteSpace()) + if (string.IsNullOrWhiteSpace(path)) { throw new ArgumentException("path"); } From a3dbbc523168f522d74e3a59a6852b9953aa2041 Mon Sep 17 00:00:00 2001 From: Marius Thesing Date: Sun, 25 Jun 2023 10:52:02 +0200 Subject: [PATCH 25/96] Use License Expression for NuGet Package licenseUrl is deprecated, see https://github.com/NuGet/Announcements/issues/32 --- build/nuget/SSH.NET.nuspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/nuget/SSH.NET.nuspec b/build/nuget/SSH.NET.nuspec index 3fe48202b..a694592e0 100644 --- a/build/nuget/SSH.NET.nuspec +++ b/build/nuget/SSH.NET.nuspec @@ -6,7 +6,7 @@ SSH.NET Renci olegkap,drieseng - https://github.com/sshnet/SSH.NET/blob/master/LICENSE + MIT https://github.com/sshnet/SSH.NET/ false SSH.NET is a Secure Shell (SSH) library for .NET, optimized for parallelism and with broad framework support. From 69a42d3b708229e0f452d134e88337b1d8a9ee38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Thu, 29 Jun 2023 06:29:17 +0200 Subject: [PATCH 26/96] Integration tests --- .../.editorconfig | 32 ++++++++ src/Renci.SshNet.IntegrationTests/Dockerfile | 49 ++++++++++++ .../Renci.SshNet.IntegrationTests.csproj | 33 ++++++++ .../ScpClientTests.cs | 43 ++++++++++ .../SftpClientTests.cs | 67 ++++++++++++++++ .../SshClientTests.cs | 34 ++++++++ .../TestInitializer.cs | 20 +++++ .../TestsFixtures/InfrastructureFixture.cs | 80 +++++++++++++++++++ .../TestsFixtures/IntegrationTestBase.cs | 67 ++++++++++++++++ .../TestsFixtures/SshUser.cs | 16 ++++ src/Renci.SshNet.IntegrationTests/Usings.cs | 2 + .../server/script/start.sh | 10 +++ .../server/ssh/ssh_host_ecdsa_key | 9 +++ .../server/ssh/ssh_host_ed25519_key | 7 ++ .../server/ssh/ssh_host_rsa_key | 38 +++++++++ .../user/sshnet/authorized_keys | 4 + src/Renci.SshNet.sln | 22 +++++ 17 files changed, 533 insertions(+) create mode 100644 src/Renci.SshNet.IntegrationTests/.editorconfig create mode 100644 src/Renci.SshNet.IntegrationTests/Dockerfile create mode 100644 src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj create mode 100644 src/Renci.SshNet.IntegrationTests/ScpClientTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/SftpClientTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/SshClientTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/TestInitializer.cs create mode 100644 src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs create mode 100644 src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs create mode 100644 src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs create mode 100644 src/Renci.SshNet.IntegrationTests/Usings.cs create mode 100644 src/Renci.SshNet.IntegrationTests/server/script/start.sh create mode 100644 src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ecdsa_key create mode 100644 src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ed25519_key create mode 100644 src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_rsa_key create mode 100644 src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys diff --git a/src/Renci.SshNet.IntegrationTests/.editorconfig b/src/Renci.SshNet.IntegrationTests/.editorconfig new file mode 100644 index 000000000..b94e29112 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/.editorconfig @@ -0,0 +1,32 @@ +锘縖*.cs] + +#### SYSLIB diagnostics #### + +# SYSLIB1045: Use 'GeneratedRegexAttribute' to generate the regular expression implementation at compile-time +# +# TODO: Remove this when https://github.com/sshnet/SSH.NET/issues/1131 is implemented. +dotnet_diagnostic.SYSLIB1045.severity = none + +### StyleCop Analyzers rules ### + +#### .NET Compiler Platform analysers rules #### + +# IDE0007: Use var instead of explicit type +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0007 +dotnet_diagnostic.IDE0007.severity = suggestion + +# IDE0028: Use collection initializers +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0028 +dotnet_diagnostic.IDE0028.severity = suggestion + +# IDE0058: Remove unnecessary expression value +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0058 +dotnet_diagnostic.IDE0058.severity = suggestion + +# IDE0059: Remove unnecessary value assignment +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0059 +dotnet_diagnostic.IDE0059.severity = suggestion + +# IDE0230: Use UTF-8 string literal +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0230 +dotnet_diagnostic.IDE0230.severity = suggestion diff --git a/src/Renci.SshNet.IntegrationTests/Dockerfile b/src/Renci.SshNet.IntegrationTests/Dockerfile new file mode 100644 index 000000000..811d51543 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/Dockerfile @@ -0,0 +1,49 @@ +FROM alpine:latest + +COPY --chown=root:root server/ssh /etc/ssh/ +COPY --chown=root:root server/script /opt/sshnet +COPY user/sshnet /home/sshnet/.ssh + +RUN apk update && apk upgrade --no-cache && \ + apk add --no-cache syslog-ng && \ + # install and configure sshd + apk add --no-cache openssh && \ + # install openssh-server-pam to allow for keyboard-interactive authentication + apk add --no-cache openssh-server-pam && \ + dos2unix /etc/ssh/* && \ + chmod 400 /etc/ssh/ssh*key && \ + sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config && \ + sed -i 's/#LogLevel\s*INFO/LogLevel DEBUG3/' /etc/ssh/sshd_config && \ + echo 'PubkeyAcceptedAlgorithms ssh-rsa' >> /etc/ssh/sshd_config && \ + chmod 646 /etc/ssh/sshd_config && \ + # install and configure sudo + apk add --no-cache sudo && \ + addgroup sudo && \ + # allow root to run any command + echo 'root ALL=(ALL) ALL' > /etc/sudoers && \ + # allow everyone in the 'sudo' group to run any command without a password + echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers && \ + # add user to run most of the integration tests + adduser -D sshnet && \ + passwd -u sshnet && \ + echo 'sshnet:ssh4ever' | chpasswd && \ + dos2unix /home/sshnet/.ssh/* && \ + chown -R sshnet:sshnet /home/sshnet && \ + chmod -R 700 /home/sshnet/.ssh && \ + chmod -R 644 /home/sshnet/.ssh/authorized_keys && \ + # add user to administer container (update configs, restart sshd) + adduser -D sshnetadm && \ + passwd -u sshnetadm && \ + echo 'sshnetadm:ssh4ever' | chpasswd && \ + addgroup sshnetadm sudo && \ + dos2unix /opt/sshnet/* && \ + # install shadow package; we use chage command in this package to expire/unexpire password of the sshnet user + apk add --no-cache shadow && \ + # allow us to use telnet command; we use this in the remote port forwarding tests + apk --no-cache add busybox-extras && \ + # install full-fledged ps command + apk add --no-cache procps + +EXPOSE 22 22 + +ENTRYPOINT ["/opt/sshnet/start.sh"] \ No newline at end of file diff --git a/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj b/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj new file mode 100644 index 000000000..bf09d62cc --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj @@ -0,0 +1,33 @@ + + + + net7.0 + enable + enable + + false + true + + $(NoWarn);CS1591 + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + diff --git a/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs b/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs new file mode 100644 index 000000000..62cbaeb0b --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs @@ -0,0 +1,43 @@ +using System.Text; + +namespace Renci.SshNet.IntegrationTests +{ + /// + /// The SCP client integration tests + /// + [TestClass] + public class ScpClientTests : IntegrationTestBase, IDisposable + { + private readonly ScpClient _scpClient; + + public ScpClientTests() + { + _scpClient = new ScpClient(SshServerHostName, SshServerPort, User.UserName, User.Password); + _scpClient.Connect(); + } + + [TestMethod] + + public void Scp_Upload_And_Download_FileStream() + { + var file = $"/tmp/{Guid.NewGuid()}.txt"; + var fileContent = "File content !@#$%^&*()_+{}:,./<>[];'\\|"; + + using var uploadStream = new MemoryStream(Encoding.UTF8.GetBytes(fileContent)); + _scpClient.Upload(uploadStream, file); + + using var downloadStream = new MemoryStream(); + _scpClient.Download(file, downloadStream); + + var result = Encoding.UTF8.GetString(downloadStream.ToArray()); + + Assert.AreEqual(fileContent, result); + } + + public void Dispose() + { + _scpClient.Disconnect(); + _scpClient.Dispose(); + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs b/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs new file mode 100644 index 000000000..5eb9a2dbe --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs @@ -0,0 +1,67 @@ +using System.Text; + +using Renci.SshNet.Common; + +namespace Renci.SshNet.IntegrationTests +{ + /// + /// The SFTP client integration tests + /// + [TestClass] + public class SftpClientTests : IntegrationTestBase, IDisposable + { + private readonly SftpClient _sftpClient; + + public SftpClientTests() + { + _sftpClient = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password); + _sftpClient.Connect(); + } + + [TestMethod] + public void Test_Sftp_ListDirectory_Home_Directory() + { + var builder = new StringBuilder(); + var files = _sftpClient.ListDirectory("/"); + foreach (var file in files) + { + builder.AppendLine($"{file.FullName}"); + } + + Assert.AreEqual(@"/usr +/var +/. +/bin +/mnt +/opt +/tmp +/etc +/root +/media +/.. +/dev +/proc +/sys +/home +/lib +/sbin +/run +/srv +/.dockerenv +", builder.ToString()); + } + + [TestMethod] + [ExpectedException(typeof(SftpPermissionDeniedException), "Permission denied")] + public void Test_Sftp_ListDirectory_Permission_Denied() + { + _sftpClient.ListDirectory("/root"); + } + + public void Dispose() + { + _sftpClient.Disconnect(); + _sftpClient.Dispose(); + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/SshClientTests.cs b/src/Renci.SshNet.IntegrationTests/SshClientTests.cs new file mode 100644 index 000000000..ba25bc6c7 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/SshClientTests.cs @@ -0,0 +1,34 @@ +using System.Text; + +namespace Renci.SshNet.IntegrationTests +{ + /// + /// The SSH client integration tests + /// + [TestClass] + public class SshClientTests : IntegrationTestBase, IDisposable + { + private readonly SshClient _sshClient; + + public SshClientTests() + { + _sshClient = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password); + _sshClient.Connect(); + } + + [TestMethod] + public void Test_SSH_Echo_Command() + { + var builder = new StringBuilder(); + var response = _sshClient.RunCommand("echo $'test !@#$%^&*()_+{}:,./<>[];\\|'"); + + Assert.AreEqual("test !@#$%^&*()_+{}:,./<>[];\\|\n", response.Result); + } + + public void Dispose() + { + _sshClient.Disconnect(); + _sshClient.Dispose(); + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/TestInitializer.cs b/src/Renci.SshNet.IntegrationTests/TestInitializer.cs new file mode 100644 index 000000000..5e0b7d876 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/TestInitializer.cs @@ -0,0 +1,20 @@ +namespace Renci.SshNet.IntegrationTests +{ + [TestClass] + public class TestInitializer + { + [AssemblyInitialize] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "MSTests requires context parameter")] + public static async Task Initialize(TestContext context) + { + + await InfrastructureFixture.Instance.InitializeAsync(); + } + + [AssemblyCleanup] + public static async Task Cleanup() + { + await InfrastructureFixture.Instance.DisposeAsync(); + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs b/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs new file mode 100644 index 000000000..3c6a0572c --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs @@ -0,0 +1,80 @@ +锘縰sing DotNet.Testcontainers.Images; +using DotNet.Testcontainers.Builders; +using DotNet.Testcontainers.Containers; + +namespace Renci.SshNet.IntegrationTests.TestsFixtures +{ + public sealed class InfrastructureFixture : IDisposable + { + private InfrastructureFixture() + { + + } + + private static readonly Lazy InstanceLazy = new Lazy(() => new InfrastructureFixture()); + + public static InfrastructureFixture Instance + { + get + { + return InstanceLazy.Value; + } + } + + private IContainer? _sshServer; + + private IFutureDockerImage? _sshServerImage; + + public string? SshServerHostName { get; set; } + + public ushort SshServerPort { get; set; } + + // TODO the user name and password can be injected to dockerfile via arguments + public SshUser AdminUser = new SshUser("sshnetadm", "ssh4ever"); + + // TODO the user name and password can be injected to dockerfile via arguments + public SshUser User = new SshUser("sshnet", "ssh4ever"); + + public async Task InitializeAsync() + { + _sshServerImage = new ImageFromDockerfileBuilder() + .WithName("renci-ssh-tests-server-image") + .WithDockerfileDirectory(CommonDirectoryPath.GetSolutionDirectory(), "Renci.SshNet.IntegrationTests") + .WithDockerfile("Dockerfile") + .WithDeleteIfExists(true) + + .Build(); + + await _sshServerImage.CreateAsync(); + + _sshServer = new ContainerBuilder() + .WithHostname("renci-ssh-tests-server") + .WithImage(_sshServerImage) + //.WithPrivileged(true) + .WithPortBinding(22, true) + .Build(); + + await _sshServer.StartAsync(); + + SshServerPort = _sshServer.GetMappedPublicPort(22); + SshServerHostName = _sshServer.Hostname; + } + + public async Task DisposeAsync() + { + if (_sshServer != null) + { + await _sshServer.DisposeAsync(); + } + + if (_sshServerImage != null) + { + await _sshServerImage.DisposeAsync(); + } + } + + public void Dispose() + { + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs b/src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs new file mode 100644 index 000000000..6079da1b5 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs @@ -0,0 +1,67 @@ +锘 +namespace Renci.SshNet.IntegrationTests.TestsFixtures +{ + /// + /// The base class for integration tests + /// + public abstract class IntegrationTestBase + { + private readonly InfrastructureFixture _infrastructureFixture; + + /// + /// The SSH Server host name. + /// + public string? SshServerHostName + { + get + { + return _infrastructureFixture.SshServerHostName; + } + } + + /// + /// The SSH Server host name + /// + public ushort SshServerPort + { + get + { + return _infrastructureFixture.SshServerPort; + } + } + + /// + /// The admin user that can use SSH Server. + /// + public SshUser AdminUser + { + get + { + return _infrastructureFixture.AdminUser; + } + } + + /// + /// The normal user that can use SSH Server. + /// + public SshUser User + { + get + { + return _infrastructureFixture.User; + } + } + + protected IntegrationTestBase() + { + _infrastructureFixture = InfrastructureFixture.Instance; + ShowInfrastructureInformation(); + } + + private void ShowInfrastructureInformation() + { + Console.WriteLine($"SSH Server host name: {_infrastructureFixture.SshServerHostName}"); + Console.WriteLine($"SSH Server port: {_infrastructureFixture.SshServerPort}"); + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs b/src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs new file mode 100644 index 000000000..9a67f65c3 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs @@ -0,0 +1,16 @@ +锘縩amespace Renci.SshNet.IntegrationTests.TestsFixtures +{ + public class SshUser + { + public string UserName { get; } + + public string Password { get; } + + public SshUser(string userName, string password) + { + UserName = userName; + Password = password; + } + } +} + diff --git a/src/Renci.SshNet.IntegrationTests/Usings.cs b/src/Renci.SshNet.IntegrationTests/Usings.cs new file mode 100644 index 000000000..3d31edecb --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/Usings.cs @@ -0,0 +1,2 @@ +global using Microsoft.VisualStudio.TestTools.UnitTesting; +global using Renci.SshNet.IntegrationTests.TestsFixtures; diff --git a/src/Renci.SshNet.IntegrationTests/server/script/start.sh b/src/Renci.SshNet.IntegrationTests/server/script/start.sh new file mode 100644 index 000000000..e7e9f758c --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/server/script/start.sh @@ -0,0 +1,10 @@ +#!/bin/ash +/usr/sbin/syslog-ng + +# allow us to make changes to /etc/hosts; we need this for the port forwarding tests +chmod 777 /etc/hosts + +# start PAM-enabled ssh daemon as we also want keyboard-interactive authentication to work +/usr/sbin/sshd.pam + +tail -f < /var/log/auth.log diff --git a/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ecdsa_key b/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ecdsa_key new file mode 100644 index 000000000..5739844cf --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ecdsa_key @@ -0,0 +1,9 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQTtDoci0CaEgyR+p+ersiYltKUSqZx/ +MffWpnEPfGgnFI81huQw0D9e/SqABbeHtrzcSWskSZc0f2jjFxyqVkliAAAAsDrEln06xJ +Z9AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBO0OhyLQJoSDJH6n +56uyJiW0pRKpnH8x99amcQ98aCcUjzWG5DDQP179KoAFt4e2vNxJayRJlzR/aOMXHKpWSW +IAAAAgYdRMomjDSquRMSYTvEIzX7cReJ2grVIWsxIOLyhJnw0AAAAWcm9vdEBVYnVudHUx +OTEwRGVza3RvcAEC +-----END OPENSSH PRIVATE KEY----- diff --git a/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ed25519_key b/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ed25519_key new file mode 100644 index 000000000..8e45178e6 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ed25519_key @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACCCMW3VnuKfj6AxBQ7gJ4qAfEgw/YJl9q3AXyelCw+OdwAAAKDKcLC0ynCw +tAAAAAtzc2gtZWQyNTUxOQAAACCCMW3VnuKfj6AxBQ7gJ4qAfEgw/YJl9q3AXyelCw+Odw +AAAED9TRnDkG0tzdZv5oPJCXwzqrkxut7y33A8Wi8AzusJL4IxbdWe4p+PoDEFDuAnioB8 +SDD9gmX2rcBfJ6ULD453AAAAFnJvb3RAVWJ1bnR1MTkxMERlc2t0b3ABAgMEBQYH +-----END OPENSSH PRIVATE KEY----- diff --git a/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_rsa_key b/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_rsa_key new file mode 100644 index 000000000..edb94f341 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_rsa_key @@ -0,0 +1,38 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +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 +-----END OPENSSH PRIVATE KEY----- diff --git a/src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys b/src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys new file mode 100644 index 000000000..484a0bdcc --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys @@ -0,0 +1,4 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4N0T6VopnwPSYQUw0waQNhBjz0DYFQwvkv4OwWYSf//fJF3M6bH42Tn2J+IlQ+4/fCFnE3m99seV5T1myEj7fsupNteY2sKFGXENLGtAD/76FM0iBmXx76xlSTyZSSmNDIRU4xUR23cfc+al84F5mO2lEk+5Zr3Qn5JUpucBfis4vtu0sMDgZ4w1d0tcuXkT/MEJn2iX2cnxbSy5qNAPHu7b+LEfXBv2OrMDqPrx/X6QREgi3w5RxL5kz7bvitWsIwIvb3ST2ARAArBwb8pEyp2A/w5p22rkQtL+3ibZ8fkmpgn33f31AZPgtM++iJPBmPKFjArcWEJ9fIVB/6DAj +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPzzrPpItEjNG7tU0DpJJ4pkI01E9d6K61OKTVPdFQSyGCdMj9XdP93lC6sJA+9/ahvf5F3gWEKxUJL2CKUiFWw= +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBLSsu/HNKiaALhQ26UDv+N0AFdMb26fMVrOKe866CGu6ajSf9HUOhJFdjhseihB2rTalMPr8MrcXNLufii4mL8u4l9fUQXFgwnM/ZpiVPSs6C+8i4u/ZDg7Nx2NXybNIgQ== +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACB4WgRgGBRo6Uk+cRgg8tJPCbEtGURRWlUA7PDDerXR+P9O6mm3L99Etxsyh5XNYqXyaMNtH5c51ooMajrFwcayAHIhPPb8X3CsTwEfIUQ96aDyHQMotbRfnkn6uefeUTRrSNcqeAndUtVyAqBdqbsq2mgJYXHrz2NUKlPFYgauQi+WQ== \ No newline at end of file diff --git a/src/Renci.SshNet.sln b/src/Renci.SshNet.sln index 09953551d..c73ed0faa 100644 --- a/src/Renci.SshNet.sln +++ b/src/Renci.SshNet.sln @@ -42,6 +42,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D21A4D03-0 ..\test\Directory.Build.props = ..\test\Directory.Build.props EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.IntegrationTests", "Renci.SshNet.IntegrationTests\Renci.SshNet.IntegrationTests.csproj", "{EEF98046-729C-419E-932D-4E569073C8CC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -84,6 +86,26 @@ Global {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Mixed Platforms.Build.0 = Release|Any CPU {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x64.ActiveCfg = Release|Any CPU {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x86.ActiveCfg = Release|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|ARM.ActiveCfg = Debug|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|ARM.Build.0 = Debug|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|x64.ActiveCfg = Debug|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|x64.Build.0 = Debug|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|x86.ActiveCfg = Debug|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|x86.Build.0 = Debug|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Release|Any CPU.Build.0 = Release|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Release|ARM.ActiveCfg = Release|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Release|ARM.Build.0 = Release|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Release|x64.ActiveCfg = Release|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Release|x64.Build.0 = Release|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Release|x86.ActiveCfg = Release|Any CPU + {EEF98046-729C-419E-932D-4E569073C8CC}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 6f567ec7bb2c190eaf10df3b4b36e25d752deab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Thu, 29 Jun 2023 06:31:15 +0200 Subject: [PATCH 27/96] Remove todos --- .../TestsFixtures/InfrastructureFixture.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs b/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs index 3c6a0572c..340410ff0 100644 --- a/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs +++ b/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs @@ -29,10 +29,8 @@ public static InfrastructureFixture Instance public ushort SshServerPort { get; set; } - // TODO the user name and password can be injected to dockerfile via arguments public SshUser AdminUser = new SshUser("sshnetadm", "ssh4ever"); - // TODO the user name and password can be injected to dockerfile via arguments public SshUser User = new SshUser("sshnet", "ssh4ever"); public async Task InitializeAsync() From 3d36f88abb54c49bfe4ff4753492ebebd3cdea20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Fri, 25 Aug 2023 11:21:30 +0200 Subject: [PATCH 28/96] Update CODEOWNERS --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index b5c81321d..31f99465e 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @drieseng \ No newline at end of file +* @drieseng @WojciechNagorski From 82dc77a2f8c74318c87e095a0f946ffde98ad678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Wed, 30 Aug 2023 06:10:28 +0200 Subject: [PATCH 29/96] Use correct SSH.NET --- ...onTests.csproj => IntegrationTests.csproj} | 26 ++++-- .../ScpClientTests.cs | 6 +- .../SftpClientTests.cs | 89 +++++++++++++------ .../SshClientTests.cs | 6 +- .../TestInitializer.cs | 3 +- .../TestsFixtures/InfrastructureFixture.cs | 4 +- .../TestsFixtures/IntegrationTestBase.cs | 3 +- .../TestsFixtures/SshUser.cs | 2 +- src/Renci.SshNet.IntegrationTests/Usings.cs | 36 +++++++- src/Renci.SshNet.IntegrationTests/app.config | 15 ++++ .../Renci.SshNet.Tests.csproj | 6 +- src/Renci.SshNet.sln | 2 +- .../Properties/CommonAssemblyInfo.cs | 10 +-- 13 files changed, 148 insertions(+), 60 deletions(-) rename src/Renci.SshNet.IntegrationTests/{Renci.SshNet.IntegrationTests.csproj => IntegrationTests.csproj} (65%) create mode 100644 src/Renci.SshNet.IntegrationTests/app.config diff --git a/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj b/src/Renci.SshNet.IntegrationTests/IntegrationTests.csproj similarity index 65% rename from src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj rename to src/Renci.SshNet.IntegrationTests/IntegrationTests.csproj index bf09d62cc..244ee6f3a 100644 --- a/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj +++ b/src/Renci.SshNet.IntegrationTests/IntegrationTests.csproj @@ -1,4 +1,4 @@ - +锘 net7.0 @@ -7,6 +7,7 @@ false true + true $(NoWarn);CS1591 + - - - - - + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all + + + LocalSshNet + + + + + + PreserveNewest + + + diff --git a/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs b/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs index 62cbaeb0b..a03b04a3a 100644 --- a/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs +++ b/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs @@ -1,6 +1,4 @@ -using System.Text; - -namespace Renci.SshNet.IntegrationTests +namespace IntegrationTests { /// /// The SCP client integration tests @@ -18,7 +16,7 @@ public ScpClientTests() [TestMethod] - public void Scp_Upload_And_Download_FileStream() + public void Upload_And_Download_FileStream() { var file = $"/tmp/{Guid.NewGuid()}.txt"; var fileContent = "File content !@#$%^&*()_+{}:,./<>[];'\\|"; diff --git a/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs b/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs index 5eb9a2dbe..dfb406475 100644 --- a/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs +++ b/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs @@ -1,8 +1,4 @@ -using System.Text; - -using Renci.SshNet.Common; - -namespace Renci.SshNet.IntegrationTests +namespace IntegrationTests { /// /// The SFTP client integration tests @@ -19,35 +15,72 @@ public SftpClientTests() } [TestMethod] - public void Test_Sftp_ListDirectory_Home_Directory() + public void Create_directory_with_contents_and_list_it() + { + var testDirectory = "/home/sshnet/sshnet-test"; + var testFileName = "test-file.txt"; + var testFilePath = $"{testDirectory}/{testFileName}"; + var testContent = "file content"; + + // Create new directory and check if it exists + _sftpClient.CreateDirectory(testDirectory); + Assert.IsTrue(_sftpClient.Exists(testDirectory)); + + // Upload file and check if it exists + using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(testContent)); + _sftpClient.UploadFile(fileStream, testFilePath); + Assert.IsTrue(_sftpClient.Exists(testFilePath)); + + // Check if ListDirectory works + var files = _sftpClient.ListDirectory(testDirectory); + + _sftpClient.DeleteFile(testFilePath); + _sftpClient.DeleteDirectory(testDirectory); + + var builder = new StringBuilder(); + foreach (var file in files) + { + builder.AppendLine($"{file.FullName} {file.IsRegularFile} {file.IsDirectory}"); + } + + Assert.AreEqual(@"/home/sshnet/sshnet-test/. False True +/home/sshnet/sshnet-test/.. False True +/home/sshnet/sshnet-test/test-file.txt True False +", builder.ToString()); + } + + [TestMethod] + public async Task Create_directory_with_contents_and_list_it_async() { + var testDirectory = "/home/sshnet/sshnet-test"; + var testFileName = "test-file.txt"; + var testFilePath = $"{testDirectory}/{testFileName}"; + var testContent = "file content"; + + // Create new directory and check if it exists + _sftpClient.CreateDirectory(testDirectory); + Assert.IsTrue(_sftpClient.Exists(testDirectory)); + + // Upload file and check if it exists + using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(testContent)); + _sftpClient.UploadFile(fileStream, testFilePath); + Assert.IsTrue(_sftpClient.Exists(testFilePath)); + + // Check if ListDirectory works + var files = await _sftpClient.ListDirectoryAsync(testDirectory, CancellationToken.None); + + _sftpClient.DeleteFile(testFilePath); + _sftpClient.DeleteDirectory(testDirectory); + var builder = new StringBuilder(); - var files = _sftpClient.ListDirectory("/"); foreach (var file in files) { - builder.AppendLine($"{file.FullName}"); + builder.AppendLine($"{file.FullName} {file.IsRegularFile} {file.IsDirectory}"); } - Assert.AreEqual(@"/usr -/var -/. -/bin -/mnt -/opt -/tmp -/etc -/root -/media -/.. -/dev -/proc -/sys -/home -/lib -/sbin -/run -/srv -/.dockerenv + Assert.AreEqual(@"/home/sshnet/sshnet-test/. False True +/home/sshnet/sshnet-test/.. False True +/home/sshnet/sshnet-test/test-file.txt True False ", builder.ToString()); } diff --git a/src/Renci.SshNet.IntegrationTests/SshClientTests.cs b/src/Renci.SshNet.IntegrationTests/SshClientTests.cs index ba25bc6c7..33a90d13e 100644 --- a/src/Renci.SshNet.IntegrationTests/SshClientTests.cs +++ b/src/Renci.SshNet.IntegrationTests/SshClientTests.cs @@ -1,6 +1,4 @@ -using System.Text; - -namespace Renci.SshNet.IntegrationTests +namespace IntegrationTests { /// /// The SSH client integration tests @@ -17,7 +15,7 @@ public SshClientTests() } [TestMethod] - public void Test_SSH_Echo_Command() + public void Echo_Command_with_all_characters() { var builder = new StringBuilder(); var response = _sshClient.RunCommand("echo $'test !@#$%^&*()_+{}:,./<>[];\\|'"); diff --git a/src/Renci.SshNet.IntegrationTests/TestInitializer.cs b/src/Renci.SshNet.IntegrationTests/TestInitializer.cs index 5e0b7d876..16b0a3eca 100644 --- a/src/Renci.SshNet.IntegrationTests/TestInitializer.cs +++ b/src/Renci.SshNet.IntegrationTests/TestInitializer.cs @@ -1,4 +1,4 @@ -namespace Renci.SshNet.IntegrationTests +namespace IntegrationTests { [TestClass] public class TestInitializer @@ -7,7 +7,6 @@ public class TestInitializer [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "MSTests requires context parameter")] public static async Task Initialize(TestContext context) { - await InfrastructureFixture.Instance.InitializeAsync(); } diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs b/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs index 340410ff0..63e6c70ce 100644 --- a/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs +++ b/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs @@ -2,13 +2,12 @@ using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Containers; -namespace Renci.SshNet.IntegrationTests.TestsFixtures +namespace IntegrationTests.TestsFixtures { public sealed class InfrastructureFixture : IDisposable { private InfrastructureFixture() { - } private static readonly Lazy InstanceLazy = new Lazy(() => new InfrastructureFixture()); @@ -48,7 +47,6 @@ public async Task InitializeAsync() _sshServer = new ContainerBuilder() .WithHostname("renci-ssh-tests-server") .WithImage(_sshServerImage) - //.WithPrivileged(true) .WithPortBinding(22, true) .Build(); diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs b/src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs index 6079da1b5..521f947cc 100644 --- a/src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs +++ b/src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs @@ -1,5 +1,4 @@ -锘 -namespace Renci.SshNet.IntegrationTests.TestsFixtures +锘縩amespace IntegrationTests.TestsFixtures { /// /// The base class for integration tests diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs b/src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs index 9a67f65c3..5f2ee4d56 100644 --- a/src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs +++ b/src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs @@ -1,4 +1,4 @@ -锘縩amespace Renci.SshNet.IntegrationTests.TestsFixtures +锘縩amespace IntegrationTests.TestsFixtures { public class SshUser { diff --git a/src/Renci.SshNet.IntegrationTests/Usings.cs b/src/Renci.SshNet.IntegrationTests/Usings.cs index 3d31edecb..bc21218d4 100644 --- a/src/Renci.SshNet.IntegrationTests/Usings.cs +++ b/src/Renci.SshNet.IntegrationTests/Usings.cs @@ -1,2 +1,36 @@ +#pragma warning disable IDE0005 + +extern alias LocalSshNet; + +global using System.Text; + global using Microsoft.VisualStudio.TestTools.UnitTesting; -global using Renci.SshNet.IntegrationTests.TestsFixtures; + +global using IntegrationTests.TestsFixtures; + +// The testcontainers library uses SSH.NET, so we have two versions of SSH.NET in the project. +// We need to explicitly choose which version we want to test. +// To avoid problems, we import all namespaces. +global using LocalSshNet::Renci.SshNet; +global using LocalSshNet::Renci.SshNet.Abstractions; +global using LocalSshNet::Renci.SshNet.Channels; +global using LocalSshNet::Renci.SshNet.Common; +global using LocalSshNet::Renci.SshNet.Compression; +global using LocalSshNet::Renci.SshNet.Connection; +global using LocalSshNet::Renci.SshNet.Messages; +global using LocalSshNet::Renci.SshNet.Messages.Authentication; +global using LocalSshNet::Renci.SshNet.Messages.Connection; +global using LocalSshNet::Renci.SshNet.Messages.Transport; +global using LocalSshNet::Renci.SshNet.NetConf; +global using LocalSshNet::Renci.SshNet.Security; +global using LocalSshNet::Renci.SshNet.Security.Chaos; +global using LocalSshNet::Renci.SshNet.Security.Chaos.NaCl; +global using LocalSshNet::Renci.SshNet.Security.Chaos.NaCl.Internal; +global using LocalSshNet::Renci.SshNet.Security.Cryptography; +global using LocalSshNet::Renci.SshNet.Security.Cryptography.Ciphers; +global using LocalSshNet::Renci.SshNet.Security.Org; +global using LocalSshNet::Renci.SshNet.Security.Org.BouncyCastle; + +global using LocalSshNet::Renci.SshNet.Sftp; + + diff --git a/src/Renci.SshNet.IntegrationTests/app.config b/src/Renci.SshNet.IntegrationTests/app.config new file mode 100644 index 000000000..3571058ce --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/app.config @@ -0,0 +1,15 @@ +锘 + + + + + + + + + + + + diff --git a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index 88693e5aa..94a4e8015 100644 --- a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -64,9 +64,9 @@ - - - + + + diff --git a/src/Renci.SshNet.sln b/src/Renci.SshNet.sln index c73ed0faa..be2686bee 100644 --- a/src/Renci.SshNet.sln +++ b/src/Renci.SshNet.sln @@ -42,7 +42,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D21A4D03-0 ..\test\Directory.Build.props = ..\test\Directory.Build.props EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.IntegrationTests", "Renci.SshNet.IntegrationTests\Renci.SshNet.IntegrationTests.csproj", "{EEF98046-729C-419E-932D-4E569073C8CC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTests", "Renci.SshNet.IntegrationTests\IntegrationTests.csproj", "{EEF98046-729C-419E-932D-4E569073C8CC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/src/Renci.SshNet/Properties/CommonAssemblyInfo.cs b/src/Renci.SshNet/Properties/CommonAssemblyInfo.cs index 0883060cc..d99338feb 100644 --- a/src/Renci.SshNet/Properties/CommonAssemblyInfo.cs +++ b/src/Renci.SshNet/Properties/CommonAssemblyInfo.cs @@ -5,13 +5,13 @@ [assembly: AssemblyDescription("SSH.NET is a Secure Shell (SSH) library for .NET, optimized for parallelism.")] [assembly: AssemblyCompany("Renci")] [assembly: AssemblyProduct("SSH.NET")] -[assembly: AssemblyCopyright("Copyright Renci 2010-2021")] +[assembly: AssemblyCopyright("Copyright Renci 2010-2023")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("2020.0.1")] -[assembly: AssemblyFileVersion("2020.0.1")] -[assembly: AssemblyInformationalVersion("2020.0.1")] +[assembly: AssemblyVersion("2023.0.0")] +[assembly: AssemblyFileVersion("2023.0.0")] +[assembly: AssemblyInformationalVersion("2023.0.0")] [assembly: CLSCompliant(false)] // Setting ComVisible to false makes the types in this assembly not visible @@ -24,4 +24,4 @@ [assembly: AssemblyConfiguration("Debug")] #else [assembly: AssemblyConfiguration("Release")] -#endif \ No newline at end of file +#endif From 7cd0487785c82730ecfe277cb9964ab2e101a4af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Wed, 30 Aug 2023 10:22:10 +0200 Subject: [PATCH 30/96] ListDirectoryAsync return IAsyncEnumerable (#1126) * ListDirectoryAsync return IAsyncEnumerable * Fix documentation * Update README.md * Fix * Add Sftp ListDirectoryAsync test * Revert * Integration tests for ListDirectoryAsync with IAsyncEnumerable --- README.md | 2 +- build/build.proj | 4 +++ build/nuget/SSH.NET.nuspec | 3 ++ .../SftpClientTests.cs | 10 +++---- .../Classes/SftpClientTest.ListDirectory.cs | 30 ++++++++++++++++++- src/Renci.SshNet/ISftpClient.cs | 12 ++++---- src/Renci.SshNet/Renci.SshNet.csproj | 10 +++++-- src/Renci.SshNet/SftpClient.cs | 21 ++++++------- 8 files changed, 67 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 5708d0af4..2c0dc015c 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ Private keys can be encrypted using one of the following cipher methods: ## Framework Support **SSH.NET** supports the following target frameworks: * .NETFramework 4.6.2 (and higher) -* .NET Standard 2.0 +* .NET Standard 2.0 and 2.1 * .NET 6 (and higher) ## Usage diff --git a/build/build.proj b/build/build.proj index d2911509c..97b406cf6 100644 --- a/build/build.proj +++ b/build/build.proj @@ -25,6 +25,10 @@ Renci.SshNet\bin\$(Configuration)\netstandard2.0 netstandard2.0 + + Renci.SshNet\bin\$(Configuration)\netstandard2.1 + netstandard2.1 + Renci.SshNet\bin\$(Configuration)\net6.0 net6.0 diff --git a/build/nuget/SSH.NET.nuspec b/build/nuget/SSH.NET.nuspec index a694592e0..55ce42e28 100644 --- a/build/nuget/SSH.NET.nuspec +++ b/build/nuget/SSH.NET.nuspec @@ -19,6 +19,9 @@ + + + diff --git a/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs b/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs index dfb406475..9648587a1 100644 --- a/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs +++ b/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs @@ -67,17 +67,17 @@ public async Task Create_directory_with_contents_and_list_it_async() Assert.IsTrue(_sftpClient.Exists(testFilePath)); // Check if ListDirectory works - var files = await _sftpClient.ListDirectoryAsync(testDirectory, CancellationToken.None); - - _sftpClient.DeleteFile(testFilePath); - _sftpClient.DeleteDirectory(testDirectory); + var files = _sftpClient.ListDirectoryAsync(testDirectory, CancellationToken.None); var builder = new StringBuilder(); - foreach (var file in files) + await foreach (var file in files) { builder.AppendLine($"{file.FullName} {file.IsRegularFile} {file.IsDirectory}"); } + _sftpClient.DeleteFile(testFilePath); + _sftpClient.DeleteDirectory(testDirectory); + Assert.AreEqual(@"/home/sshnet/sshnet-test/. False True /home/sshnet/sshnet-test/.. False True /home/sshnet/sshnet-test/test-file.txt True False diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs index 69f90aefe..6a19ce5a3 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs @@ -4,6 +4,10 @@ using System; using System.Diagnostics; using System.Linq; +#if NET6_0_OR_GREATER +using System.Threading; +using System.Threading.Tasks; +#endif namespace Renci.SshNet.Tests.Classes { @@ -89,6 +93,30 @@ public void Test_Sftp_ListDirectory_Current() } } +#if NET6_0_OR_GREATER + [TestMethod] + [TestCategory("Sftp")] + [TestCategory("integration")] + public async Task Test_Sftp_ListDirectoryAsync_Current() + { + using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + { + sftp.Connect(); + var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromMinutes(1)); + var count = 0; + await foreach(var file in sftp.ListDirectoryAsync(".", cts.Token)) + { + count++; + Debug.WriteLine(file.FullName); + } + + Assert.IsTrue(count > 0); + + sftp.Disconnect(); + } + } +#endif [TestMethod] [TestCategory("Sftp")] [TestCategory("integration")] @@ -265,4 +293,4 @@ public void Test_Sftp_Call_EndListDirectory_Twice() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/ISftpClient.cs b/src/Renci.SshNet/ISftpClient.cs index 82117295c..21d05ae7c 100644 --- a/src/Renci.SshNet/ISftpClient.cs +++ b/src/Renci.SshNet/ISftpClient.cs @@ -40,7 +40,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// SSH_FXP_DATA protocol fields. /// /// - /// The size of the each indivual SSH_FXP_DATA message is limited to the + /// The size of the each individual SSH_FXP_DATA message is limited to the /// local maximum packet size of the channel, which is set to 64 KB /// for SSH.NET. However, the peer can limit this even further. /// @@ -699,21 +699,23 @@ public interface ISftpClient : IBaseClient, IDisposable /// The method was called after the client was disposed. IEnumerable ListDirectory(string path, Action listCallback = null); +#if FEATURE_ASYNC_ENUMERABLE /// - /// Asynchronously retrieves list of files in remote directory. + /// Asynchronously enumerates the files in remote directory. /// /// The path. /// The to observe. /// - /// A that represents the asynchronous list operation. - /// The task result contains an enumerable collection of for the files in the directory specified by . + /// An of that represents the asynchronous enumeration operation. + /// The enumeration contains an async stream of for the files in the directory specified by . /// /// is null. /// Client is not connected. /// Permission to list the contents of the directory was denied by the remote host. -or- A SSH command was denied by the server. /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. - Task> ListDirectoryAsync(string path, CancellationToken cancellationToken); + IAsyncEnumerable ListDirectoryAsync(string path, CancellationToken cancellationToken); +#endif //FEATURE_ASYNC_ENUMERABLE /// /// Opens a on the specified path with read/write access. diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index 9fcd62fd3..e55911d55 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -2,18 +2,22 @@ false Renci.SshNet - net462;netstandard2.0;net6.0;net7.0 + net462;netstandard2.0;netstandard2.1;net6.0;net7.0 FEATURE_BINARY_SERIALIZATION;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_DNS_SYNC;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160 - + - + FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP + + + $(DefineConstants);FEATURE_ASYNC_ENUMERABLE + diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index a275413a1..e6f9cb2d6 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -10,6 +10,9 @@ using Renci.SshNet.Common; using Renci.SshNet.Sftp; using System.Threading.Tasks; +#if FEATURE_ASYNC_ENUMERABLE +using System.Runtime.CompilerServices; +#endif namespace Renci.SshNet { @@ -92,7 +95,7 @@ public TimeSpan OperationTimeout /// SSH_FXP_DATA protocol fields. /// /// - /// The size of the each indivual SSH_FXP_DATA message is limited to the + /// The size of the each individual SSH_FXP_DATA message is limited to the /// local maximum packet size of the channel, which is set to 64 KB /// for SSH.NET. However, the peer can limit this even further. /// @@ -584,21 +587,22 @@ public IEnumerable ListDirectory(string path, Action listCallbac return InternalListDirectory(path, listCallback); } +#if FEATURE_ASYNC_ENUMERABLE /// - /// Asynchronously retrieves list of files in remote directory. + /// Asynchronously enumerates the files in remote directory. /// /// The path. /// The to observe. /// - /// A that represents the asynchronous list operation. - /// The task result contains an enumerable collection of for the files in the directory specified by . + /// An of that represents the asynchronous enumeration operation. + /// The enumeration contains an async stream of for the files in the directory specified by . /// /// is null. /// Client is not connected. /// Permission to list the contents of the directory was denied by the remote host. -or- A SSH command was denied by the server. /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. - public async Task> ListDirectoryAsync(string path, CancellationToken cancellationToken) + public async IAsyncEnumerable ListDirectoryAsync(string path, [EnumeratorCancellation] CancellationToken cancellationToken) { CheckDisposed(); @@ -616,7 +620,6 @@ public async Task> ListDirectoryAsync(string path, Cancel var fullPath = await _sftpSession.GetCanonicalPathAsync(path, cancellationToken).ConfigureAwait(false); - var result = new List(); var handle = await _sftpSession.RequestOpenDirAsync(fullPath, cancellationToken).ConfigureAwait(false); try { @@ -634,18 +637,16 @@ public async Task> ListDirectoryAsync(string path, Cancel foreach (var file in files) { - result.Add(new SftpFile(_sftpSession, basePath + file.Key, file.Value)); + yield return new SftpFile(_sftpSession, basePath + file.Key, file.Value); } } - } finally { await _sftpSession.RequestCloseAsync(handle, cancellationToken).ConfigureAwait(false); } - - return result; } +#endif //FEATURE_ASYNC_ENUMERABLE /// /// Begins an asynchronous operation of retrieving list of files in remote directory. From 004b57ae9e7ca07f12e7192d7987a8e5d950b04c Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Wed, 30 Aug 2023 14:56:49 +0200 Subject: [PATCH 31/96] Fix the assembly resolution build warning (#1165) --- .../IntegrationTests.csproj | 23 +++++++++------- .../ScpClientTests.cs | 2 ++ .../SftpClientTests.cs | 3 +++ .../SshClientTests.cs | 2 ++ src/Renci.SshNet.IntegrationTests/Usings.cs | 27 ------------------- src/Renci.SshNet.IntegrationTests/app.config | 15 ----------- 6 files changed, 20 insertions(+), 52 deletions(-) delete mode 100644 src/Renci.SshNet.IntegrationTests/app.config diff --git a/src/Renci.SshNet.IntegrationTests/IntegrationTests.csproj b/src/Renci.SshNet.IntegrationTests/IntegrationTests.csproj index 244ee6f3a..2fdbcfd74 100644 --- a/src/Renci.SshNet.IntegrationTests/IntegrationTests.csproj +++ b/src/Renci.SshNet.IntegrationTests/IntegrationTests.csproj @@ -7,7 +7,6 @@ false true - true + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -33,15 +44,7 @@ - - LocalSshNet - - - - - - PreserveNewest - + diff --git a/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs b/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs index a03b04a3a..5db1fe51c 100644 --- a/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs +++ b/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs @@ -1,3 +1,5 @@ +using Renci.SshNet; + namespace IntegrationTests { /// diff --git a/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs b/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs index 9648587a1..9e91ad70d 100644 --- a/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs +++ b/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs @@ -1,3 +1,6 @@ +using Renci.SshNet; +using Renci.SshNet.Common; + namespace IntegrationTests { /// diff --git a/src/Renci.SshNet.IntegrationTests/SshClientTests.cs b/src/Renci.SshNet.IntegrationTests/SshClientTests.cs index 33a90d13e..867514441 100644 --- a/src/Renci.SshNet.IntegrationTests/SshClientTests.cs +++ b/src/Renci.SshNet.IntegrationTests/SshClientTests.cs @@ -1,3 +1,5 @@ +using Renci.SshNet; + namespace IntegrationTests { /// diff --git a/src/Renci.SshNet.IntegrationTests/Usings.cs b/src/Renci.SshNet.IntegrationTests/Usings.cs index bc21218d4..e6180a739 100644 --- a/src/Renci.SshNet.IntegrationTests/Usings.cs +++ b/src/Renci.SshNet.IntegrationTests/Usings.cs @@ -1,36 +1,9 @@ #pragma warning disable IDE0005 -extern alias LocalSshNet; - global using System.Text; global using Microsoft.VisualStudio.TestTools.UnitTesting; global using IntegrationTests.TestsFixtures; -// The testcontainers library uses SSH.NET, so we have two versions of SSH.NET in the project. -// We need to explicitly choose which version we want to test. -// To avoid problems, we import all namespaces. -global using LocalSshNet::Renci.SshNet; -global using LocalSshNet::Renci.SshNet.Abstractions; -global using LocalSshNet::Renci.SshNet.Channels; -global using LocalSshNet::Renci.SshNet.Common; -global using LocalSshNet::Renci.SshNet.Compression; -global using LocalSshNet::Renci.SshNet.Connection; -global using LocalSshNet::Renci.SshNet.Messages; -global using LocalSshNet::Renci.SshNet.Messages.Authentication; -global using LocalSshNet::Renci.SshNet.Messages.Connection; -global using LocalSshNet::Renci.SshNet.Messages.Transport; -global using LocalSshNet::Renci.SshNet.NetConf; -global using LocalSshNet::Renci.SshNet.Security; -global using LocalSshNet::Renci.SshNet.Security.Chaos; -global using LocalSshNet::Renci.SshNet.Security.Chaos.NaCl; -global using LocalSshNet::Renci.SshNet.Security.Chaos.NaCl.Internal; -global using LocalSshNet::Renci.SshNet.Security.Cryptography; -global using LocalSshNet::Renci.SshNet.Security.Cryptography.Ciphers; -global using LocalSshNet::Renci.SshNet.Security.Org; -global using LocalSshNet::Renci.SshNet.Security.Org.BouncyCastle; - -global using LocalSshNet::Renci.SshNet.Sftp; - diff --git a/src/Renci.SshNet.IntegrationTests/app.config b/src/Renci.SshNet.IntegrationTests/app.config deleted file mode 100644 index 3571058ce..000000000 --- a/src/Renci.SshNet.IntegrationTests/app.config +++ /dev/null @@ -1,15 +0,0 @@ -锘 - - - - - - - - - - - - From 9f1699b5602807e50b8ea6b4300a12ff9d00f93f Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Wed, 6 Sep 2023 16:18:25 +0200 Subject: [PATCH 32/96] Delete performance/longrunning tests (#1143) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Wojciech Nag贸rski --- appveyor.yml | 4 +- .../Classes/Common/ASCIIEncodingTest.cs | 241 ------------------ .../Classes/Common/BigIntegerTest.cs | 56 ---- .../Classes/Common/ExtensionsTest_Concat.cs | 81 ------ .../ExtensionsTest_IsEqualTo_ByteArray.cs | 90 ------- .../Common/ExtensionsTest_Take_Count.cs | 91 ------- 6 files changed, 2 insertions(+), 561 deletions(-) delete mode 100644 src/Renci.SshNet.Tests/Classes/Common/ASCIIEncodingTest.cs diff --git a/appveyor.yml b/appveyor.yml index d380a3f58..c9bb51683 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,6 +9,6 @@ build: test_script: - cmd: >- - vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net462\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning" --blame + vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net462\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration" --blame - vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net7.0\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration&TestCategory!=LongRunning" --blame \ No newline at end of file + vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net7.0\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration" --blame diff --git a/src/Renci.SshNet.Tests/Classes/Common/ASCIIEncodingTest.cs b/src/Renci.SshNet.Tests/Classes/Common/ASCIIEncodingTest.cs deleted file mode 100644 index 6e614b523..000000000 --- a/src/Renci.SshNet.Tests/Classes/Common/ASCIIEncodingTest.cs +++ /dev/null @@ -1,241 +0,0 @@ -锘縰sing System; -using System.Diagnostics; -using System.Globalization; -using System.Text; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - [TestClass] - public class ASCIIEncodingTest : TestBase - { - private Random _random; - private Encoding _ascii; - - [TestInitialize] - public void SetUp() - { - _random = new Random(); - _ascii = SshData.Ascii; - } - - [TestMethod] - public void GetByteCount_Chars() - { - var chars = new[] { 'B', 'e', 'l', 'g', 'i', 'u', 'm' }; - - var actual = _ascii.GetByteCount(chars); - - Assert.AreEqual(chars.Length, actual); - } - - [TestMethod] - public void GetBytes_CharArray() - { - var chars = new[] {'B', 'e', 'l', 'g', 'i', 'u', 'm'}; - - var actual = _ascii.GetBytes(chars); - - Assert.IsNotNull(actual); - Assert.AreEqual(7, actual.Length); - Assert.AreEqual(0x42, actual[0]); - Assert.AreEqual(0x65, actual[1]); - Assert.AreEqual(0x6c, actual[2]); - Assert.AreEqual(0x67, actual[3]); - Assert.AreEqual(0x69, actual[4]); - Assert.AreEqual(0x75, actual[5]); - Assert.AreEqual(0x6d ,actual[6]); - } - - [TestMethod] - public void GetCharCount_Bytes() - { - var bytes = new byte[] { 0x42, 0x65, 0x6c, 0x67, 0x69, 0x75, 0x6d }; - - var actual = _ascii.GetCharCount(bytes); - - Assert.AreEqual(bytes.Length, actual); - } - - [TestMethod] - public void GetChars_Bytes() - { - var bytes = new byte[] {0x42, 0x65, 0x6c, 0x67, 0x69, 0x75, 0x6d}; - - var actual = _ascii.GetChars(bytes); - - Assert.AreEqual("Belgium", new string(actual)); - } - - [TestMethod] - public void GetChars_Bytes_DefaultFallback() - { - var bytes = new byte[] { 0x42, 0x65, 0x6c, 0x80, 0x69, 0x75, 0x6d }; - - var actual = _ascii.GetChars(bytes); - - Assert.AreEqual("Bel?ium", new string(actual)); - } - - [TestMethod] - public void GetMaxByteCount_ShouldReturnCharCountPlusOneWhenCharCountIsNonNegative() - { - var charCount = _random.Next(0, 20000); - - var actual = _ascii.GetMaxByteCount(charCount); - - Assert.AreEqual(++charCount, actual); - } - - [TestMethod] - public void GetMaxByteCount_ShouldThrowArgumentOutOfRangeExceptionWhenCharCountIsNegative() - { - var charCount = _random.Next(-5000, -1); - - try - { - var actual = _ascii.GetMaxByteCount(charCount); - Assert.Fail(actual.ToString(CultureInfo.InvariantCulture)); - } - catch (ArgumentOutOfRangeException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual("charCount", ex.ParamName); - } - } - - [TestMethod] - public void GetMaxCharCount_ShouldReturnByteCountWhenByteCountIsNonNegative() - { - var byteCount = _random.Next(0, 20000); - - var actual = _ascii.GetMaxCharCount(byteCount); - - Assert.AreEqual(byteCount, actual); - } - - [TestMethod] - public void GetMaxCharCount_ShouldThrowArgumentOutOfRangeExceptionWhenByteCountIsNegative() - { - var byteCount = _random.Next(-5000, -1); - - try - { - var actual = _ascii.GetMaxCharCount(byteCount); - Assert.Fail(actual.ToString(CultureInfo.InvariantCulture)); - } - catch (ArgumentOutOfRangeException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual("byteCount", ex.ParamName); - } - } - - [TestMethod] - public void GetPreamble() - { - var actual = _ascii.GetPreamble(); - - Assert.AreEqual(0, actual.Length); - } - - [TestMethod] - public void IsSingleByte() - { - Assert.IsTrue(_ascii.IsSingleByte); - } - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void GetBytes_Performance() - { - const string input = "eererzfdfdsfsfsfsqdqseererzfdfdsfsfsfsqdqseererzfdfdsfsfsfsqdqseererzfdfdsfsfsfsqdqseererzfdfdsfsfsfsqdqseererzfdfdsfsfsfsqdqseererzfdfdsfsfsfsqdqseererzfdfdsfsfsfsqdqseererzfdfdsfsfsfsqdqs"; - const int loopCount = 10000000; - var result = new byte[input.Length]; - - var corefxAscii = new System.Text.ASCIIEncoding(); - var sshAscii = _ascii; - - var stopWatch = new Stopwatch(); - - GC.Collect(); - GC.WaitForFullGCComplete(); - - stopWatch.Start(); - - for (var i = 0; i < loopCount; i++) - { - corefxAscii.GetBytes(input, 0, input.Length, result, 0); - } - - stopWatch.Stop(); - - Console.WriteLine(stopWatch.ElapsedMilliseconds); - - stopWatch.Reset(); - - GC.Collect(); - GC.WaitForFullGCComplete(); - - stopWatch.Start(); - - for (var i = 0; i < loopCount; i++) - { - sshAscii.GetBytes(input, 0, input.Length, result, 0); - } - - stopWatch.Stop(); - - Console.WriteLine(stopWatch.ElapsedMilliseconds); - } - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void GetChars_Performance() - { - var input = new byte[2000]; - new Random().NextBytes(input); - const int loopCount = 100000; - - var corefxAscii = new System.Text.ASCIIEncoding(); - var sshAscii = _ascii; - - var stopWatch = new Stopwatch(); - - GC.Collect(); - GC.WaitForFullGCComplete(); - - stopWatch.Start(); - - for (var i = 0; i < loopCount; i++) - { - var actual = corefxAscii.GetChars(input); - } - - stopWatch.Stop(); - - Console.WriteLine(stopWatch.ElapsedMilliseconds); - - stopWatch.Reset(); - - GC.Collect(); - GC.WaitForFullGCComplete(); - - stopWatch.Start(); - - for (var i = 0; i < loopCount; i++) - { - var actual = sshAscii.GetChars(input); - } - - stopWatch.Stop(); - - Console.WriteLine(stopWatch.ElapsedMilliseconds); - } - - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs b/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs index 0640697a2..af5613e87 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs @@ -11,7 +11,6 @@ //#define FEATURE_NUMERICS_BIGINTEGER using System; -using System.Diagnostics; using System.Globalization; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -1559,61 +1558,6 @@ public void Bug16526() } } - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void ToArray_Performance() - { - const int loopCount = 100000000; - var bigInteger = new BigInteger(Huge_a); - - var stopWatch = new Stopwatch(); - - GC.Collect(); - _ = GC.WaitForFullGCComplete(); - - stopWatch.Start(); - - for (var i = 0; i < loopCount; i++) - { - _ = bigInteger.ToByteArray(); - } - - GC.Collect(); - _ = GC.WaitForFullGCComplete(); - - stopWatch.Stop(); - - Console.WriteLine(stopWatch.ElapsedMilliseconds); - } - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Ctor_ByteArray_Performance() - { - const int loopCount = 100000000; - - var stopWatch = new Stopwatch(); - - GC.Collect(); - _ = GC.WaitForFullGCComplete(); - - stopWatch.Start(); - - for (var i = 0; i < loopCount; i++) - { - _ = new BigInteger(Huge_a); - } - - GC.Collect(); - _ = GC.WaitForFullGCComplete(); - - stopWatch.Stop(); - - Console.WriteLine(stopWatch.ElapsedMilliseconds); - } - [TestMethod] public void MinusOne() { diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs index 1b3785f8f..ad961bfc4 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs @@ -1,7 +1,5 @@ 锘縰sing System; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; @@ -96,85 +94,6 @@ public void ShouldConcatSecondToFirstWhenBothAreNotEmpty() Assert.AreEqual(second[1], actual[5]); } - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_LargeArray_FirstEmpty() - { - var first = Array.Empty(); - var second = CreateBuffer(50000); - const int runs = 10000; - - Performance(first, second, runs); - } - - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_LargeArray_SecondEmpty() - { - var first = CreateBuffer(50000); - var second = Array.Empty(); - const int runs = 10000; - - Performance(first, second, runs); - } - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_LargeArray_BothNotEmpty() - { - var first = CreateBuffer(50000); - var second = CreateBuffer(20000); - const int runs = 10000; - - Performance(first, second, runs); - } - - private static void Performance(byte[] first, byte[] second, int runs) - { - var stopWatch = new Stopwatch(); - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopWatch.Start(); - - for (var i = 0; i < runs; i++) - { - var result = Extensions.Concat(first, second); - var resultLength = result.Length; - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopWatch.Stop(); - - Console.WriteLine(stopWatch.ElapsedMilliseconds); - - stopWatch.Reset(); - stopWatch.Start(); - - for (var i = 0; i < runs; i++) - { - var result = Enumerable.Concat(first, second); - var resultLength = result.ToArray().Length; - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopWatch.Stop(); - - Console.WriteLine(stopWatch.ElapsedMilliseconds); - } - private byte[] CreateBuffer(int length) { var buffer = new byte[length]; diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs index c59fd5843..8d1d18076 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs @@ -1,5 +1,4 @@ 锘縰sing System; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; @@ -96,95 +95,6 @@ public void ShouldReturnTrueWhenLeftIsSameAsRight() Assert.IsTrue(Extensions.IsEqualTo(left, left)); } - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_LargeArray_Equal() - { - var buffer = CreateBuffer(50000); - var left = buffer.Concat(new byte[] {0x0a}); - var right = buffer.Concat(new byte[] {0x0a}); - const int runs = 10000; - - Performance(left, right, runs); - } - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_LargeArray_NotEqual_DifferentLength() - { - var left = CreateBuffer(50000); - var right = left.Concat(new byte[] {0x0a}); - const int runs = 10000; - - Performance(left, right, runs); - } - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_LargeArray_NotEqual_SameLength() - { - var buffer = CreateBuffer(50000); - var left = buffer.Concat(new byte[] {0x0a}); - var right = buffer.Concat(new byte[] {0x0b}); - const int runs = 10000; - - Performance(left, right, runs); - } - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_LargeArray_Same() - { - var left = CreateBuffer(50000); - var right = left.Concat(new byte[] {0x0a}); - const int runs = 10000; - - Performance(left, right, runs); - } - - private static void Performance(byte[] left, byte[] right, int runs) - { - var stopWatch = new Stopwatch(); - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopWatch.Start(); - - for (var i = 0; i < runs; i++) - { - _ = Extensions.IsEqualTo(left, right); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopWatch.Stop(); - - Console.WriteLine(stopWatch.ElapsedMilliseconds); - - stopWatch.Reset(); - stopWatch.Start(); - - for (var i = 0; i < runs; i++) - { - var result = System.Linq.Enumerable.SequenceEqual(left, right); - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopWatch.Stop(); - - Console.WriteLine(stopWatch.ElapsedMilliseconds); - } - private byte[] CreateBuffer(int length) { var buffer = new byte[length]; diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_Count.cs b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_Count.cs index 3d734da19..05a090611 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_Count.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_Count.cs @@ -1,7 +1,5 @@ 锘縰sing System; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; @@ -94,95 +92,6 @@ public void ShouldThrowArgumentExceptionWhenCountIsGreaterThanLengthOfValue() } } - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_LargeArray_All() - { - var value = CreateBuffer(50000); - var count = value.Length; - const int runs = 10000; - - Performance(value, count, runs); - } - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_LargeArray_LargeCount() - { - var value = CreateBuffer(50000); - const int count = 40000; - const int runs = 1000000; - - Performance(value, count, runs); - } - - [TestMethod] - [TestCategory("LongRunning")] - [TestCategory("Performance")] - public void Performance_LargeArray_SmallCount() - { - var value = CreateBuffer(50000); - const int count = 50; - const int runs = 1000000; - - Performance(value, count, runs); - } - - [TestMethod] - [TestCategory("Performance")] - public void Performance_LargeArray_ZeroCount() - { - var value = CreateBuffer(50000); - const int count = 0; - const int runs = 1000000; - - Performance(value, count, runs); - } - - private static void Performance(byte[] value, int count, int runs) - { - var stopWatch = new Stopwatch(); - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopWatch.Start(); - - for (var i = 0; i < runs; i++) - { - var result = Extensions.Take(value, count); - var resultLength = result.Length; - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopWatch.Stop(); - - Console.WriteLine(stopWatch.ElapsedMilliseconds); - - stopWatch.Reset(); - stopWatch.Start(); - - for (var i = 0; i < runs; i++) - { - var result = Enumerable.Take(value, count); - var resultLength = result.ToArray().Length; - } - - GC.Collect(); - GC.WaitForPendingFinalizers(); - GC.Collect(); - - stopWatch.Stop(); - - Console.WriteLine(stopWatch.ElapsedMilliseconds); - } - private byte[] CreateBuffer(int length) { var buffer = new byte[length]; From 9593e87e547c325e9fbacb992c30c63eb1b12cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Tue, 12 Sep 2023 13:34:43 +0200 Subject: [PATCH 33/96] Move Integration tests (#1173) * Renci.SshNet.IntegrationTests * Renci.SshNet.TestTools.OpenSSH * Move integration tests to main repo * Move old tests to new integration tests * Move old integration tests to new integration tests * Move more tests * Move authentication tests * Move SshClientTests * Fix some tests * Remove duplicated test * Poc of ProcessDisruptor * Rename * Some fixes * Remove performance tests * Small improvements --- src/Renci.SshNet.IntegrationTests/.gitignore | 1 + src/Renci.SshNet.IntegrationTests/App.config | 23 + .../AuthenticationMethodFactory.cs | 84 + .../AuthenticationTests.cs | 427 ++ .../Common/ArrayBuilder.cs | 32 + .../Common/AsyncSocketListener.cs | 393 ++ .../Common/RemoteSshdConfigExtensions.cs | 31 + .../Common/Socks5Handler.cs | 255 + .../ConnectivityTests.cs | 415 ++ .../Credential.cs | 14 + .../HostConfig.cs | 115 + .../HostKeyAlgorithmTests.cs | 105 + .../HostKeyFile.cs | 23 + .../IConnectionInfoFactory.cs | 10 + .../KeyExchangeAlgorithmTests.cs | 206 + .../LinuxAdminConnectionFactory.cs | 36 + .../LinuxVMConnectionFactory.cs | 62 + .../OldIntegrationTests/AesCipherTests.cs | 147 + .../ForwardedPortLocalTest.cs | 158 + .../OldIntegrationTests/HMacTest.cs | 67 + .../OldIntegrationTests/ScpClientTest.cs | 336 + .../SftpClientTest.ChangeDirectory.cs | 28 +- .../SftpClientTest.CreateDirectory.cs | 72 + .../SftpClientTest.DeleteDirectory.cs | 71 + .../SftpClientTest.Download.cs | 35 +- .../SftpClientTest.ListDirectory.cs | 263 + .../SftpClientTest.RenameFile.cs | 19 +- .../SftpClientTest.RenameFileAsync.cs | 18 +- .../SftpClientTest.SynchronizeDirectories.cs | 22 +- .../SftpClientTest.Upload.cs | 44 +- .../OldIntegrationTests/SftpClientTest.cs | 68 + .../OldIntegrationTests/SftpFileTest.cs | 120 + .../OldIntegrationTests/SshCommandTest.cs | 545 ++ .../TripleDesCipherTest.cs | 50 + .../PrivateKeyAuthenticationTests.cs | 84 + src/Renci.SshNet.IntegrationTests/Program.cs | 11 + .../RemoteSshd.cs | 246 + ...j => Renci.SshNet.IntegrationTests.csproj} | 25 +- .../ScpClientTests.cs | 4 +- src/Renci.SshNet.IntegrationTests/ScpTests.cs | 2379 +++++++ .../SftpClientTests.cs | 3 +- .../SftpTests.cs | 6234 +++++++++++++++++ .../SshClientTests.cs | 4 +- .../SshConnectionDisruptor.cs | 41 + .../SshConnectionRestorer.cs | 36 + src/Renci.SshNet.IntegrationTests/SshTests.cs | 972 +++ src/Renci.SshNet.IntegrationTests/TestBase.cs | 80 + .../TestInitializer.cs | 2 +- .../TestsFixtures/InfrastructureFixture.cs | 12 +- .../TestsFixtures/IntegrationTestBase.cs | 23 +- .../TestsFixtures/SshUser.cs | 2 +- src/Renci.SshNet.IntegrationTests/Users.cs | 8 + src/Renci.SshNet.IntegrationTests/Usings.cs | 6 +- .../resources/client/id_dsa | 12 + .../resources/client/id_dsa.ppk | 17 + .../resources/client/id_noaccess.rsa | 27 + .../resources/client/id_rsa | 27 + .../resources/client/id_rsa.pub | 1 + .../resources/client/id_rsa_with_pass | 28 + .../resources/client/key_ecdsa_256_openssh | 9 + .../client/key_ecdsa_256_openssh.pub | 1 + .../resources/client/key_ecdsa_384_openssh | 10 + .../client/key_ecdsa_384_openssh.pub | 1 + .../resources/client/key_ecdsa_521_openssh | 12 + .../client/key_ecdsa_521_openssh.pub | 1 + .../resources/client/key_ed25519_openssh | 7 + .../resources/issue #70.png | Bin 0 -> 312036 bytes src/Renci.SshNet.TestTools.OpenSSH/Cipher.cs | 54 + .../Formatters/BooleanFormatter.cs | 20 + .../Formatters/Int32Formatter.cs | 12 + .../Formatters/LogLevelFormatter.cs | 10 + .../Formatters/MatchFormatter.cs | 54 + .../Formatters/SubsystemFormatter.cs | 10 + .../HostKeyAlgorithm.cs | 53 + .../KeyExchangeAlgorithm.cs | 52 + .../LogLevel.cs | 15 + src/Renci.SshNet.TestTools.OpenSSH/Match.cs | 57 + .../MessageAuthenticationCodeAlgorithm.cs | 56 + .../PublicKeyAlgorithm.cs | 59 + .../Renci.SshNet.TestTools.OpenSSH.csproj | 21 + .../SshdConfig.cs | 501 ++ .../Subsystem.cs | 41 + ...ctConnectorTest_Connect_HostNameInvalid.cs | 2 +- ...pConnectorTest_Connect_ProxyHostInvalid.cs | 2 +- ...rTest_Connect_TimeoutReadingHttpContent.cs | 1 - ...orTest_Connect_TimeoutReadingStatusLine.cs | 1 - ...changeTest_ServerResponseValid_Comments.cs | 2 +- ...angeTest_ServerResponseValid_NoComments.cs | 2 +- ...rminatedByLineFeedWithoutCarriageReturn.cs | 1 - ...nnectorTest_Connect_ConnectionSucceeded.cs | 1 - ...onnect_TimeoutReadingDestinationAddress.cs | 1 - ...torTest_Connect_TimeoutReadingReplyCode.cs | 1 - ...Test_Connect_TimeoutReadingReplyVersion.cs | 1 - .../Classes/ForwardedPortLocalTest.cs | 222 - .../Classes/ForwardedPortRemoteTest.cs | 103 - .../KeyboardInteractiveConnectionInfoTest.cs | 40 +- .../PasswordAuthenticationMethodTest.cs | 29 +- .../Classes/PasswordConnectionInfoTest.cs | 134 +- .../Classes/PrivateKeyConnectionInfoTest.cs | 52 +- .../Classes/ScpClientTest.cs | 328 - .../Cryptography/Ciphers/AesCipherTest.cs | 122 +- .../Cryptography/Ciphers/Arc4CipherTest.cs | 38 +- .../Ciphers/BlowfishCipherTest.cs | 19 +- .../Cryptography/Ciphers/CastCipherTest.cs | 20 +- .../Ciphers/TripleDesCipherTest.cs | 18 - .../Classes/Security/Cryptography/HMacTest.cs | 134 - .../Classes/Security/KeyHostAlgorithmTest.cs | 123 - .../Classes/Sftp/SftpFileTest.cs | 122 +- .../Classes/SftpClientTest.Connect.cs | 4 +- .../Classes/SftpClientTest.CreateDirectory.cs | 106 - .../Classes/SftpClientTest.DeleteDirectory.cs | 71 - .../Classes/SftpClientTest.ListDirectory.cs | 269 +- .../Classes/SftpClientTest.cs | 66 - .../Classes/SshClientTest.cs | 246 +- .../Classes/SshCommandTest.cs | 574 -- src/Renci.SshNet.sln | 24 +- src/Renci.SshNet/Properties/AssemblyInfo.cs | 1 + 117 files changed, 15542 insertions(+), 2973 deletions(-) create mode 100644 src/Renci.SshNet.IntegrationTests/.gitignore create mode 100644 src/Renci.SshNet.IntegrationTests/App.config create mode 100644 src/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs create mode 100644 src/Renci.SshNet.IntegrationTests/AuthenticationTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/Common/ArrayBuilder.cs create mode 100644 src/Renci.SshNet.IntegrationTests/Common/AsyncSocketListener.cs create mode 100644 src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs create mode 100644 src/Renci.SshNet.IntegrationTests/Common/Socks5Handler.cs create mode 100644 src/Renci.SshNet.IntegrationTests/ConnectivityTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/Credential.cs create mode 100644 src/Renci.SshNet.IntegrationTests/HostConfig.cs create mode 100644 src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/HostKeyFile.cs create mode 100644 src/Renci.SshNet.IntegrationTests/IConnectionInfoFactory.cs create mode 100644 src/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/LinuxAdminConnectionFactory.cs create mode 100644 src/Renci.SshNet.IntegrationTests/LinuxVMConnectionFactory.cs create mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/AesCipherTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs create mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/HMacTest.cs create mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/ScpClientTest.cs rename src/{Renci.SshNet.Tests/Classes => Renci.SshNet.IntegrationTests/OldIntegrationTests}/SftpClientTest.ChangeDirectory.cs (66%) create mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.CreateDirectory.cs create mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.DeleteDirectory.cs rename src/{Renci.SshNet.Tests/Classes => Renci.SshNet.IntegrationTests/OldIntegrationTests}/SftpClientTest.Download.cs (70%) create mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ListDirectory.cs rename src/{Renci.SshNet.Tests/Classes => Renci.SshNet.IntegrationTests/OldIntegrationTests}/SftpClientTest.RenameFile.cs (69%) rename src/{Renci.SshNet.Tests/Classes => Renci.SshNet.IntegrationTests/OldIntegrationTests}/SftpClientTest.RenameFileAsync.cs (72%) rename src/{Renci.SshNet.Tests/Classes => Renci.SshNet.IntegrationTests/OldIntegrationTests}/SftpClientTest.SynchronizeDirectories.cs (78%) rename src/{Renci.SshNet.Tests/Classes => Renci.SshNet.IntegrationTests/OldIntegrationTests}/SftpClientTest.Upload.cs (89%) create mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.cs create mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs create mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs create mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/TripleDesCipherTest.cs create mode 100644 src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/Program.cs create mode 100644 src/Renci.SshNet.IntegrationTests/RemoteSshd.cs rename src/Renci.SshNet.IntegrationTests/{IntegrationTests.csproj => Renci.SshNet.IntegrationTests.csproj} (65%) create mode 100644 src/Renci.SshNet.IntegrationTests/ScpTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/SftpTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/SshConnectionDisruptor.cs create mode 100644 src/Renci.SshNet.IntegrationTests/SshConnectionRestorer.cs create mode 100644 src/Renci.SshNet.IntegrationTests/SshTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/TestBase.cs create mode 100644 src/Renci.SshNet.IntegrationTests/Users.cs create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/id_dsa create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/id_rsa create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub create mode 100644 src/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh create mode 100644 src/Renci.SshNet.IntegrationTests/resources/issue #70.png create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/Cipher.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/LogLevel.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/Match.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs create mode 100644 src/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/HMacTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/KeyHostAlgorithmTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/SftpClientTest.CreateDirectory.cs diff --git a/src/Renci.SshNet.IntegrationTests/.gitignore b/src/Renci.SshNet.IntegrationTests/.gitignore new file mode 100644 index 000000000..0819dad73 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/.gitignore @@ -0,0 +1 @@ +TestResults/ \ No newline at end of file diff --git a/src/Renci.SshNet.IntegrationTests/App.config b/src/Renci.SshNet.IntegrationTests/App.config new file mode 100644 index 000000000..c9794e84d --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/App.config @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs b/src/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs new file mode 100644 index 000000000..638b285d8 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs @@ -0,0 +1,84 @@ +锘縩amespace Renci.SshNet.IntegrationTests +{ + public class AuthenticationMethodFactory + { + public PasswordAuthenticationMethod CreatePowerUserPasswordAuthenticationMethod() + { + var user = Users.Admin; + return new PasswordAuthenticationMethod(user.UserName, user.Password); + } + + public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyAuthenticationMethod() + { + var privateKeyFile = GetPrivateKey("Renci.SshNet.IntegrationTests.resources.client.id_rsa"); + return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile); + } + + public PrivateKeyAuthenticationMethod CreateRegularUserMultiplePrivateKeyAuthenticationMethod() + { + var privateKeyFile1 = GetPrivateKey("Renci.SshNet.IntegrationTests.resources.client.id_rsa"); + var privateKeyFile2 = GetPrivateKey("Renci.SshNet.IntegrationTests.resources.client.id_rsa"); + return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile1, privateKeyFile2); + } + + public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyWithPassPhraseAuthenticationMethod() + { + var privateKeyFile = GetPrivateKey("Renci.SshNet.IntegrationTests.resources.client.id_rsa_with_pass", "tester"); + return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile); + } + + public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyWithEmptyPassPhraseAuthenticationMethod() + { + var privateKeyFile = GetPrivateKey("Renci.SshNet.IntegrationTests.resources.client.id_rsa_with_pass", null); + return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile); + } + + public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey() + { + var privateKeyFile = GetPrivateKey("Renci.SshNet.IntegrationTests.resources.client.id_noaccess.rsa"); + return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile); + } + + public PasswordAuthenticationMethod CreateRegulatUserPasswordAuthenticationMethod() + { + return new PasswordAuthenticationMethod(Users.Regular.UserName, Users.Regular.Password); + } + + public PasswordAuthenticationMethod CreateRegularUserPasswordAuthenticationMethodWithBadPassword() + { + return new PasswordAuthenticationMethod(Users.Regular.UserName, "xxx"); + } + + public KeyboardInteractiveAuthenticationMethod CreateRegularUserKeyboardInteractiveAuthenticationMethod() + { + var keyboardInteractive = new KeyboardInteractiveAuthenticationMethod(Users.Regular.UserName); + keyboardInteractive.AuthenticationPrompt += (sender, args) => + { + foreach (var authenticationPrompt in args.Prompts) + { + authenticationPrompt.Response = Users.Regular.Password; + } + }; + return keyboardInteractive; + } + + private PrivateKeyFile GetPrivateKey(string resourceName, string passPhrase = null) + { + using (var stream = GetResourceStream(resourceName)) + { + return new PrivateKeyFile(stream, passPhrase); + } + } + + private Stream GetResourceStream(string resourceName) + { + var type = GetType(); + var resourceStream = type.Assembly.GetManifestResourceStream(resourceName); + if (resourceStream == null) + { + throw new ArgumentException($"Resource '{resourceName}' not found in assembly '{type.Assembly.FullName}'.", nameof(resourceName)); + } + return resourceStream; + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/AuthenticationTests.cs b/src/Renci.SshNet.IntegrationTests/AuthenticationTests.cs new file mode 100644 index 000000000..c3968e949 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/AuthenticationTests.cs @@ -0,0 +1,427 @@ +锘縰sing Renci.SshNet.Common; +using Renci.SshNet.IntegrationTests.Common; + +namespace Renci.SshNet.IntegrationTests +{ + [TestClass] + public class AuthenticationTests : IntegrationTestBase + { + private AuthenticationMethodFactory _authenticationMethodFactory; + private IConnectionInfoFactory _connectionInfoFactory; + private IConnectionInfoFactory _adminConnectionInfoFactory; + private RemoteSshdConfig _remoteSshdConfig; + + [TestInitialize] + public void SetUp() + { + _authenticationMethodFactory = new AuthenticationMethodFactory(); + _connectionInfoFactory = new LinuxVMConnectionFactory(SshServerHostName, SshServerPort, _authenticationMethodFactory); + _adminConnectionInfoFactory = new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort); + _remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig(); + } + + [TestCleanup] + public void TearDown() + { + _remoteSshdConfig?.Reset(); + + using (var client = new SshClient(_adminConnectionInfoFactory.Create())) + { + client.Connect(); + + // Reset the password back to the "regular" password. + using (var cmd = client.RunCommand($"echo \"{Users.Regular.Password}\n{Users.Regular.Password}\" | sudo passwd " + Users.Regular.UserName)) + { + Assert.AreEqual(0, cmd.ExitStatus, cmd.Error); + } + + // Remove password expiration + using (var cmd = client.RunCommand($"sudo chage --expiredate -1 " + Users.Regular.UserName)) + { + Assert.AreEqual(0, cmd.ExitStatus, cmd.Error); + } + } + } + + [TestMethod] + public void Multifactor_PublicKey() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "publickey") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + } + + [TestMethod] + [TestCategory("Authentication")] + public void Multifactor_PublicKey_Connect_Then_Reconnect() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "publickey") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + client.Disconnect(); + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void Multifactor_PublicKeyWithPassPhrase() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "publickey") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyWithPassPhraseAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + } + + [TestMethod] + [ExpectedException(typeof(SshPassPhraseNullOrEmptyException))] + public void Multifactor_PublicKeyWithEmptyPassPhrase() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "publickey") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyWithEmptyPassPhraseAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + } + + [TestMethod] + public void Multifactor_PublicKey_MultiplePrivateKey() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "publickey") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserMultiplePrivateKeyAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + } + + [TestMethod] + public void Multifactor_PublicKey_MultipleAuthenticationMethod() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "publickey") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod(), + _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + } + + [TestMethod] + public void Multifactor_KeyboardInteractiveAndPublicKey() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "keyboard-interactive,publickey") + .WithChallengeResponseAuthentication(true) + .WithKeyboardInteractiveAuthentication(true) + .WithUsePAM(true) + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethodWithBadPassword(), + _authenticationMethodFactory.CreateRegularUserKeyboardInteractiveAuthenticationMethod(), + _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + } + + [TestMethod] + public void Multifactor_Password_ExceedsPartialSuccessLimit() + { + // configure server to require more successfull authentications from a given method than our partial + // success limit (5) allows + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password,password,password,password,password,password") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + try + { + client.Connect(); + Assert.Fail(); + } + catch (SshAuthenticationException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Reached authentication attempt limit for method (password).", ex.Message); + } + } + } + + [TestMethod] + public void Multifactor_Password_MatchPartialSuccessLimit() + { + // configure server to require a number of successfull authentications from a given method that exactly + // matches our partial success limit (5) + + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password,password,password,password,password") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + } + + [TestMethod] + public void Multifactor_Password_Or_PublicKeyAndKeyboardInteractive() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password publickey,keyboard-interactive") + .WithChallengeResponseAuthentication(true) + .WithKeyboardInteractiveAuthentication(true) + .WithUsePAM(true) + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod(), + _authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + } + + [TestMethod] + public void Multifactor_Password_Or_PublicKeyAndPassword_BadPassword() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password publickey,password") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethodWithBadPassword(), + _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + try + { + client.Connect(); + Assert.Fail(); + } + catch (SshAuthenticationException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Permission denied (password).", ex.Message); + } + } + } + + [TestMethod] + public void Multifactor_PasswordAndPublicKey_Or_PasswordAndPassword() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password,publickey password,password") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod(), + _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + + connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethodWithBadPassword(), + _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + try + { + client.Connect(); + Assert.Fail(); + } + catch (SshAuthenticationException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Permission denied (password).", ex.Message); + } + } + + } + + [TestMethod] + public void Multifactor_PasswordAndPassword_Or_PublicKey() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password,password publickey") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod(), + _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + + connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + + } + + [TestMethod] + public void Multifactor_Password_Or_Password() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "password password") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + + connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod(), + _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey()); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + } + } + + [TestMethod] + public void KeyboardInteractive_PasswordExpired() + { + var temporaryPassword = new Random().Next().ToString(); + + using (var client = new SshClient(_adminConnectionInfoFactory.Create())) + { + client.Connect(); + + // Temporarity modify password so that when we expire this password, we change reset the password back to + // the "regular" password. + using (var cmd = client.RunCommand($"echo \"{temporaryPassword}\n{temporaryPassword}\" | sudo passwd " + Users.Regular.UserName)) + { + Assert.AreEqual(0, cmd.ExitStatus, cmd.Error); + } + + // Force the password to expire immediately + using (var cmd = client.RunCommand($"sudo chage -d 0 " + Users.Regular.UserName)) + { + Assert.AreEqual(0, cmd.ExitStatus, cmd.Error); + } + } + + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "keyboard-interactive") + .WithChallengeResponseAuthentication(true) + .WithKeyboardInteractiveAuthentication(true) + .WithUsePAM(true) + .Update() + .Restart(); + + var keyboardInteractive = new KeyboardInteractiveAuthenticationMethod(Users.Regular.UserName); + int authenticationPromptCount = 0; + keyboardInteractive.AuthenticationPrompt += (sender, args) => + { + Console.WriteLine(args.Instruction); + foreach (var authenticationPrompt in args.Prompts) + { + Console.WriteLine(authenticationPrompt.Request); + switch (authenticationPromptCount) + { + case 0: + // Regular password prompt + authenticationPrompt.Response = temporaryPassword; + break; + case 1: + // Password expired, provide current password + authenticationPrompt.Response = temporaryPassword; + break; + case 2: + // Password expired, provide new password + authenticationPrompt.Response = Users.Regular.Password; + break; + case 3: + // Password expired, retype new password + authenticationPrompt.Response = Users.Regular.Password; + break; + } + + authenticationPromptCount++; + } + }; + + var connectionInfo = _connectionInfoFactory.Create(keyboardInteractive); + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + Assert.AreEqual(4, authenticationPromptCount); + } + } + + [TestMethod] + public void KeyboardInteractiveConnectionInfo() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "keyboard-interactive") + .WithChallengeResponseAuthentication(true) + .WithKeyboardInteractiveAuthentication(true) + .WithUsePAM(true) + .Update() + .Restart(); + + var host = SshServerHostName; + var port = SshServerPort; + var username = User.UserName; + var password = User.Password; + + #region Example KeyboardInteractiveConnectionInfo AuthenticationPrompt + + var connectionInfo = new KeyboardInteractiveConnectionInfo(host, port, username); + connectionInfo.AuthenticationPrompt += delegate (object sender, AuthenticationPromptEventArgs e) + { + Console.WriteLine(e.Instruction); + + foreach (var prompt in e.Prompts) + { + Console.WriteLine(prompt.Request); + prompt.Response = password; + } + }; + + using (var client = new SftpClient(connectionInfo)) + { + client.Connect(); + + // Do something here + client.Disconnect(); + } + + #endregion + + Assert.AreEqual(connectionInfo.Host, SshServerHostName); + Assert.AreEqual(connectionInfo.Username, User.UserName); + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/Common/ArrayBuilder.cs b/src/Renci.SshNet.IntegrationTests/Common/ArrayBuilder.cs new file mode 100644 index 000000000..1720c19c9 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/Common/ArrayBuilder.cs @@ -0,0 +1,32 @@ +锘縩amespace Renci.SshNet.IntegrationTests.Common +{ + public class ArrayBuilder + { + private readonly List _buffer; + + public ArrayBuilder() + { + _buffer = new List(); + } + + public ArrayBuilder Add(T[] array) + { + return Add(array, 0, array.Length); + } + + public ArrayBuilder Add(T[] array, int index, int length) + { + for (var i = 0; i < length; i++) + { + _buffer.Add(array[index + i]); + } + + return this; + } + + public T[] Build() + { + return _buffer.ToArray(); + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/Common/AsyncSocketListener.cs b/src/Renci.SshNet.IntegrationTests/Common/AsyncSocketListener.cs new file mode 100644 index 000000000..753385582 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/Common/AsyncSocketListener.cs @@ -0,0 +1,393 @@ +锘縰sing System.Net; +using System.Net.Sockets; + +namespace Renci.SshNet.IntegrationTests.Common +{ + public class AsyncSocketListener : IDisposable + { + private readonly IPEndPoint _endPoint; + private readonly ManualResetEvent _acceptCallbackDone; + private readonly List _connectedClients; + private readonly object _syncLock; + private Socket _listener; + private Thread _receiveThread; + private bool _started; + private string _stackTrace; + + public delegate void BytesReceivedHandler(byte[] bytesReceived, Socket socket); + public delegate void ConnectedHandler(Socket socket); + + public event BytesReceivedHandler BytesReceived; + public event ConnectedHandler Connected; + public event ConnectedHandler Disconnected; + + public AsyncSocketListener(IPEndPoint endPoint) + { + _endPoint = endPoint; + _acceptCallbackDone = new ManualResetEvent(false); + _connectedClients = new List(); + _syncLock = new object(); + ShutdownRemoteCommunicationSocket = true; + } + + /// + /// Gets a value indicating whether the is invoked on the + /// that is used to handle the communication with the remote host, when the remote host has closed the connection. + /// + /// + /// to invoke on the that is used + /// to handle the communication with the remote host, when the remote host has closed the connection; otherwise, + /// . The default is . + /// + public bool ShutdownRemoteCommunicationSocket { get; set; } + + public void Start() + { + _listener = new Socket(_endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + _listener.Bind(_endPoint); + _listener.Listen(1); + + _started = true; + + _receiveThread = new Thread(StartListener); + _receiveThread.Start(_listener); + + _stackTrace = Environment.StackTrace; + } + + public void Stop() + { + _started = false; + + lock (_syncLock) + { + foreach (var connectedClient in _connectedClients) + { + try + { + connectedClient.Shutdown(SocketShutdown.Send); + } + catch (Exception ex) + { + Console.Error.WriteLine("[{0}] Failure shutting down socket: {1}", + typeof(AsyncSocketListener).FullName, + ex); + } + + DrainSocket(connectedClient); + connectedClient.Dispose(); + } + + _connectedClients.Clear(); + } + + _listener?.Dispose(); + + if (_receiveThread != null) + { + _receiveThread.Join(); + _receiveThread = null; + } + } + + public void Dispose() + { + Stop(); + GC.SuppressFinalize(this); + } + + private void StartListener(object state) + { + try + { + var listener = (Socket) state; + while (_started) + { + _ = _acceptCallbackDone.Reset(); + _ = listener.BeginAccept(AcceptCallback, listener); + _ = _acceptCallbackDone.WaitOne(); + } + } + catch (Exception ex) + { + // On .NET framework when Thread throws an exception then unit tests + // were executed without any problem. + // On new .NET exceptions from Thread breaks unit tests session. + Console.Error.WriteLine("[{0}] Failure in StartListener: {1}", + typeof(AsyncSocketListener).FullName, + ex); + } + } + + private void AcceptCallback(IAsyncResult ar) + { + // Signal the main thread to continue + _ = _acceptCallbackDone.Set(); + + // Get the socket that listens for inbound connections + var listener = (Socket) ar.AsyncState; + + // Get the socket that handles the client request + Socket handler; + + try + { + handler = listener.EndAccept(ar); + } + catch (SocketException ex) + { + // The listener is stopped through a Dispose() call, which in turn causes + // Socket.EndAccept(...) to throw a SocketException or + // ObjectDisposedException + // + // Since we consider such an exception normal when the listener is being + // stopped, we only write a message to stderr if the listener is considered + // to be up and running + if (_started) + { + Console.Error.WriteLine("[{0}] Failure accepting new connection: {1}", + typeof(AsyncSocketListener).FullName, + ex); + } + return; + } + catch (ObjectDisposedException ex) + { + // The listener is stopped through a Dispose() call, which in turn causes + // Socket.EndAccept(IAsyncResult) to throw a SocketException or + // ObjectDisposedException + // + // Since we consider such an exception normal when the listener is being + // stopped, we only write a message to stderr if the listener is considered + // to be up and running + if (_started) + { + Console.Error.WriteLine("[{0}] Failure accepting new connection: {1}", + typeof(AsyncSocketListener).FullName, + ex); + } + return; + } + + // Signal new connection + SignalConnected(handler); + + lock (_syncLock) + { + // Register client socket + _connectedClients.Add(handler); + } + + var state = new SocketStateObject(handler); + + try + { + _ = handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state); + } + catch (SocketException ex) + { + // The listener is stopped through a Dispose() call, which in turn causes + // Socket.BeginReceive(...) to throw a SocketException or + // ObjectDisposedException + // + // Since we consider such an exception normal when the listener is being + // stopped, we only write a message to stderr if the listener is considered + // to be up and running + if (_started) + { + Console.Error.WriteLine("[{0}] Failure receiving new data: {1}", + typeof(AsyncSocketListener).FullName, + ex); + } + } + catch (ObjectDisposedException ex) + { + // The listener is stopped through a Dispose() call, which in turn causes + // Socket.BeginReceive(...) to throw a SocketException or + // ObjectDisposedException + // + // Since we consider such an exception normal when the listener is being + // stopped, we only write a message to stderr if the listener is considered + // to be up and running + if (_started) + { + Console.Error.WriteLine("[{0}] Failure receiving new data: {1}", + typeof(AsyncSocketListener).FullName, + ex); + } + } + } + + private void ReadCallback(IAsyncResult ar) + { + // Retrieve the state object and the handler socket + // from the asynchronous state object + var state = (SocketStateObject) ar.AsyncState; + var handler = state.Socket; + + int bytesRead; + try + { + // Read data from the client socket. + bytesRead = handler.EndReceive(ar, out var errorCode); + if (errorCode != SocketError.Success) + { + bytesRead = 0; + } + } + catch (SocketException ex) + { + // The listener is stopped through a Dispose() call, which in turn causes + // Socket.EndReceive(...) to throw a SocketException or + // ObjectDisposedException + // + // Since we consider such an exception normal when the listener is being + // stopped, we only write a message to stderr if the listener is considered + // to be up and running + if (_started) + { + Console.Error.WriteLine("[{0}] Failure receiving new data: {1}", + typeof(AsyncSocketListener).FullName, + ex); + } + return; + } + catch (ObjectDisposedException ex) + { + // The listener is stopped through a Dispose() call, which in turn causes + // Socket.EndReceive(...) to throw a SocketException or + // ObjectDisposedException + // + // Since we consider such an exception normal when the listener is being + // stopped, we only write a message to stderr if the listener is considered + // to be up and running + if (_started) + { + Console.Error.WriteLine("[{0}] Failure receiving new data: {1}", + typeof(AsyncSocketListener).FullName, + ex); + } + return; + } + + void ConnectionDisconnected() + { + SignalDisconnected(handler); + + if (ShutdownRemoteCommunicationSocket) + { + lock (_syncLock) + { + if (!_started) + { + return; + } + + try + { + handler.Shutdown(SocketShutdown.Send); + handler.Close(); + } + catch (SocketException ex) when (ex.SocketErrorCode == SocketError.ConnectionReset) + { + // On .NET 7 we got Socker Exception with ConnectionReset from Shutdown method + // when the socket is disposed + } + catch (SocketException ex) + { + throw new Exception("Exception in ReadCallback: " + ex.SocketErrorCode + " " + _stackTrace, ex); + } + catch (Exception ex) + { + throw new Exception("Exception in ReadCallback: " + _stackTrace, ex); + } + + _ = _connectedClients.Remove(handler); + } + } + } + + if (bytesRead > 0) + { + var bytesReceived = new byte[bytesRead]; + Array.Copy(state.Buffer, bytesReceived, bytesRead); + SignalBytesReceived(bytesReceived, handler); + + try + { + _ = handler.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, ReadCallback, state); + } + catch (ObjectDisposedException) + { + // TODO On .NET 7, sometimes we get ObjectDisposedException when _started but only on appveyor, locally it works + ConnectionDisconnected(); + } + catch (SocketException ex) + { + if (!_started) + { + throw new Exception("BeginReceive while stopping!", ex); + } + + throw new Exception("BeginReceive while started!: " + ex.SocketErrorCode + " " + _stackTrace, ex); + } + + } + else + { + ConnectionDisconnected(); + } + } + + private void SignalBytesReceived(byte[] bytesReceived, Socket client) + { + BytesReceived?.Invoke(bytesReceived, client); + } + + private void SignalConnected(Socket client) + { + Connected?.Invoke(client); + } + + private void SignalDisconnected(Socket client) + { + Disconnected?.Invoke(client); + } + + private static void DrainSocket(Socket socket) + { + var buffer = new byte[128]; + + try + { + while (true && socket.Connected) + { + var bytesRead = socket.Receive(buffer); + if (bytesRead == 0) + { + break; + } + } + } + catch (SocketException ex) + { + Console.Error.WriteLine("[{0}] Failure draining socket ({1}): {2}", + typeof(AsyncSocketListener).FullName, + ex.SocketErrorCode.ToString("G"), + ex); + } + } + + private class SocketStateObject + { + public Socket Socket { get; private set; } + + public readonly byte[] Buffer = new byte[1024]; + + public SocketStateObject(Socket handler) + { + Socket = handler; + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs b/src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs new file mode 100644 index 000000000..64676a0d2 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs @@ -0,0 +1,31 @@ +锘縰sing Renci.SshNet.TestTools.OpenSSH; + +namespace Renci.SshNet.IntegrationTests.Common +{ + internal static class RemoteSshdConfigExtensions + { + private const string DefaultAuthenticationMethods = "password publickey"; + + public static void Reset(this RemoteSshdConfig remoteSshdConfig) + { + remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, DefaultAuthenticationMethods) + .WithChallengeResponseAuthentication(false) + .WithKeyboardInteractiveAuthentication(false) + .PrintMotd() + .WithLogLevel(LogLevel.Debug3) + .ClearHostKeyFiles() + .AddHostKeyFile(HostKeyFile.Rsa.FilePath) + .ClearSubsystems() + .AddSubsystem(new Subsystem("sftp", "/usr/lib/ssh/sftp-server")) + .ClearCiphers() + .ClearKeyExchangeAlgorithms() + .ClearHostKeyAlgorithms() + .AddHostKeyAlgorithm(HostKeyAlgorithm.SshRsa) + .ClearPublicKeyAcceptedAlgorithms() + .AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.SshRsa) + .WithUsePAM(true) + .Update() + .Restart(); + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/Common/Socks5Handler.cs b/src/Renci.SshNet.IntegrationTests/Common/Socks5Handler.cs new file mode 100644 index 000000000..e50858c33 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/Common/Socks5Handler.cs @@ -0,0 +1,255 @@ +锘縰sing System.Net; +using System.Net.Sockets; + +using Renci.SshNet.Abstractions; +using Renci.SshNet.Common; +using Renci.SshNet.Messages.Transport; + +namespace Renci.SshNet.IntegrationTests.Common +{ + class Socks5Handler + { + private readonly IPEndPoint _proxyEndPoint; + private readonly string _userName; + private readonly string _password; + + public Socks5Handler(IPEndPoint proxyEndPoint, string userName, string password) + { + _proxyEndPoint = proxyEndPoint; + _userName = userName; + _password = password; + } + + public Socket Connect(IPEndPoint endPoint) + { + if (endPoint == null) + { + throw new ArgumentNullException("endPoint"); + } + + var addressBytes = GetAddressBytes(endPoint); + return Connect(addressBytes, endPoint.Port); + } + + public Socket Connect(string host, int port) + { + if (host == null) + { + throw new ArgumentNullException(nameof(host)); + } + + if (host.Length > byte.MaxValue) + { + throw new ArgumentException($@"Cannot be more than {byte.MaxValue} characters.", nameof(host)); + } + + var addressBytes = new byte[host.Length + 2]; + addressBytes[0] = 0x03; + addressBytes[1] = (byte) host.Length; + Encoding.ASCII.GetBytes(host, 0, host.Length, addressBytes, 2); + return Connect(addressBytes, port); + } + + private Socket Connect(byte[] addressBytes, int port) + { + var socket = SocketAbstraction.Connect(_proxyEndPoint, TimeSpan.FromSeconds(5)); + + // Send socks version number + SocketWriteByte(socket, 0x05); + + // Send number of supported authentication methods + SocketWriteByte(socket, 0x02); + + // Send supported authentication methods + SocketWriteByte(socket, 0x00); // No authentication + SocketWriteByte(socket, 0x02); // Username/Password + + var socksVersion = SocketReadByte(socket); + if (socksVersion != 0x05) + { + throw new ProxyException(string.Format("SOCKS Version '{0}' is not supported.", socksVersion)); + } + + var authenticationMethod = SocketReadByte(socket); + switch (authenticationMethod) + { + case 0x00: + break; + case 0x02: + + // Send version + SocketWriteByte(socket, 0x01); + + var username = Encoding.ASCII.GetBytes(_userName); + if (username.Length > byte.MaxValue) + { + throw new ProxyException("Proxy username is too long."); + } + + // Send username length + SocketWriteByte(socket, (byte) username.Length); + + // Send username + SocketAbstraction.Send(socket, username); + + var password = Encoding.ASCII.GetBytes(_password); + + if (password.Length > byte.MaxValue) + { + throw new ProxyException("Proxy password is too long."); + } + + // Send username length + SocketWriteByte(socket, (byte) password.Length); + + // Send username + SocketAbstraction.Send(socket, password); + + var serverVersion = SocketReadByte(socket); + + if (serverVersion != 1) + { + throw new ProxyException("SOCKS5: Server authentication version is not valid."); + } + + var statusCode = SocketReadByte(socket); + if (statusCode != 0) + { + throw new ProxyException("SOCKS5: Username/Password authentication failed."); + } + + break; + case 0xFF: + throw new ProxyException("SOCKS5: No acceptable authentication methods were offered."); + default: + throw new ProxyException("SOCKS5: No acceptable authentication methods were offered."); + } + + // Send socks version number + SocketWriteByte(socket, 0x05); + + // Send command code + SocketWriteByte(socket, 0x01); // establish a TCP/IP stream connection + + // Send reserved, must be 0x00 + SocketWriteByte(socket, 0x00); + + // Send address type and address + SocketAbstraction.Send(socket, addressBytes); + + // Send port + SocketWriteByte(socket, (byte)(port / 0xFF)); + SocketWriteByte(socket, (byte)(port % 0xFF)); + + // Read Server SOCKS5 version + if (SocketReadByte(socket) != 5) + { + throw new ProxyException("SOCKS5: Version 5 is expected."); + } + + // Read response code + var status = SocketReadByte(socket); + + switch (status) + { + case 0x00: + break; + case 0x01: + throw new ProxyException("SOCKS5: General failure."); + case 0x02: + throw new ProxyException("SOCKS5: Connection not allowed by ruleset."); + case 0x03: + throw new ProxyException("SOCKS5: Network unreachable."); + case 0x04: + throw new ProxyException("SOCKS5: Host unreachable."); + case 0x05: + throw new ProxyException("SOCKS5: Connection refused by destination host."); + case 0x06: + throw new ProxyException("SOCKS5: TTL expired."); + case 0x07: + throw new ProxyException("SOCKS5: Command not supported or protocol error."); + case 0x08: + throw new ProxyException("SOCKS5: Address type not supported."); + default: + throw new ProxyException("SOCKS4: Not valid response."); + } + + // Read 0 + if (SocketReadByte(socket) != 0) + { + throw new ProxyException("SOCKS5: 0 byte is expected."); + } + + var addressType = SocketReadByte(socket); + var responseIp = new byte[16]; + + switch (addressType) + { + case 0x01: + SocketRead(socket, responseIp, 0, 4); + break; + case 0x04: + SocketRead(socket, responseIp, 0, 16); + break; + default: + throw new ProxyException(string.Format("Address type '{0}' is not supported.", addressType)); + } + + var portBytes = new byte[2]; + + // Read 2 bytes to be ignored + SocketRead(socket, portBytes, 0, 2); + + return socket; + } + + private static byte[] GetAddressBytes(IPEndPoint endPoint) + { + if (endPoint.AddressFamily == AddressFamily.InterNetwork) + { + var addressBytes = new byte[4 + 1]; + addressBytes[0] = 0x01; + var address = endPoint.Address.GetAddressBytes(); + Buffer.BlockCopy(address, 0, addressBytes, 1, address.Length); + return addressBytes; + } + + if (endPoint.AddressFamily == AddressFamily.InterNetworkV6) + { + var addressBytes = new byte[16 + 1]; + addressBytes[0] = 0x04; + var address = endPoint.Address.GetAddressBytes(); + Buffer.BlockCopy(address, 0, addressBytes, 1, address.Length); + return addressBytes; + } + + throw new ProxyException(string.Format("SOCKS5: IP address '{0}' is not supported.", endPoint.Address)); + } + + private static void SocketWriteByte(Socket socket, byte data) + { + SocketAbstraction.Send(socket, new[] { data }); + } + + private static byte SocketReadByte(Socket socket) + { + var buffer = new byte[1]; + SocketRead(socket, buffer, 0, 1); + return buffer[0]; + } + + private static int SocketRead(Socket socket, byte[] buffer, int offset, int length) + { + var bytesRead = SocketAbstraction.Read(socket, buffer, offset, length, TimeSpan.FromMilliseconds(-1)); + if (bytesRead == 0) + { + // when we're in the disconnecting state (either triggered by client or server), then the + // SshConnectionException will interrupt the message listener loop (if not already interrupted) + // and the exception itself will be ignored (in RaiseError) + throw new SshConnectionException("An established connection was aborted by the server.", + DisconnectReason.ConnectionLost); + } + return bytesRead; + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/ConnectivityTests.cs b/src/Renci.SshNet.IntegrationTests/ConnectivityTests.cs new file mode 100644 index 000000000..5401e6b6b --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/ConnectivityTests.cs @@ -0,0 +1,415 @@ +锘縰sing Renci.SshNet.Common; +using Renci.SshNet.IntegrationTests.Common; +using Renci.SshNet.Messages.Transport; + +namespace Renci.SshNet.IntegrationTests +{ + [TestClass] + public class ConnectivityTests : IntegrationTestBase + { + private AuthenticationMethodFactory _authenticationMethodFactory; + private IConnectionInfoFactory _connectionInfoFactory; + private IConnectionInfoFactory _adminConnectionInfoFactory; + private RemoteSshdConfig _remoteSshdConfig; + private SshConnectionDisruptor _sshConnectionDisruptor; + + [TestInitialize] + public void SetUp() + { + _authenticationMethodFactory = new AuthenticationMethodFactory(); + _connectionInfoFactory = new LinuxVMConnectionFactory(SshServerHostName, SshServerPort, _authenticationMethodFactory); + _adminConnectionInfoFactory = new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort); + _remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig(); + _sshConnectionDisruptor = new SshConnectionDisruptor(_adminConnectionInfoFactory); + } + + [TestCleanup] + public void TearDown() + { + _remoteSshdConfig?.Reset(); + } + + [TestMethod] + public void Common_CreateMoreChannelsThanMaxSessions() + { + var connectionInfo = _connectionInfoFactory.Create(); + connectionInfo.MaxSessions = 2; + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + + // create one more channel than the maximum number of sessions + // as that would block indefinitely when creating the last channel + // if the channel would not be properly closed + for (var i = 0; i < connectionInfo.MaxSessions + 1; i++) + { + using (var stream = client.CreateShellStream("vt220", 20, 20, 20, 20, 0)) + { + stream.WriteLine("echo test"); + stream.ReadLine(); + } + } + } + } + + [TestMethod] + public void Common_DisposeAfterLossOfNetworkConnectivity() + { + var hostNetworkConnectionDisabled = false; + SshConnectionRestorer disruptor = null; + try + { + Exception errorOccurred = null; + int count = 0; + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.ErrorOccurred += (sender, args) => + { + Console.WriteLine("Exception " + count++); + Console.WriteLine(args.Exception); + errorOccurred = args.Exception; + }; + client.Connect(); + + disruptor = _sshConnectionDisruptor.BreakConnections(); + hostNetworkConnectionDisabled = true; + WaitForConnectionInterruption(client); + } + + Assert.IsNotNull(errorOccurred); + Assert.AreEqual(typeof(SshConnectionException), errorOccurred.GetType()); + + var connectionException = (SshConnectionException) errorOccurred; + Assert.AreEqual(DisconnectReason.ConnectionLost, connectionException.DisconnectReason); + Assert.IsNull(connectionException.InnerException); + Assert.AreEqual("An established connection was aborted by the server.", connectionException.Message); + } + finally + { + if (hostNetworkConnectionDisabled) + { + disruptor?.RestoreConnections(); + disruptor?.Dispose(); + } + } + } + + [TestMethod] + public void Common_DetectLossOfNetworkConnectivityThroughKeepAlive() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + Exception errorOccurred = null; + int count = 0; + client.ErrorOccurred += (sender, args) => + { + Console.WriteLine("Exception "+ count++); + Console.WriteLine(args.Exception); + errorOccurred = args.Exception; + }; + client.KeepAliveInterval = new TimeSpan(0, 0, 0, 0, 50); + client.Connect(); + + var disruptor = _sshConnectionDisruptor.BreakConnections(); + + try + { + WaitForConnectionInterruption(client); + + Assert.IsFalse(client.IsConnected); + + Assert.IsNotNull(errorOccurred); + Assert.AreEqual(typeof(SshConnectionException), errorOccurred.GetType()); + + var connectionException = (SshConnectionException) errorOccurred; + Assert.AreEqual(DisconnectReason.ConnectionLost, connectionException.DisconnectReason); + Assert.IsNull(connectionException.InnerException); + Assert.AreEqual("An established connection was aborted by the server.", connectionException.Message); + } + finally + { + disruptor?.RestoreConnections(); + disruptor?.Dispose(); + } + } + } + + private static void WaitForConnectionInterruption(SftpClient client) + { + for (var i = 0; i < 500; i++) + { + if (!client.IsConnected) + { + break; + } + + Thread.Sleep(100); + } + + // After interruption, you have to wait for the events to propagate. + Thread.Sleep(100); + } + + [TestMethod] + public void Common_DetectConnectionResetThroughSftpInvocation() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.KeepAliveInterval = TimeSpan.FromSeconds(1); + client.OperationTimeout = TimeSpan.FromSeconds(60); + ManualResetEvent errorOccurredSignaled = new ManualResetEvent(false); + Exception errorOccurred = null; + client.ErrorOccurred += (sender, args) => + { + errorOccurred = args.Exception; + errorOccurredSignaled.Set(); + }; + client.Connect(); + + var disruptor = _sshConnectionDisruptor.BreakConnections(); + + try + { + client.ListDirectory("/"); + Assert.Fail(); + } + catch (SshConnectionException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Client not connected.", ex.Message); + + Assert.IsNotNull(errorOccurred); + Assert.AreEqual(typeof(SshConnectionException), errorOccurred.GetType()); + + var connectionException = (SshConnectionException) errorOccurred; + Assert.AreEqual(DisconnectReason.ConnectionLost, connectionException.DisconnectReason); + Assert.IsNull(connectionException.InnerException); + Assert.AreEqual("An established connection was aborted by the server.", connectionException.Message); + } + finally + { + disruptor.RestoreConnections(); + disruptor.Dispose(); + } + } + } + + [TestMethod] + public void Common_LossOfNetworkConnectivityDisconnectAndConnect() + { + bool vmNetworkConnectionDisabled = false; + SshConnectionRestorer disruptor = null; + try + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + Exception errorOccurred = null; + client.ErrorOccurred += (sender, args) => errorOccurred = args.Exception; + + client.Connect(); + + disruptor = _sshConnectionDisruptor.BreakConnections(); + vmNetworkConnectionDisabled = true; + + WaitForConnectionInterruption(client); + // disconnect while network connectivity is lost + client.Disconnect(); + + Assert.IsFalse(client.IsConnected); + + disruptor.RestoreConnections(); + vmNetworkConnectionDisabled = false; + + // connect when network connectivity is restored + client.Connect(); + client.ChangeDirectory(client.WorkingDirectory); + client.Dispose(); + + Assert.IsNotNull(errorOccurred); + Assert.AreEqual(typeof(SshConnectionException), errorOccurred.GetType()); + + var connectionException = (SshConnectionException) errorOccurred; + Assert.AreEqual(DisconnectReason.ConnectionLost, connectionException.DisconnectReason); + Assert.IsNull(connectionException.InnerException); + Assert.AreEqual("An established connection was aborted by the server.", connectionException.Message); + } + } + finally + { + if (vmNetworkConnectionDisabled) + { + disruptor.RestoreConnections(); + } + disruptor?.Dispose(); + } + } + + [TestMethod] + public void Common_DetectLossOfNetworkConnectivityThroughSftpInvocation() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + ManualResetEvent errorOccurredSignaled = new ManualResetEvent(false); + Exception errorOccurred = null; + client.ErrorOccurred += (sender, args) => + { + errorOccurred = args.Exception; + errorOccurredSignaled.Set(); + }; + client.Connect(); + + var disruptor = _sshConnectionDisruptor.BreakConnections(); + Thread.Sleep(100); + try + { + client.ListDirectory("/"); + Assert.Fail(); + } + catch (SshConnectionException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Client not connected.", ex.Message); + + Assert.IsNotNull(errorOccurred); + Assert.AreEqual(typeof(SshConnectionException), errorOccurred.GetType()); + + var connectionException = (SshConnectionException) errorOccurred; + Assert.AreEqual(DisconnectReason.ConnectionLost, connectionException.DisconnectReason); + Assert.IsNull(connectionException.InnerException); + Assert.AreEqual("An established connection was aborted by the server.", connectionException.Message); + } + finally + { + disruptor.RestoreConnections(); + disruptor.Dispose(); + } + } + } + + [TestMethod] + public void Common_DetectSessionKilledOnServer() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + ManualResetEvent errorOccurredSignaled = new ManualResetEvent(false); + Exception errorOccurred = null; + client.ErrorOccurred += (sender, args) => + { + errorOccurred = args.Exception; + errorOccurredSignaled.Set(); + }; + client.Connect(); + + // Kill the server session + using (var adminClient = new SshClient(_adminConnectionInfoFactory.Create())) + { + adminClient.Connect(); + + var command = $"sudo ps --no-headers -u {client.ConnectionInfo.Username} -f | grep \"{client.ConnectionInfo.Username}@notty\" | awk '{{print $2}}' | xargs sudo kill -9"; + var sshCommand = adminClient.CreateCommand(command); + var result = sshCommand.Execute(); + Assert.AreEqual(0, sshCommand.ExitStatus, sshCommand.Error); + } + + Assert.IsTrue(errorOccurredSignaled.WaitOne(200)); + Assert.IsNotNull(errorOccurred); + Assert.AreEqual(typeof(SshConnectionException), errorOccurred.GetType()); + Assert.IsNull(errorOccurred.InnerException); + Assert.AreEqual("An established connection was aborted by the server.", errorOccurred.Message); + Assert.IsFalse(client.IsConnected); + } + } + + [TestMethod] + public void Common_HostKeyValidation_Failure() + { + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.HostKeyReceived += (sender, e) => { e.CanTrust = false; }; + + try + { + client.Connect(); + Assert.Fail(); + } + catch (SshConnectionException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Key exchange negotiation failed.", ex.Message); + } + } + } + + [TestMethod] + public void Common_HostKeyValidation_Success() + { + byte[] host_rsa_key_openssh_fingerprint = + { + 0x3d, 0x90, 0xd8, 0x0d, 0xd5, 0xe0, 0xb6, 0x13, + 0x42, 0x7c, 0x78, 0x1e, 0x19, 0xa3, 0x99, 0x2b + }; + + var hostValidationSuccessful = false; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.HostKeyReceived += (sender, e) => + { + if (host_rsa_key_openssh_fingerprint.Length == e.FingerPrint.Length) + { + for (var i = 0; i < host_rsa_key_openssh_fingerprint.Length; i++) + { + if (host_rsa_key_openssh_fingerprint[i] != e.FingerPrint[i]) + { + e.CanTrust = false; + break; + } + } + + hostValidationSuccessful = e.CanTrust; + } + else + { + e.CanTrust = false; + } + }; + client.Connect(); + } + + Assert.IsTrue(hostValidationSuccessful); + } + + /// + /// Verifies whether we handle a disconnect initiated by the SSH server (through a SSH_MSG_DISCONNECT message). + /// + /// + /// We force this by only configuring keyboard-interactive as authentication method, while ChallengeResponseAuthentication + /// is not enabled. This causes OpenSSH to terminate the connection because there are no authentication methods left. + /// + [TestMethod] + public void Common_ServerRejectsConnection() + { + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "keyboard-interactive") + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserKeyboardInteractiveAuthenticationMethod()); + using (var client = new SftpClient(connectionInfo)) + { + try + { + client.Connect(); + Assert.Fail(); + } + catch (SshConnectionException ex) + { + Assert.AreEqual(DisconnectReason.ProtocolError, ex.DisconnectReason); + Assert.IsNull(ex.InnerException); + Assert.AreEqual("The connection was closed by the server: no authentication methods enabled (ProtocolError).", ex.Message); + } + } + } + + } +} diff --git a/src/Renci.SshNet.IntegrationTests/Credential.cs b/src/Renci.SshNet.IntegrationTests/Credential.cs new file mode 100644 index 000000000..ee62d0f7b --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/Credential.cs @@ -0,0 +1,14 @@ +锘縩amespace Renci.SshNet.IntegrationTests +{ + internal class Credential + { + public Credential(string userName, string password) + { + UserName = userName; + Password = password; + } + + public string UserName { get; } + public string Password { get; } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/HostConfig.cs b/src/Renci.SshNet.IntegrationTests/HostConfig.cs new file mode 100644 index 000000000..817bd7026 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/HostConfig.cs @@ -0,0 +1,115 @@ +锘縰sing System.Net; +using System.Text.RegularExpressions; + +namespace Renci.SshNet.IntegrationTests +{ + class HostConfig + { + private static readonly Regex HostsEntryRegEx = new Regex(@"^(?[\S]+)\s+(?[a-zA-Z]+[a-zA-Z\-\.]*[a-zA-Z]+)\s*(?.+)*$", RegexOptions.Singleline); + + public List Entries { get; } + + private HostConfig() + { + Entries = new List(); + } + + public static HostConfig Read(ScpClient scpClient, string path) + { + HostConfig hostConfig = new HostConfig(); + + using (var ms = new MemoryStream()) + { + scpClient.Download(path, ms); + ms.Position = 0; + + using (var sr = new StreamReader(ms, Encoding.ASCII)) + { + string line; + while ((line = sr.ReadLine()) != null) + { + // skip comments + if (line.StartsWith("#")) + { + continue; + } + + var hostEntryMatch = HostsEntryRegEx.Match(line); + if (!hostEntryMatch.Success) + { + continue; + } + + var entryIPAddress = hostEntryMatch.Groups["IPAddress"].Value; + var entryAliasesGroup = hostEntryMatch.Groups["Aliases"]; + + var entry = new HostEntry(IPAddress.Parse(entryIPAddress), hostEntryMatch.Groups["HostName"].Value); + + if (entryAliasesGroup.Success) + { + var aliases = entryAliasesGroup.Value.Split(' '); + foreach (var alias in aliases) + { + entry.Aliases.Add(alias); + } + } + + hostConfig.Entries.Add(entry); + } + } + } + + return hostConfig; + } + + public void Write(ScpClient scpClient, string path) + { + using (var ms = new MemoryStream()) + using (var sw = new StreamWriter(ms, Encoding.ASCII)) + { + // Use linux line ending + sw.NewLine = "\n"; + + foreach (var hostEntry in Entries) + { + sw.Write(hostEntry.IPAddress); + sw.Write(" "); + sw.Write(hostEntry.HostName); + + if (hostEntry.Aliases.Count > 0) + { + sw.Write(" "); + for (var i = 0; i < hostEntry.Aliases.Count; i++) + { + if (i > 0) + { + sw.Write(' '); + } + sw.Write(hostEntry.Aliases[i]); + } + } + sw.WriteLine(); + } + + sw.Flush(); + ms.Position = 0; + + scpClient.Upload(ms, path); + } + } + } + + public class HostEntry + { + public HostEntry(IPAddress ipAddress, string hostName) + { + IPAddress = ipAddress; + HostName = hostName; + Aliases = new List(); + } + + public IPAddress IPAddress { get; private set; } + public string HostName { get; set; } + public List Aliases { get; } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs b/src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs new file mode 100644 index 000000000..3732f1e22 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs @@ -0,0 +1,105 @@ +锘縰sing Renci.SshNet.Common; +using Renci.SshNet.IntegrationTests.Common; +using Renci.SshNet.TestTools.OpenSSH; + +namespace Renci.SshNet.IntegrationTests +{ + [TestClass] + public class HostKeyAlgorithmTests : IntegrationTestBase + { + private IConnectionInfoFactory _connectionInfoFactory; + private RemoteSshdConfig _remoteSshdConfig; + + [TestInitialize] + public void SetUp() + { + _connectionInfoFactory = new LinuxVMConnectionFactory(SshServerHostName, SshServerPort); + _remoteSshdConfig = new RemoteSshd(new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort)).OpenConfig(); + } + + [TestCleanup] + public void TearDown() + { + _remoteSshdConfig?.Reset(); + } + + [TestMethod] + [Ignore] // No longer supported in recent versions of OpenSSH + public void SshDsa() + { + _remoteSshdConfig.ClearHostKeyAlgorithms() + .AddHostKeyAlgorithm(HostKeyAlgorithm.SshDsa) + .ClearHostKeyFiles() + .AddHostKeyFile(HostKeyFile.Dsa.FilePath) + .Update() + .Restart(); + + HostKeyEventArgs hostKeyEventsArgs = null; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.HostKeyReceived += (sender, e) => hostKeyEventsArgs = e; + client.Connect(); + client.Disconnect(); + } + + Assert.IsNotNull(hostKeyEventsArgs); + Assert.AreEqual(HostKeyFile.Dsa.KeyName, hostKeyEventsArgs.HostKeyName); + Assert.AreEqual(1024, hostKeyEventsArgs.KeyLength); + Assert.IsTrue(hostKeyEventsArgs.FingerPrint.SequenceEqual(HostKeyFile.Dsa.FingerPrint)); + } + + [TestMethod] + public void SshRsa() + { + _remoteSshdConfig.ClearHostKeyAlgorithms() + .AddHostKeyAlgorithm(HostKeyAlgorithm.SshRsa) + .Update() + .Restart(); + + HostKeyEventArgs hostKeyEventsArgs = null; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.HostKeyReceived += (sender, e) => hostKeyEventsArgs = e; + client.Connect(); + client.Disconnect(); + } + + Assert.IsNotNull(hostKeyEventsArgs); + Assert.AreEqual(HostKeyFile.Rsa.KeyName, hostKeyEventsArgs.HostKeyName); + Assert.AreEqual(3072, hostKeyEventsArgs.KeyLength); + Assert.IsTrue(hostKeyEventsArgs.FingerPrint.SequenceEqual(HostKeyFile.Rsa.FingerPrint)); + } + + [TestMethod] + public void SshEd25519() + { + _remoteSshdConfig.ClearHostKeyAlgorithms() + .AddHostKeyAlgorithm(HostKeyAlgorithm.SshEd25519) + .ClearHostKeyFiles() + .AddHostKeyFile(HostKeyFile.Ed25519.FilePath) + .Update() + .Restart(); + + HostKeyEventArgs hostKeyEventsArgs = null; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.HostKeyReceived += (sender, e) => hostKeyEventsArgs = e; + client.Connect(); + client.Disconnect(); + } + + Assert.IsNotNull(hostKeyEventsArgs); + Assert.AreEqual(HostKeyFile.Ed25519.KeyName, hostKeyEventsArgs.HostKeyName); + Assert.AreEqual(256, hostKeyEventsArgs.KeyLength); + Assert.IsTrue(hostKeyEventsArgs.FingerPrint.SequenceEqual(HostKeyFile.Ed25519.FingerPrint)); + } + + private void Client_HostKeyReceived(object sender, HostKeyEventArgs e) + { + throw new NotImplementedException(); + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/HostKeyFile.cs b/src/Renci.SshNet.IntegrationTests/HostKeyFile.cs new file mode 100644 index 000000000..01cf957f5 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/HostKeyFile.cs @@ -0,0 +1,23 @@ +锘縩amespace Renci.SshNet.IntegrationTests +{ + public sealed class HostKeyFile + { + public static readonly HostKeyFile Rsa = new HostKeyFile("ssh-rsa", "/etc/ssh/ssh_host_rsa_key", new byte[] { 0x3d, 0x90, 0xd8, 0x0d, 0xd5, 0xe0, 0xb6, 0x13, 0x42, 0x7c, 0x78, 0x1e, 0x19, 0xa3, 0x99, 0x2b }); + public static readonly HostKeyFile Dsa = new HostKeyFile("ssh-dsa", "/etc/ssh/ssh_host_dsa_key", new byte[] { 0x3d, 0x90, 0xd8, 0x0d, 0xd5, 0xe0, 0xb6, 0x13, 0x42, 0x7c, 0x78, 0x1e, 0x19, 0xa3, 0x99, 0x2b }); + public static readonly HostKeyFile Ed25519 = new HostKeyFile("ssh-ed25519", "/etc/ssh/ssh_host_ed25519_key", new byte[] { 0xb3, 0xb9, 0xd0, 0x1b, 0x73, 0xc4, 0x60, 0xb4, 0xce, 0xed, 0x06, 0xf8, 0x58, 0x49, 0xa3, 0xda }); + public const string Ecdsa = "/etc/ssh/ssh_host_ecdsa_key"; + + private HostKeyFile(string keyName, string filePath, byte[] fingerPrint) + { + KeyName = keyName; + FilePath = filePath; + FingerPrint = fingerPrint; + } + + public string KeyName {get; } + public string FilePath { get; } + public byte[] FingerPrint { get; } + } + + +} diff --git a/src/Renci.SshNet.IntegrationTests/IConnectionInfoFactory.cs b/src/Renci.SshNet.IntegrationTests/IConnectionInfoFactory.cs new file mode 100644 index 000000000..858dd0872 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/IConnectionInfoFactory.cs @@ -0,0 +1,10 @@ +锘縩amespace Renci.SshNet.IntegrationTests +{ + public interface IConnectionInfoFactory + { + ConnectionInfo Create(); + ConnectionInfo Create(params AuthenticationMethod[] authenticationMethods); + ConnectionInfo CreateWithProxy(); + ConnectionInfo CreateWithProxy(params AuthenticationMethod[] authenticationMethods); + } +} diff --git a/src/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs b/src/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs new file mode 100644 index 000000000..dfd6b6394 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs @@ -0,0 +1,206 @@ +锘縰sing Renci.SshNet.IntegrationTests.Common; +using Renci.SshNet.TestTools.OpenSSH; + +namespace Renci.SshNet.IntegrationTests +{ + [TestClass] + public class KeyExchangeAlgorithmTests : IntegrationTestBase + { + private IConnectionInfoFactory _connectionInfoFactory; + private RemoteSshdConfig _remoteSshdConfig; + + [TestInitialize] + public void SetUp() + { + _connectionInfoFactory = new LinuxVMConnectionFactory(SshServerHostName, SshServerPort); + _remoteSshdConfig = new RemoteSshd(new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort)).OpenConfig(); + } + + [TestCleanup] + public void TearDown() + { + _remoteSshdConfig?.Reset(); + } + + [TestMethod] + public void Curve25519Sha256() + { + _remoteSshdConfig.ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.Curve25519Sha256) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void Curve25519Sha256Libssh() + { + _remoteSshdConfig.ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.Curve25519Sha256Libssh) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void DiffieHellmanGroup1Sha1() + { + _remoteSshdConfig.ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.DiffieHellmanGroup1Sha1) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void DiffieHellmanGroup14Sha1() + { + _remoteSshdConfig.ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.DiffieHellmanGroup14Sha1) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void DiffieHellmanGroup14Sha256() + { + _remoteSshdConfig.ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.DiffieHellmanGroup14Sha256) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void DiffieHellmanGroup16Sha512() + { + _remoteSshdConfig.ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.DiffieHellmanGroup16Sha512) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + [Ignore] + public void DiffieHellmanGroup18Sha512() + { + _remoteSshdConfig.ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.DiffieHellmanGroup18Sha512) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void DiffieHellmanGroupExchangeSha1() + { + _remoteSshdConfig.ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.DiffieHellmanGroupExchangeSha1) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void DiffieHellmanGroupExchangeSha256() + { + _remoteSshdConfig.ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.DiffieHellmanGroupExchangeSha256) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void EcdhSha2Nistp256() + { + _remoteSshdConfig.ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.EcdhSha2Nistp256) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void EcdhSha2Nistp384() + { + _remoteSshdConfig.ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.EcdhSha2Nistp384) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void EcdhSha2Nistp521() + { + _remoteSshdConfig.ClearKeyExchangeAlgorithms() + .AddKeyExchangeAlgorithm(KeyExchangeAlgorithm.EcdhSha2Nistp521) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/LinuxAdminConnectionFactory.cs b/src/Renci.SshNet.IntegrationTests/LinuxAdminConnectionFactory.cs new file mode 100644 index 000000000..dfb5c1369 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/LinuxAdminConnectionFactory.cs @@ -0,0 +1,36 @@ +锘縩amespace Renci.SshNet.IntegrationTests +{ + public class LinuxAdminConnectionFactory : IConnectionInfoFactory + { + private readonly string _host; + private readonly int _port; + + public LinuxAdminConnectionFactory(string sshServerHostName, ushort sshServerPort) + { + _host = sshServerHostName; + _port = sshServerPort; + } + + public ConnectionInfo Create() + { + var user = Users.Admin; + return new ConnectionInfo(_host, _port, user.UserName, new PasswordAuthenticationMethod(user.UserName, user.Password)); + } + + public ConnectionInfo Create(params AuthenticationMethod[] authenticationMethods) + { + throw new NotImplementedException(); + } + + public ConnectionInfo CreateWithProxy() + { + throw new NotImplementedException(); + } + + public ConnectionInfo CreateWithProxy(params AuthenticationMethod[] authenticationMethods) + { + throw new NotImplementedException(); + } + } +} + diff --git a/src/Renci.SshNet.IntegrationTests/LinuxVMConnectionFactory.cs b/src/Renci.SshNet.IntegrationTests/LinuxVMConnectionFactory.cs new file mode 100644 index 000000000..f2f04dbfc --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/LinuxVMConnectionFactory.cs @@ -0,0 +1,62 @@ +锘縩amespace Renci.SshNet.IntegrationTests +{ + public class LinuxVMConnectionFactory : IConnectionInfoFactory + { + + + private const string ProxyHost = "127.0.0.1"; + private const int ProxyPort = 1234; + private const string ProxyUserName = "test"; + private const string ProxyPassword = "123"; + private readonly string _host; + private readonly int _port; + private readonly AuthenticationMethodFactory _authenticationMethodFactory; + + + public LinuxVMConnectionFactory(string sshServerHostName, ushort sshServerPort) + { + _host = sshServerHostName; + _port = sshServerPort; + + _authenticationMethodFactory = new AuthenticationMethodFactory(); + } + + public LinuxVMConnectionFactory(string sshServerHostName, ushort sshServerPort, AuthenticationMethodFactory authenticationMethodFactory) + { + _host = sshServerHostName; + _port = sshServerPort; + + _authenticationMethodFactory = authenticationMethodFactory; + } + + public ConnectionInfo Create() + { + return Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod()); + } + + public ConnectionInfo Create(params AuthenticationMethod[] authenticationMethods) + { + return new ConnectionInfo(_host, _port, Users.Regular.UserName, authenticationMethods); + } + + public ConnectionInfo CreateWithProxy() + { + return CreateWithProxy(_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod()); + } + + public ConnectionInfo CreateWithProxy(params AuthenticationMethod[] authenticationMethods) + { + return new ConnectionInfo( + _host, + _port, + Users.Regular.UserName, + ProxyTypes.Socks4, + ProxyHost, + ProxyPort, + ProxyUserName, + ProxyPassword, + authenticationMethods); + } + } +} + diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/AesCipherTests.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/AesCipherTests.cs new file mode 100644 index 000000000..7e9e97b01 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/AesCipherTests.cs @@ -0,0 +1,147 @@ +锘縰sing Renci.SshNet.IntegrationTests.Common; +using Renci.SshNet.Security.Cryptography.Ciphers; +using Renci.SshNet.Security.Cryptography.Ciphers.Modes; +using Renci.SshNet.TestTools.OpenSSH; + +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests +{ + [TestClass] + public class AesCipherTests : IntegrationTestBase + { + private IConnectionInfoFactory _adminConnectionInfoFactory; + private RemoteSshdConfig _remoteSshdConfig; + + [TestInitialize] + public void SetUp() + { + _adminConnectionInfoFactory = new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort); + _remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig(); + } + + [TestCleanup] + public void TearDown() + { + _remoteSshdConfig?.Reset(); + } + + [TestMethod] + [Owner("olegkap")] + [TestCategory("Cipher")] + public void Test_Cipher_AEes128CBC_Connection() + { + _remoteSshdConfig.AddCipher(Cipher.Aes128Cbc) + .Update() + .Restart(); + + var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); + connectionInfo.Encryptions.Clear(); + connectionInfo.Encryptions.Add("aes128-cbc", new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), null); })); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + [Owner("olegkap")] + [TestCategory("Cipher")] + public void Test_Cipher_Aes192CBC_Connection() + { + _remoteSshdConfig.AddCipher(Cipher.Aes192Cbc) + .Update() + .Restart(); + + var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); + connectionInfo.Encryptions.Clear(); + connectionInfo.Encryptions.Add("aes192-cbc", new CipherInfo(192, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), null); })); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + [Owner("olegkap")] + [TestCategory("Cipher")] + public void Test_Cipher_Aes256CBC_Connection() + { + _remoteSshdConfig.AddCipher(Cipher.Aes256Cbc) + .Update() + .Restart(); + + var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); + connectionInfo.Encryptions.Clear(); + connectionInfo.Encryptions.Add("aes256-cbc", new CipherInfo(256, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), null); })); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + [Owner("olegkap")] + [TestCategory("Cipher")] + public void Test_Cipher_Aes128CTR_Connection() + { + _remoteSshdConfig.AddCipher(Cipher.Aes128Ctr) + .Update() + .Restart(); + + var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); + connectionInfo.Encryptions.Clear(); + connectionInfo.Encryptions.Add("aes128-ctr", new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CtrCipherMode(iv), null); })); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + [Owner("olegkap")] + [TestCategory("Cipher")] + public void Test_Cipher_Aes192CTR_Connection() + { + _remoteSshdConfig.AddCipher(Cipher.Aes192Ctr) + .Update() + .Restart(); + + var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); + connectionInfo.Encryptions.Clear(); + connectionInfo.Encryptions.Add("aes192-ctr", new CipherInfo(192, (key, iv) => { return new AesCipher(key, new CtrCipherMode(iv), null); })); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + [Owner("olegkap")] + [TestCategory("Cipher")] + public void Test_Cipher_Aes256CTR_Connection() + { + _remoteSshdConfig.AddCipher(Cipher.Aes256Ctr) + .Update() + .Restart(); + + var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); + connectionInfo.Encryptions.Clear(); + connectionInfo.Encryptions.Add("aes256-ctr", new CipherInfo(256, (key, iv) => { return new AesCipher(key, new CtrCipherMode(iv), null); })); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + client.Disconnect(); + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs new file mode 100644 index 000000000..bf6292faa --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs @@ -0,0 +1,158 @@ +锘縰sing System.Diagnostics; + +using Renci.SshNet.Common; + +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests +{ + /// + /// Provides functionality for local port forwarding + /// + [TestClass] + public class ForwardedPortLocalTest : IntegrationTestBase + { + [TestMethod] + [WorkItem(713)] + [Owner("Kenneth_aa")] + [TestCategory("PortForwarding")] + [Description("Test if calling Stop on ForwardedPortLocal instance causes wait.")] + public void Test_PortForwarding_Local_Stop_Hangs_On_Wait() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + + var port1 = new ForwardedPortLocal("localhost", 8084, "www.google.com", 80); + client.AddForwardedPort(port1); + port1.Exception += delegate (object sender, ExceptionEventArgs e) + { + Assert.Fail(e.Exception.ToString()); + }; + + port1.Start(); + + var hasTestedTunnel = false; + + _ = ThreadPool.QueueUserWorkItem(delegate (object state) + { + try + { + var url = "http://www.google.com/"; + Debug.WriteLine("Starting web request to \"" + url + "\""); + +#if NET6_0_OR_GREATER + var httpClient = new HttpClient(); + var response = httpClient.GetAsync(url) + .ConfigureAwait(false) + .GetAwaiter() + .GetResult(); +#else + var request = (HttpWebRequest) WebRequest.Create(url); + var response = (HttpWebResponse) request.GetResponse(); +#endif // NET6_0_OR_GREATER + + Assert.IsNotNull(response); + + Debug.WriteLine("Http Response status code: " + response.StatusCode.ToString()); + + response.Dispose(); + + hasTestedTunnel = true; + } + catch (Exception ex) + { + Assert.Fail(ex.ToString()); + } + }); + + // Wait for the web request to complete. + while (!hasTestedTunnel) + { + Thread.Sleep(1000); + } + + try + { + // Try stop the port forwarding, wait 3 seconds and fail if it is still started. + _ = ThreadPool.QueueUserWorkItem(delegate (object state) + { + Debug.WriteLine("Trying to stop port forward."); + port1.Stop(); + Debug.WriteLine("Port forwarding stopped."); + }); + + Thread.Sleep(3000); + if (port1.IsStarted) + { + Assert.Fail("Port forwarding not stopped."); + } + } + catch (Exception ex) + { + Assert.Fail(ex.ToString()); + } + client.RemoveForwardedPort(port1); + client.Disconnect(); + Debug.WriteLine("Success."); + } + } + + [TestMethod] + [ExpectedException(typeof(SshConnectionException))] + public void Test_PortForwarding_Local_Without_Connecting() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + var port1 = new ForwardedPortLocal("localhost", 8084, "www.renci.org", 80); + client.AddForwardedPort(port1); + port1.Exception += delegate (object sender, ExceptionEventArgs e) + { + Assert.Fail(e.Exception.ToString()); + }; + port1.Start(); + + var test = Parallel.For(0, + 100, + counter => + { + var start = DateTime.Now; + +#if NET6_0_OR_GREATER + var httpClient = new HttpClient(); + using (var response = httpClient.GetAsync("http://localhost:8084").GetAwaiter().GetResult()) + { + var data = ReadStream(response.Content.ReadAsStream()); +#else + var request = (HttpWebRequest) WebRequest.Create("http://localhost:8084"); + using (var response = (HttpWebResponse) request.GetResponse()) + { + var data = ReadStream(response.GetResponseStream()); +#endif // NET6_0_OR_GREATER + var end = DateTime.Now; + + Debug.WriteLine(string.Format("Request# {2}: Lenght: {0} Time: {1}", data.Length, end - start, counter)); + } + }); + } + } + + private static byte[] ReadStream(Stream stream) + { + var buffer = new byte[1024]; + using (var ms = new MemoryStream()) + { + while (true) + { + var read = stream.Read(buffer, 0, buffer.Length); + if (read > 0) + { + ms.Write(buffer, 0, read); + } + else + { + return ms.ToArray(); + } + } + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/HMacTest.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/HMacTest.cs new file mode 100644 index 000000000..c8df34e9d --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/HMacTest.cs @@ -0,0 +1,67 @@ +锘縰sing Renci.SshNet.Abstractions; +using Renci.SshNet.IntegrationTests.Common; + +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests +{ + [TestClass] + public class HMacTest : IntegrationTestBase + { + private IConnectionInfoFactory _adminConnectionInfoFactory; + private RemoteSshdConfig _remoteSshdConfig; + + [TestInitialize] + public void SetUp() + { + _adminConnectionInfoFactory = new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort); + _remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig(); + } + + [TestCleanup] + public void TearDown() + { + _remoteSshdConfig?.Reset(); + } + + [TestMethod] + public void Test_HMac_Sha1_Connection() + { + var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); + connectionInfo.HmacAlgorithms.Clear(); + connectionInfo.HmacAlgorithms.Add("hmac-sha1", new HashInfo(20 * 8, CryptoAbstraction.CreateHMACSHA1)); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void Test_HMac_Sha256_Connection() + { + var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); + connectionInfo.HmacAlgorithms.Clear(); + connectionInfo.HmacAlgorithms.Add("hmac-sha2-256", new HashInfo(32 * 8, CryptoAbstraction.CreateHMACSHA256)); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + client.Disconnect(); + } + } + + [TestMethod] + public void Test_HMac_Sha2_512_Connection() + { + var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); + connectionInfo.HmacAlgorithms.Clear(); + connectionInfo.HmacAlgorithms.Add("hmac-sha2-512", new HashInfo(64 * 8, CryptoAbstraction.CreateHMACSHA512)); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + client.Disconnect(); + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/ScpClientTest.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/ScpClientTest.cs new file mode 100644 index 000000000..e9015a3c6 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/ScpClientTest.cs @@ -0,0 +1,336 @@ +锘縰sing System.Security.Cryptography; + +using Renci.SshNet.Common; + +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests +{ + /// + /// Provides SCP client functionality. + /// + [TestClass] + public partial class ScpClientTest : IntegrationTestBase + { + [TestMethod] + [TestCategory("Scp")] + public void Test_Scp_File_Upload_Download() + { + RemoveAllFiles(); + + using (var scp = new ScpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + scp.Connect(); + + var uploadedFileName = Path.GetTempFileName(); + var downloadedFileName = Path.GetTempFileName(); + + CreateTestFile(uploadedFileName, 1); + + scp.Upload(new FileInfo(uploadedFileName), Path.GetFileName(uploadedFileName)); + + scp.Download(Path.GetFileName(uploadedFileName), new FileInfo(downloadedFileName)); + + // Calculate MD5 value + var uploadedHash = CalculateMD5(uploadedFileName); + var downloadedHash = CalculateMD5(downloadedFileName); + + File.Delete(uploadedFileName); + File.Delete(downloadedFileName); + + scp.Disconnect(); + + Assert.AreEqual(uploadedHash, downloadedHash); + } + } + + [TestMethod] + [TestCategory("Scp")] + public void Test_Scp_Stream_Upload_Download() + { + RemoveAllFiles(); + + using (var scp = new ScpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + scp.Connect(); + + var uploadedFileName = Path.GetTempFileName(); + var downloadedFileName = Path.GetTempFileName(); + + CreateTestFile(uploadedFileName, 1); + + // Calculate has value + using (var stream = File.OpenRead(uploadedFileName)) + { + scp.Upload(stream, Path.GetFileName(uploadedFileName)); + } + + using (var stream = File.OpenWrite(downloadedFileName)) + { + scp.Download(Path.GetFileName(uploadedFileName), stream); + } + + // Calculate MD5 value + var uploadedHash = CalculateMD5(uploadedFileName); + var downloadedHash = CalculateMD5(downloadedFileName); + + File.Delete(uploadedFileName); + File.Delete(downloadedFileName); + + scp.Disconnect(); + + Assert.AreEqual(uploadedHash, downloadedHash); + } + } + + [TestMethod] + [TestCategory("Scp")] + public void Test_Scp_10MB_File_Upload_Download() + { + RemoveAllFiles(); + + using (var scp = new ScpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + scp.Connect(); + + var uploadedFileName = Path.GetTempFileName(); + var downloadedFileName = Path.GetTempFileName(); + + CreateTestFile(uploadedFileName, 10); + + scp.Upload(new FileInfo(uploadedFileName), Path.GetFileName(uploadedFileName)); + + scp.Download(Path.GetFileName(uploadedFileName), new FileInfo(downloadedFileName)); + + // Calculate MD5 value + var uploadedHash = CalculateMD5(uploadedFileName); + var downloadedHash = CalculateMD5(downloadedFileName); + + File.Delete(uploadedFileName); + File.Delete(downloadedFileName); + + scp.Disconnect(); + + Assert.AreEqual(uploadedHash, downloadedHash); + } + } + + [TestMethod] + [TestCategory("Scp")] + public void Test_Scp_10MB_Stream_Upload_Download() + { + RemoveAllFiles(); + + using (var scp = new ScpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + scp.Connect(); + + var uploadedFileName = Path.GetTempFileName(); + var downloadedFileName = Path.GetTempFileName(); + + CreateTestFile(uploadedFileName, 10); + + // Calculate has value + using (var stream = File.OpenRead(uploadedFileName)) + { + scp.Upload(stream, Path.GetFileName(uploadedFileName)); + } + + using (var stream = File.OpenWrite(downloadedFileName)) + { + scp.Download(Path.GetFileName(uploadedFileName), stream); + } + + // Calculate MD5 value + var uploadedHash = CalculateMD5(uploadedFileName); + var downloadedHash = CalculateMD5(downloadedFileName); + + File.Delete(uploadedFileName); + File.Delete(downloadedFileName); + + scp.Disconnect(); + + Assert.AreEqual(uploadedHash, downloadedHash); + } + } + + [TestMethod] + [TestCategory("Scp")] + public void Test_Scp_Directory_Upload_Download() + { + RemoveAllFiles(); + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + sftp.CreateDirectory("uploaded_dir"); + } + + using (var scp = new ScpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + scp.Connect(); + + var uploadDirectory = + Directory.CreateDirectory(string.Format("{0}\\{1}", Path.GetTempPath(), Path.GetRandomFileName())); + for (var i = 0; i < 3; i++) + { + var subfolder = Directory.CreateDirectory(string.Format(@"{0}\folder_{1}", uploadDirectory.FullName, i)); + + for (var j = 0; j < 5; j++) + { + CreateTestFile(string.Format(@"{0}\file_{1}", subfolder.FullName, j), 1); + } + + CreateTestFile(string.Format(@"{0}\file_{1}", uploadDirectory.FullName, i), 1); + } + + scp.Upload(uploadDirectory, "uploaded_dir"); + + var downloadDirectory = + Directory.CreateDirectory(string.Format("{0}\\{1}", Path.GetTempPath(), Path.GetRandomFileName())); + + scp.Download("uploaded_dir", downloadDirectory); + + var uploadedFiles = uploadDirectory.GetFiles("*.*", SearchOption.AllDirectories); + var downloadFiles = downloadDirectory.GetFiles("*.*", SearchOption.AllDirectories); + + var result = from f1 in uploadedFiles + from f2 in downloadFiles + where + f1.FullName.Substring(uploadDirectory.FullName.Length) == + f2.FullName.Substring(downloadDirectory.FullName.Length) + && CalculateMD5(f1.FullName) == CalculateMD5(f2.FullName) + select f1; + + var counter = result.Count(); + + scp.Disconnect(); + + Assert.IsTrue(counter == uploadedFiles.Length && uploadedFiles.Length == downloadFiles.Length); + } + RemoveAllFiles(); + } + + [TestMethod] + [TestCategory("Scp")] + public void Test_Scp_File_20_Parallel_Upload_Download() + { + using (var scp = new ScpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + scp.Connect(); + + var uploadFilenames = new string[20]; + for (var i = 0; i < uploadFilenames.Length; i++) + { + uploadFilenames[i] = Path.GetTempFileName(); + CreateTestFile(uploadFilenames[i], 1); + } + + _ = Parallel.ForEach(uploadFilenames, + filename => + { + scp.Upload(new FileInfo(filename), Path.GetFileName(filename)); + }); + _ = Parallel.ForEach(uploadFilenames, + filename => + { + scp.Download(Path.GetFileName(filename), new FileInfo(string.Format("{0}.down", filename))); + }); + + var result = from file in uploadFilenames + where CalculateMD5(file) == CalculateMD5(string.Format("{0}.down", file)) + select file; + + scp.Disconnect(); + + Assert.IsTrue(result.Count() == uploadFilenames.Length); + } + } + + [TestMethod] + [TestCategory("Scp")] + public void Test_Scp_File_Upload_Download_Events() + { + using (var scp = new ScpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + scp.Connect(); + + var uploadFilenames = new string[10]; + + for (var i = 0; i < uploadFilenames.Length; i++) + { + uploadFilenames[i] = Path.GetTempFileName(); + CreateTestFile(uploadFilenames[i], 1); + } + + var uploadedFiles = uploadFilenames.ToDictionary(Path.GetFileName, (filename) => 0L); + var downloadedFiles = uploadFilenames.ToDictionary((filename) => string.Format("{0}.down", Path.GetFileName(filename)), (filename) => 0L); + + scp.Uploading += delegate (object sender, ScpUploadEventArgs e) + { + uploadedFiles[e.Filename] = e.Uploaded; + }; + + scp.Downloading += delegate (object sender, ScpDownloadEventArgs e) + { + downloadedFiles[string.Format("{0}.down", e.Filename)] = e.Downloaded; + }; + + _ = Parallel.ForEach(uploadFilenames, + filename => + { + scp.Upload(new FileInfo(filename), Path.GetFileName(filename)); + }); + _ = Parallel.ForEach(uploadFilenames, + filename => + { + scp.Download(Path.GetFileName(filename), new FileInfo(string.Format("{0}.down", filename))); + }); + + var result = from uf in uploadedFiles + from df in downloadedFiles + where string.Format("{0}.down", uf.Key) == df.Key && uf.Value == df.Value + select uf; + + scp.Disconnect(); + + Assert.IsTrue(result.Count() == uploadFilenames.Length && uploadFilenames.Length == uploadedFiles.Count && uploadedFiles.Count == downloadedFiles.Count); + } + } + + protected static string CalculateMD5(string fileName) + { + using (var file = new FileStream(fileName, FileMode.Open)) + { +#if NET7_0_OR_GREATER + var hash = MD5.HashData(file); +#else +#if NET6_0 + var md5 = MD5.Create(); +#else + MD5 md5 = new MD5CryptoServiceProvider(); +#endif // NET6_0 + var hash = md5.ComputeHash(file); +#endif // NET7_0_OR_GREATER + + file.Close(); + + var sb = new StringBuilder(); + + for (var i = 0; i < hash.Length; i++) + { + _ = sb.Append(i.ToString("x2")); + } + + return sb.ToString(); + } + } + + private void RemoveAllFiles() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + _ = client.RunCommand("rm -rf *"); + client.Disconnect(); + } + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ChangeDirectory.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ChangeDirectory.cs similarity index 66% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.ChangeDirectory.cs rename to src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ChangeDirectory.cs index 5c58e1fa1..6fb518506 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ChangeDirectory.cs +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ChangeDirectory.cs @@ -1,21 +1,18 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Properties; +锘縰sing Renci.SshNet.Common; -namespace Renci.SshNet.Tests.Classes +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests { /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest + public partial class SftpClientTest : IntegrationTestBase { [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [ExpectedException(typeof(SftpPathNotFoundException))] public void Test_Sftp_ChangeDirectory_Root_Dont_Exists() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); sftp.ChangeDirectory("/asdasd"); @@ -24,11 +21,10 @@ public void Test_Sftp_ChangeDirectory_Root_Dont_Exists() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [ExpectedException(typeof(SftpPathNotFoundException))] public void Test_Sftp_ChangeDirectory_Root_With_Slash_Dont_Exists() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); sftp.ChangeDirectory("/asdasd/"); @@ -37,11 +33,10 @@ public void Test_Sftp_ChangeDirectory_Root_With_Slash_Dont_Exists() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [ExpectedException(typeof(SftpPathNotFoundException))] public void Test_Sftp_ChangeDirectory_Subfolder_Dont_Exists() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); sftp.ChangeDirectory("/asdasd/sssddds"); @@ -50,11 +45,10 @@ public void Test_Sftp_ChangeDirectory_Subfolder_Dont_Exists() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [ExpectedException(typeof(SftpPathNotFoundException))] public void Test_Sftp_ChangeDirectory_Subfolder_With_Slash_Dont_Exists() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); sftp.ChangeDirectory("/asdasd/sssddds/"); @@ -63,10 +57,9 @@ public void Test_Sftp_ChangeDirectory_Subfolder_With_Slash_Dont_Exists() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] public void Test_Sftp_ChangeDirectory_Which_Exists() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); sftp.ChangeDirectory("/usr"); @@ -76,10 +69,9 @@ public void Test_Sftp_ChangeDirectory_Which_Exists() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] public void Test_Sftp_ChangeDirectory_Which_Exists_With_Slash() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); sftp.ChangeDirectory("/usr/"); @@ -87,4 +79,4 @@ public void Test_Sftp_ChangeDirectory_Which_Exists_With_Slash() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.CreateDirectory.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.CreateDirectory.cs new file mode 100644 index 000000000..43b176697 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.CreateDirectory.cs @@ -0,0 +1,72 @@ +锘 +using Renci.SshNet.Common; + +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests +{ + /// + /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. + /// + public partial class SftpClientTest : IntegrationTestBase + { + [TestMethod] + [TestCategory("Sftp")] + public void Test_Sftp_CreateDirectory_In_Current_Location() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + sftp.CreateDirectory("test-in-current"); + + sftp.Disconnect(); + } + } + + [TestMethod] + [TestCategory("Sftp")] + [ExpectedException(typeof(SftpPermissionDeniedException))] + public void Test_Sftp_CreateDirectory_In_Forbidden_Directory() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, AdminUser.UserName, AdminUser.Password)) + { + sftp.Connect(); + + sftp.CreateDirectory("/sbin/test"); + + sftp.Disconnect(); + } + } + + [TestMethod] + [TestCategory("Sftp")] + [ExpectedException(typeof(SftpPathNotFoundException))] + public void Test_Sftp_CreateDirectory_Invalid_Path() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + sftp.CreateDirectory("/abcdefg/abcefg"); + + sftp.Disconnect(); + } + } + + [TestMethod] + [TestCategory("Sftp")] + [ExpectedException(typeof(SshException))] + public void Test_Sftp_CreateDirectory_Already_Exists() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + sftp.CreateDirectory("test"); + + sftp.CreateDirectory("test"); + + sftp.Disconnect(); + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.DeleteDirectory.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.DeleteDirectory.cs new file mode 100644 index 000000000..30697ddce --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.DeleteDirectory.cs @@ -0,0 +1,71 @@ +锘縰sing Renci.SshNet.Common; + +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests +{ + /// + /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. + /// + public partial class SftpClientTest : IntegrationTestBase + { + [TestMethod] + [TestCategory("Sftp")] + [ExpectedException(typeof(SftpPathNotFoundException))] + public void Test_Sftp_DeleteDirectory_Which_Doesnt_Exists() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + sftp.DeleteDirectory("abcdef"); + + sftp.Disconnect(); + } + } + + [TestMethod] + [TestCategory("Sftp")] + [ExpectedException(typeof(SftpPermissionDeniedException))] + public void Test_Sftp_DeleteDirectory_Which_No_Permissions() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, AdminUser.UserName, AdminUser.Password)) + { + sftp.Connect(); + + sftp.DeleteDirectory("/usr"); + + sftp.Disconnect(); + } + } + + [TestMethod] + [TestCategory("Sftp")] + public void Test_Sftp_DeleteDirectory() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + sftp.CreateDirectory("abcdef"); + sftp.DeleteDirectory("abcdef"); + + sftp.Disconnect(); + } + } + + [TestMethod] + [TestCategory("Sftp")] + [Description("Test passing null to DeleteDirectory.")] + [ExpectedException(typeof(ArgumentException))] + public void Test_Sftp_DeleteDirectory_Null() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + sftp.DeleteDirectory(null); + + sftp.Disconnect(); + } + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Download.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Download.cs similarity index 70% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.Download.cs rename to src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Download.cs index 41dbdf33f..318834e4c 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Download.cs +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Download.cs @@ -1,28 +1,18 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Properties; -using System; -using System.IO; +锘縰sing Renci.SshNet.Common; -namespace Renci.SshNet.Tests.Classes +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests { /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest + public partial class SftpClientTest : IntegrationTestBase { [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [ExpectedException(typeof(SftpPermissionDeniedException))] public void Test_Sftp_Download_Forbidden() { - if (Resources.USERNAME == "root") - { - Assert.Fail("Must not run this test as root!"); - } - - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, AdminUser.UserName, AdminUser.Password)) { sftp.Connect(); @@ -39,11 +29,10 @@ public void Test_Sftp_Download_Forbidden() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [ExpectedException(typeof(SftpPathNotFoundException))] public void Test_Sftp_Download_File_Not_Exists() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); @@ -59,12 +48,11 @@ public void Test_Sftp_Download_File_Not_Exists() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [Description("Test passing null to BeginDownloadFile")] [ExpectedException(typeof(ArgumentNullException))] public void Test_Sftp_BeginDownloadFile_StreamIsNull() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); sftp.BeginDownloadFile("aaaa", null, null, null); @@ -74,12 +62,11 @@ public void Test_Sftp_BeginDownloadFile_StreamIsNull() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [Description("Test passing null to BeginDownloadFile")] [ExpectedException(typeof(ArgumentException))] public void Test_Sftp_BeginDownloadFile_FileNameIsWhiteSpace() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); sftp.BeginDownloadFile(" ", new MemoryStream(), null, null); @@ -89,12 +76,11 @@ public void Test_Sftp_BeginDownloadFile_FileNameIsWhiteSpace() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [Description("Test passing null to BeginDownloadFile")] [ExpectedException(typeof(ArgumentException))] public void Test_Sftp_BeginDownloadFile_FileNameIsNull() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); sftp.BeginDownloadFile(null, new MemoryStream(), null, null); @@ -104,15 +90,14 @@ public void Test_Sftp_BeginDownloadFile_FileNameIsNull() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [ExpectedException(typeof(ArgumentException))] public void Test_Sftp_EndDownloadFile_Invalid_Async_Handle() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); var filename = Path.GetTempFileName(); - this.CreateTestFile(filename, 1); + CreateTestFile(filename, 1); sftp.UploadFile(File.OpenRead(filename), "test123"); var async1 = sftp.BeginListDirectory("/", null, null); var async2 = sftp.BeginDownloadFile("test123", new MemoryStream(), null, null); diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ListDirectory.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ListDirectory.cs new file mode 100644 index 000000000..e37e937f9 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ListDirectory.cs @@ -0,0 +1,263 @@ +锘縰sing System.Diagnostics; + +using Renci.SshNet.Common; + +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests +{ + /// + /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. + /// + public partial class SftpClientTest : IntegrationTestBase + { + [TestMethod] + [TestCategory("Sftp")] + [ExpectedException(typeof(SftpPermissionDeniedException))] + public void Test_Sftp_ListDirectory_Permission_Denied() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + var files = sftp.ListDirectory("/root"); + foreach (var file in files) + { + Debug.WriteLine(file.FullName); + } + + sftp.Disconnect(); + } + } + + [TestMethod] + [TestCategory("Sftp")] + [ExpectedException(typeof(SftpPathNotFoundException))] + public void Test_Sftp_ListDirectory_Not_Exists() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + var files = sftp.ListDirectory("/asdfgh"); + foreach (var file in files) + { + Debug.WriteLine(file.FullName); + } + + sftp.Disconnect(); + } + } + + [TestMethod] + [TestCategory("Sftp")] + public void Test_Sftp_ListDirectory_Current() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + var files = sftp.ListDirectory("."); + + Assert.IsTrue(files.Count() > 0); + + foreach (var file in files) + { + Debug.WriteLine(file.FullName); + } + + sftp.Disconnect(); + } + } + +#if NET6_0_OR_GREATER + [TestMethod] + [TestCategory("Sftp")] + public async Task Test_Sftp_ListDirectoryAsync_Current() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromMinutes(1)); + var count = 0; + await foreach(var file in sftp.ListDirectoryAsync(".", cts.Token)) + { + count++; + Debug.WriteLine(file.FullName); + } + + Assert.IsTrue(count > 0); + + sftp.Disconnect(); + } + } +#endif + [TestMethod] + [TestCategory("Sftp")] + public void Test_Sftp_ListDirectory_Empty() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + var files = sftp.ListDirectory(string.Empty); + + Assert.IsTrue(files.Count() > 0); + + foreach (var file in files) + { + Debug.WriteLine(file.FullName); + } + + sftp.Disconnect(); + } + } + + [TestMethod] + [TestCategory("Sftp")] + [Description("Test passing null to ListDirectory.")] + [ExpectedException(typeof(ArgumentNullException))] + public void Test_Sftp_ListDirectory_Null() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + var files = sftp.ListDirectory(null); + + Assert.IsTrue(files.Count() > 0); + + foreach (var file in files) + { + Debug.WriteLine(file.FullName); + } + + sftp.Disconnect(); + } + } + + [TestMethod] + [TestCategory("Sftp")] + public void Test_Sftp_ListDirectory_HugeDirectory() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + // Create 10000 directory items + for (int i = 0; i < 10000; i++) + { + sftp.CreateDirectory(string.Format("test_{0}", i)); + } + + var files = sftp.ListDirectory("."); + + // Ensure that directory has at least 10000 items + Assert.IsTrue(files.Count() > 10000); + + sftp.Disconnect(); + } + + RemoveAllFiles(); + } + + [TestMethod] + [TestCategory("Sftp")] + public void Test_Sftp_Change_Directory() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + Assert.AreEqual(sftp.WorkingDirectory, "/home/sshnet"); + + sftp.CreateDirectory("test1"); + + sftp.ChangeDirectory("test1"); + + Assert.AreEqual(sftp.WorkingDirectory, "/home/sshnet/test1"); + + sftp.CreateDirectory("test1_1"); + sftp.CreateDirectory("test1_2"); + sftp.CreateDirectory("test1_3"); + + var files = sftp.ListDirectory("."); + + Assert.IsTrue(files.First().FullName.StartsWith(string.Format("{0}", sftp.WorkingDirectory))); + + sftp.ChangeDirectory("test1_1"); + + Assert.AreEqual(sftp.WorkingDirectory, "/home/sshnet/test1/test1_1"); + + sftp.ChangeDirectory("../test1_2"); + + Assert.AreEqual(sftp.WorkingDirectory, "/home/sshnet/test1/test1_2"); + + sftp.ChangeDirectory(".."); + + Assert.AreEqual(sftp.WorkingDirectory, "/home/sshnet/test1"); + + sftp.ChangeDirectory(".."); + + Assert.AreEqual(sftp.WorkingDirectory, "/home/sshnet"); + + files = sftp.ListDirectory("test1/test1_1"); + + Assert.IsTrue(files.First().FullName.StartsWith(string.Format("{0}/test1/test1_1", sftp.WorkingDirectory))); + + sftp.ChangeDirectory("test1/test1_1"); + + Assert.AreEqual(sftp.WorkingDirectory, "/home/sshnet/test1/test1_1"); + + sftp.ChangeDirectory("/home/sshnet/test1/test1_1"); + + Assert.AreEqual(sftp.WorkingDirectory, "/home/sshnet/test1/test1_1"); + + sftp.ChangeDirectory("/home/sshnet/test1/test1_1/../test1_2"); + + Assert.AreEqual(sftp.WorkingDirectory, "/home/sshnet/test1/test1_2"); + + sftp.ChangeDirectory("../../"); + + sftp.DeleteDirectory("test1/test1_1"); + sftp.DeleteDirectory("test1/test1_2"); + sftp.DeleteDirectory("test1/test1_3"); + sftp.DeleteDirectory("test1"); + + sftp.Disconnect(); + } + + RemoveAllFiles(); + } + + [TestMethod] + [TestCategory("Sftp")] + [Description("Test passing null to ChangeDirectory.")] + [ExpectedException(typeof(ArgumentNullException))] + public void Test_Sftp_ChangeDirectory_Null() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + sftp.ChangeDirectory(null); + + sftp.Disconnect(); + } + } + + [TestMethod] + [TestCategory("Sftp")] + [Description("Test calling EndListDirectory method more then once.")] + [ExpectedException(typeof(ArgumentException))] + public void Test_Sftp_Call_EndListDirectory_Twice() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + var ar = sftp.BeginListDirectory("/", null, null); + var result = sftp.EndListDirectory(ar); + var result1 = sftp.EndListDirectory(ar); + } + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFile.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFile.cs similarity index 69% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFile.cs rename to src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFile.cs index e1685d099..e74a8e7ed 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFile.cs +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFile.cs @@ -1,21 +1,15 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Properties; -using System; -using System.IO; - -namespace Renci.SshNet.Tests.Classes +锘縩amespace Renci.SshNet.IntegrationTests.OldIntegrationTests { /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest + public partial class SftpClientTest : IntegrationTestBase { [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] public void Test_Sftp_Rename_File() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); @@ -23,7 +17,7 @@ public void Test_Sftp_Rename_File() string remoteFileName1 = Path.GetRandomFileName(); string remoteFileName2 = Path.GetRandomFileName(); - this.CreateTestFile(uploadedFileName, 1); + CreateTestFile(uploadedFileName, 1); using (var file = File.OpenRead(uploadedFileName)) { @@ -42,12 +36,11 @@ public void Test_Sftp_Rename_File() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [Description("Test passing null to RenameFile.")] [ExpectedException(typeof(ArgumentNullException))] public void Test_Sftp_RenameFile_Null() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); @@ -57,4 +50,4 @@ public void Test_Sftp_RenameFile_Null() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFileAsync.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFileAsync.cs similarity index 72% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFileAsync.cs rename to src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFileAsync.cs index a24ec0942..ade91099c 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.RenameFileAsync.cs +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFileAsync.cs @@ -1,22 +1,15 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Properties; -using System; -using System.IO; -using System.Threading.Tasks; - -namespace Renci.SshNet.Tests.Classes +锘縩amespace Renci.SshNet.IntegrationTests.OldIntegrationTests { /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest + public partial class SftpClientTest : IntegrationTestBase { [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] public async Task Test_Sftp_RenameFileAsync() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { await sftp.ConnectAsync(default); @@ -24,7 +17,7 @@ public async Task Test_Sftp_RenameFileAsync() string remoteFileName1 = Path.GetRandomFileName(); string remoteFileName2 = Path.GetRandomFileName(); - this.CreateTestFile(uploadedFileName, 1); + CreateTestFile(uploadedFileName, 1); using (var file = File.OpenRead(uploadedFileName)) { @@ -46,12 +39,11 @@ public async Task Test_Sftp_RenameFileAsync() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [Description("Test passing null to RenameFile.")] [ExpectedException(typeof(ArgumentNullException))] public async Task Test_Sftp_RenameFileAsync_Null() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { await sftp.ConnectAsync(default); diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.SynchronizeDirectories.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.SynchronizeDirectories.cs similarity index 78% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.SynchronizeDirectories.cs rename to src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.SynchronizeDirectories.cs index 2c9ddb3e0..4964715ef 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.SynchronizeDirectories.cs +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.SynchronizeDirectories.cs @@ -1,31 +1,26 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Properties; -using System.Diagnostics; -using System.IO; -using System.Linq; +锘縰sing System.Diagnostics; -namespace Renci.SshNet.Tests.Classes +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests { /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest + public partial class SftpClientTest : IntegrationTestBase { [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] public void Test_Sftp_SynchronizeDirectories() { RemoveAllFiles(); - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); string uploadedFileName = Path.GetTempFileName(); string sourceDir = Path.GetDirectoryName(uploadedFileName); - string destDir = "/"; + string destDir = "/home/sshnet/"; string searchPattern = Path.GetFileName(uploadedFileName); var upLoadedFiles = sftp.SynchronizeDirectories(sourceDir, destDir, searchPattern); @@ -42,19 +37,18 @@ public void Test_Sftp_SynchronizeDirectories() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] public void Test_Sftp_BeginSynchronizeDirectories() { RemoveAllFiles(); - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); string uploadedFileName = Path.GetTempFileName(); string sourceDir = Path.GetDirectoryName(uploadedFileName); - string destDir = "/"; + string destDir = "/home/sshnet/"; string searchPattern = Path.GetFileName(uploadedFileName); var asyncResult = sftp.BeginSynchronizeDirectories(sourceDir, @@ -83,4 +77,4 @@ public void Test_Sftp_BeginSynchronizeDirectories() } } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Upload.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs similarity index 89% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.Upload.cs rename to src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs index 2018c9f0d..91c248bd3 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Upload.cs +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs @@ -1,29 +1,20 @@ -锘縰sing System; -using System.Collections.Generic; -using System.IO; -using System.Threading; - -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Common; +锘縰sing Renci.SshNet.Common; using Renci.SshNet.Sftp; -using Renci.SshNet.Tests.Properties; -namespace Renci.SshNet.Tests.Classes +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests { /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public partial class SftpClientTest + public partial class SftpClientTest : IntegrationTestBase { [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] public void Test_Sftp_Upload_And_Download_1MB_File() { RemoveAllFiles(); - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); @@ -62,11 +53,10 @@ public void Test_Sftp_Upload_And_Download_1MB_File() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [ExpectedException(typeof(SftpPermissionDeniedException))] public void Test_Sftp_Upload_Forbidden() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); @@ -86,7 +76,6 @@ public void Test_Sftp_Upload_Forbidden() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] public void Test_Sftp_Multiple_Async_Upload_And_Download_10Files_5MB_Each() { var maxFiles = 10; @@ -94,8 +83,9 @@ public void Test_Sftp_Multiple_Async_Upload_And_Download_10Files_5MB_Each() RemoveAllFiles(); - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { + sftp.OperationTimeout = TimeSpan.FromMinutes(1); sftp.Connect(); var testInfoList = new Dictionary(); @@ -210,6 +200,11 @@ public void Test_Sftp_Multiple_Async_Upload_And_Download_10Files_5MB_Each() testInfo.DownloadedHash = CalculateMD5(testInfo.DownloadedFileName); + Console.WriteLine(remoteFile); + Console.WriteLine("UploadedBytes: "+ testInfo.UploadResult.UploadedBytes); + Console.WriteLine("DownloadedBytes: " + testInfo.DownloadResult.DownloadedBytes); + Console.WriteLine("UploadedHash: " + testInfo.UploadedHash); + Console.WriteLine("DownloadedHash: " + testInfo.DownloadedHash); if (!(testInfo.UploadResult.UploadedBytes > 0 && testInfo.DownloadResult.DownloadedBytes > 0 && testInfo.DownloadResult.DownloadedBytes == testInfo.UploadResult.UploadedBytes)) { uploadDownloadSizeOk = false; @@ -242,13 +237,12 @@ public void Test_Sftp_Multiple_Async_Upload_And_Download_10Files_5MB_Each() // TODO: Split this test into multiple tests [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [Description("Test that delegates passed to BeginUploadFile, BeginDownloadFile and BeginListDirectory are actually called.")] public void Test_Sftp_Ensure_Async_Delegates_Called_For_BeginFileUpload_BeginFileDownload_BeginListDirectory() { RemoveAllFiles(); - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); @@ -330,12 +324,11 @@ public void Test_Sftp_Ensure_Async_Delegates_Called_For_BeginFileUpload_BeginFil [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [Description("Test passing null to BeginUploadFile")] [ExpectedException(typeof(ArgumentNullException))] public void Test_Sftp_BeginUploadFile_StreamIsNull() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); _ = sftp.BeginUploadFile(null, "aaaaa", null, null); @@ -345,12 +338,11 @@ public void Test_Sftp_BeginUploadFile_StreamIsNull() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [Description("Test passing null to BeginUploadFile")] [ExpectedException(typeof(ArgumentException))] public void Test_Sftp_BeginUploadFile_FileNameIsWhiteSpace() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); _ = sftp.BeginUploadFile(new MemoryStream(), " ", null, null); @@ -360,12 +352,11 @@ public void Test_Sftp_BeginUploadFile_FileNameIsWhiteSpace() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [Description("Test passing null to BeginUploadFile")] [ExpectedException(typeof(ArgumentException))] public void Test_Sftp_BeginUploadFile_FileNameIsNull() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); _ = sftp.BeginUploadFile(new MemoryStream(), null, null, null); @@ -375,11 +366,10 @@ public void Test_Sftp_BeginUploadFile_FileNameIsNull() [TestMethod] [TestCategory("Sftp")] - [TestCategory("integration")] [ExpectedException(typeof(ArgumentException))] public void Test_Sftp_EndUploadFile_Invalid_Async_Handle() { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { sftp.Connect(); var async1 = sftp.BeginListDirectory("/", null, null); diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.cs new file mode 100644 index 000000000..1c7def55b --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.cs @@ -0,0 +1,68 @@ +锘縰sing System.Security.Cryptography; + +using Renci.SshNet.Sftp; + +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests +{ + /// + /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. + /// + [TestClass] + public partial class SftpClientTest + { + protected static string CalculateMD5(string fileName) + { + using (FileStream file = new FileStream(fileName, FileMode.Open)) + { + var hash = MD5.HashData(file); + + file.Close(); + + StringBuilder sb = new StringBuilder(); + for (var i = 0; i < hash.Length; i++) + { + sb.Append(hash[i].ToString("x2")); + } + return sb.ToString(); + } + } + + private void RemoveAllFiles() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + client.RunCommand("rm -rf *"); + client.Disconnect(); + } + } + + /// + /// Helper class to help with upload and download testing + /// + private class TestInfo + { + public string RemoteFileName { get; set; } + + public string UploadedFileName { get; set; } + + public string DownloadedFileName { get; set; } + + //public ulong UploadedBytes { get; set; } + + //public ulong DownloadedBytes { get; set; } + + public FileStream UploadedFile { get; set; } + + public FileStream DownloadedFile { get; set; } + + public string UploadedHash { get; set; } + + public string DownloadedHash { get; set; } + + public SftpUploadAsyncResult UploadResult { get; set; } + + public SftpDownloadAsyncResult DownloadResult { get; set; } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs new file mode 100644 index 000000000..058442511 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs @@ -0,0 +1,120 @@ +锘縰sing Renci.SshNet.Common; + +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests +{ + /// + /// Represents SFTP file information + /// + [TestClass] + public class SftpFileTest : IntegrationTestBase + { + [TestMethod] + [TestCategory("Sftp")] + public void Test_Get_Root_Directory() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + var directory = sftp.Get("/"); + + Assert.AreEqual("/", directory.FullName); + Assert.IsTrue(directory.IsDirectory); + Assert.IsFalse(directory.IsRegularFile); + } + } + + [TestMethod] + [TestCategory("Sftp")] + [ExpectedException(typeof(SftpPathNotFoundException))] + public void Test_Get_Invalid_Directory() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + sftp.Get("/xyz"); + } + } + + [TestMethod] + [TestCategory("Sftp")] + public void Test_Get_File() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + sftp.UploadFile(new MemoryStream(), "abc.txt"); + + var file = sftp.Get("abc.txt"); + + Assert.AreEqual("/home/sshnet/abc.txt", file.FullName); + Assert.IsTrue(file.IsRegularFile); + Assert.IsFalse(file.IsDirectory); + } + } + + [TestMethod] + [TestCategory("Sftp")] + [Description("Test passing null to Get.")] + [ExpectedException(typeof(ArgumentNullException))] + public void Test_Get_File_Null() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + var file = sftp.Get(null); + + sftp.Disconnect(); + } + } + + [TestMethod] + [TestCategory("Sftp")] + public void Test_Get_International_File() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + sftp.UploadFile(new MemoryStream(), "test-眉枚盲-"); + + var file = sftp.Get("test-眉枚盲-"); + + Assert.AreEqual("/home/sshnet/test-眉枚盲-", file.FullName); + Assert.IsTrue(file.IsRegularFile); + Assert.IsFalse(file.IsDirectory); + } + } + + [TestMethod] + [TestCategory("Sftp")] + public void Test_Sftp_SftpFile_MoveTo() + { + using (var sftp = new SftpClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + sftp.Connect(); + + string uploadedFileName = Path.GetTempFileName(); + string remoteFileName = Path.GetRandomFileName(); + string newFileName = Path.GetRandomFileName(); + + CreateTestFile(uploadedFileName, 1); + + using (var file = File.OpenRead(uploadedFileName)) + { + sftp.UploadFile(file, remoteFileName); + } + + var sftpFile = sftp.Get(remoteFileName); + + sftpFile.MoveTo(newFileName); + + Assert.AreEqual(newFileName, sftpFile.Name); + + sftp.Disconnect(); + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs new file mode 100644 index 000000000..d852a093a --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs @@ -0,0 +1,545 @@ +锘縰sing System.Diagnostics; + +using Renci.SshNet.Common; + +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests +{ + /// + /// Represents SSH command that can be executed. + /// + [TestClass] + public class SshCommandTest : IntegrationTestBase + { + [TestMethod] + public void Test_Run_SingleCommand() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + #region Example SshCommand RunCommand Result + client.Connect(); + + var testValue = Guid.NewGuid().ToString(); + var command = client.RunCommand(string.Format("echo {0}", testValue)); + var result = command.Result; + result = result.Substring(0, result.Length - 1); // Remove \n character returned by command + + client.Disconnect(); + #endregion + + Assert.IsTrue(result.Equals(testValue)); + } + } + + [TestMethod] + public void Test_Execute_SingleCommand() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + #region Example SshCommand CreateCommand Execute + client.Connect(); + + var testValue = Guid.NewGuid().ToString(); + var command = string.Format("echo {0}", testValue); + var cmd = client.CreateCommand(command); + var result = cmd.Execute(); + result = result.Substring(0, result.Length - 1); // Remove \n character returned by command + + client.Disconnect(); + #endregion + + Assert.IsTrue(result.Equals(testValue)); + } + } + + [TestMethod] + public void Test_Execute_OutputStream() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + #region Example SshCommand CreateCommand Execute OutputStream + client.Connect(); + + var cmd = client.CreateCommand("ls -l"); // very long list + var asynch = cmd.BeginExecute(); + + var reader = new StreamReader(cmd.OutputStream); + + while (!asynch.IsCompleted) + { + var result = reader.ReadToEnd(); + if (string.IsNullOrEmpty(result)) + { + continue; + } + + Console.Write(result); + } + + _ = cmd.EndExecute(asynch); + + client.Disconnect(); + #endregion + + Assert.Inconclusive(); + } + } + + [TestMethod] + public void Test_Execute_ExtendedOutputStream() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + #region Example SshCommand CreateCommand Execute ExtendedOutputStream + + client.Connect(); + var cmd = client.CreateCommand("echo 12345; echo 654321 >&2"); + var result = cmd.Execute(); + + Console.Write(result); + + var reader = new StreamReader(cmd.ExtendedOutputStream); + Console.WriteLine("DEBUG:"); + Console.Write(reader.ReadToEnd()); + + client.Disconnect(); + + #endregion + + Assert.Inconclusive(); + } + } + + [TestMethod] + [ExpectedException(typeof(SshOperationTimeoutException))] + public void Test_Execute_Timeout() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + #region Example SshCommand CreateCommand Execute CommandTimeout + client.Connect(); + var cmd = client.CreateCommand("sleep 10s"); + cmd.CommandTimeout = TimeSpan.FromSeconds(5); + cmd.Execute(); + client.Disconnect(); + #endregion + } + } + + [TestMethod] + public void Test_Execute_Infinite_Timeout() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + var cmd = client.CreateCommand("sleep 10s"); + cmd.Execute(); + client.Disconnect(); + } + } + + [TestMethod] + public void Test_Execute_InvalidCommand() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + + var cmd = client.CreateCommand(";"); + cmd.Execute(); + if (string.IsNullOrEmpty(cmd.Error)) + { + Assert.Fail("Operation should fail"); + } + Assert.IsTrue(cmd.ExitStatus > 0); + + client.Disconnect(); + } + } + + [TestMethod] + public void Test_Execute_InvalidCommand_Then_Execute_ValidCommand() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + var cmd = client.CreateCommand(";"); + cmd.Execute(); + if (string.IsNullOrEmpty(cmd.Error)) + { + Assert.Fail("Operation should fail"); + } + Assert.IsTrue(cmd.ExitStatus > 0); + + var result = ExecuteTestCommand(client); + + client.Disconnect(); + + Assert.IsTrue(result); + } + } + + [TestMethod] + public void Test_Execute_Command_with_ExtendedOutput() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + var cmd = client.CreateCommand("echo 12345; echo 654321 >&2"); + cmd.Execute(); + + //var extendedData = Encoding.ASCII.GetString(cmd.ExtendedOutputStream.ToArray()); + var extendedData = new StreamReader(cmd.ExtendedOutputStream, Encoding.ASCII).ReadToEnd(); + client.Disconnect(); + + Assert.AreEqual("12345\n", cmd.Result); + Assert.AreEqual("654321\n", extendedData); + } + } + + [TestMethod] + public void Test_Execute_Command_Reconnect_Execute_Command() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + var result = ExecuteTestCommand(client); + Assert.IsTrue(result); + + client.Disconnect(); + client.Connect(); + result = ExecuteTestCommand(client); + Assert.IsTrue(result); + client.Disconnect(); + } + } + + [TestMethod] + public void Test_Execute_Command_ExitStatus() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + #region Example SshCommand RunCommand ExitStatus + client.Connect(); + + var cmd = client.RunCommand("exit 128"); + + Console.WriteLine(cmd.ExitStatus); + + client.Disconnect(); + #endregion + + Assert.IsTrue(cmd.ExitStatus == 128); + } + } + + [TestMethod] + public void Test_Execute_Command_Asynchronously() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + + var cmd = client.CreateCommand("sleep 5s; echo 'test'"); + var asyncResult = cmd.BeginExecute(null, null); + while (!asyncResult.IsCompleted) + { + Thread.Sleep(100); + } + + cmd.EndExecute(asyncResult); + + Assert.IsTrue(cmd.Result == "test\n"); + + client.Disconnect(); + } + } + + [TestMethod] + public void Test_Execute_Command_Asynchronously_With_Error() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + + var cmd = client.CreateCommand("sleep 5s; ;"); + var asyncResult = cmd.BeginExecute(null, null); + while (!asyncResult.IsCompleted) + { + Thread.Sleep(100); + } + + cmd.EndExecute(asyncResult); + + Assert.IsFalse(string.IsNullOrEmpty(cmd.Error)); + + client.Disconnect(); + } + } + + [TestMethod] + public void Test_Execute_Command_Asynchronously_With_Callback() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + + var callbackCalled = false; + + var cmd = client.CreateCommand("sleep 5s; echo 'test'"); + var asyncResult = cmd.BeginExecute(new AsyncCallback((s) => + { + callbackCalled = true; + }), null); + while (!asyncResult.IsCompleted) + { + Thread.Sleep(100); + } + + cmd.EndExecute(asyncResult); + + Assert.IsTrue(callbackCalled); + + client.Disconnect(); + } + } + + [TestMethod] + public void Test_Execute_Command_Asynchronously_With_Callback_On_Different_Thread() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + + var currentThreadId = Thread.CurrentThread.ManagedThreadId; + int callbackThreadId = 0; + + var cmd = client.CreateCommand("sleep 5s; echo 'test'"); + var asyncResult = cmd.BeginExecute(new AsyncCallback((s) => + { + callbackThreadId = Thread.CurrentThread.ManagedThreadId; + }), null); + while (!asyncResult.IsCompleted) + { + Thread.Sleep(100); + } + + cmd.EndExecute(asyncResult); + + Assert.AreNotEqual(currentThreadId, callbackThreadId); + + client.Disconnect(); + } + } + + /// + /// Tests for Issue 563. + /// + [WorkItem(563), TestMethod] + public void Test_Execute_Command_Same_Object_Different_Commands() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + var cmd = client.CreateCommand("echo 12345"); + cmd.Execute(); + Assert.AreEqual("12345\n", cmd.Result); + cmd.Execute("echo 23456"); + Assert.AreEqual("23456\n", cmd.Result); + client.Disconnect(); + } + } + + [TestMethod] + public void Test_Get_Result_Without_Execution() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + var cmd = client.CreateCommand("ls -l"); + + Assert.IsTrue(string.IsNullOrEmpty(cmd.Result)); + client.Disconnect(); + } + } + + [TestMethod] + public void Test_Get_Error_Without_Execution() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + var cmd = client.CreateCommand("ls -l"); + + Assert.IsTrue(string.IsNullOrEmpty(cmd.Error)); + client.Disconnect(); + } + } + + [WorkItem(703), TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void Test_EndExecute_Before_BeginExecute() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + var cmd = client.CreateCommand("ls -l"); + cmd.EndExecute(null); + client.Disconnect(); + } + } + + /// + ///A test for BeginExecute + /// + [TestMethod()] + public void BeginExecuteTest() + { + string expected = "123\n"; + string result; + + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + #region Example SshCommand CreateCommand BeginExecute IsCompleted EndExecute + + client.Connect(); + + var cmd = client.CreateCommand("sleep 15s;echo 123"); // Perform long running task + + var asynch = cmd.BeginExecute(); + + while (!asynch.IsCompleted) + { + // Waiting for command to complete... + Thread.Sleep(2000); + } + result = cmd.EndExecute(asynch); + client.Disconnect(); + + #endregion + + Assert.IsNotNull(asynch); + Assert.AreEqual(expected, result); + } + } + + [TestMethod] + public void Test_Execute_Invalid_Command() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + #region Example SshCommand CreateCommand Error + + client.Connect(); + + var cmd = client.CreateCommand(";"); + cmd.Execute(); + if (!string.IsNullOrEmpty(cmd.Error)) + { + Console.WriteLine(cmd.Error); + } + + client.Disconnect(); + + #endregion + + Assert.Inconclusive(); + } + } + + [TestMethod] + public void Test_MultipleThread_Example_MultipleConnections() + { + try + { +#region Example SshCommand RunCommand Parallel + Parallel.For(0, 100, + () => + { + var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password); + client.Connect(); + return client; + }, + (int counter, ParallelLoopState pls, SshClient client) => + { + var result = client.RunCommand("echo 123"); + Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); + return client; + }, + (SshClient client) => + { + client.Disconnect(); + client.Dispose(); + } + ); +#endregion + + } + catch (Exception exp) + { + Assert.Fail(exp.ToString()); + } + } + + [TestMethod] + + public void Test_MultipleThread_100_MultipleConnections() + { + try + { + Parallel.For(0, 100, + () => + { + var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password); + client.Connect(); + return client; + }, + (int counter, ParallelLoopState pls, SshClient client) => + { + var result = ExecuteTestCommand(client); + Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); + Assert.IsTrue(result); + return client; + }, + (SshClient client) => + { + client.Disconnect(); + client.Dispose(); + } + ); + } + catch (Exception exp) + { + Assert.Fail(exp.ToString()); + } + } + + [TestMethod] + public void Test_MultipleThread_100_MultipleSessions() + { + using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) + { + client.Connect(); + Parallel.For(0, 100, + (counter) => + { + var result = ExecuteTestCommand(client); + Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); + Assert.IsTrue(result); + } + ); + + client.Disconnect(); + } + } + + private static bool ExecuteTestCommand(SshClient s) + { + var testValue = Guid.NewGuid().ToString(); + var command = string.Format("echo {0}", testValue); + var cmd = s.CreateCommand(command); + var result = cmd.Execute(); + result = result.Substring(0, result.Length - 1); // Remove \n character returned by command + return result.Equals(testValue); + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/TripleDesCipherTest.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/TripleDesCipherTest.cs new file mode 100644 index 000000000..a9195cf5e --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/TripleDesCipherTest.cs @@ -0,0 +1,50 @@ +锘縰sing Renci.SshNet.IntegrationTests.Common; +using Renci.SshNet.Security.Cryptography.Ciphers; +using Renci.SshNet.Security.Cryptography.Ciphers.Modes; +using Renci.SshNet.TestTools.OpenSSH; + +namespace Renci.SshNet.IntegrationTests.OldIntegrationTests +{ + /// + /// Implements 3DES cipher algorithm. + /// + [TestClass] + public class TripleDesCipherTest : IntegrationTestBase + { + private IConnectionInfoFactory _adminConnectionInfoFactory; + private RemoteSshdConfig _remoteSshdConfig; + + [TestInitialize] + public void SetUp() + { + _adminConnectionInfoFactory = new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort); + _remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig(); + } + + [TestCleanup] + public void TearDown() + { + _remoteSshdConfig?.Reset(); + } + + [TestMethod] + [Owner("olegkap")] + [TestCategory("Cipher")] + public void Test_Cipher_TripleDESCBC_Connection() + { + _remoteSshdConfig.AddCipher(Cipher.TripledesCbc) + .Update() + .Restart(); + + var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); + connectionInfo.Encryptions.Clear(); + connectionInfo.Encryptions.Add("3des-cbc", new CipherInfo(192, (key, iv) => { return new TripleDesCipher(key, new CbcCipherMode(iv), null); })); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + client.Disconnect(); + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs b/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs new file mode 100644 index 000000000..83313f4a8 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs @@ -0,0 +1,84 @@ +锘縰sing Renci.SshNet.IntegrationTests.Common; +using Renci.SshNet.TestTools.OpenSSH; + +namespace Renci.SshNet.IntegrationTests +{ + [TestClass] + public class PrivateKeyAuthenticationTests : TestBase + { + private IConnectionInfoFactory _connectionInfoFactory; + private RemoteSshdConfig _remoteSshdConfig; + + [TestInitialize] + public void SetUp() + { + _connectionInfoFactory = new LinuxVMConnectionFactory(SshServerHostName, SshServerPort); + _remoteSshdConfig = new RemoteSshd(new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort)).OpenConfig(); + } + + [TestCleanup] + public void TearDown() + { + _remoteSshdConfig?.Reset(); + } + + [TestMethod] + public void Ecdsa256() + { + _remoteSshdConfig.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.EcdsaSha2Nistp256) + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod("key_ecdsa_256_openssh")); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + } + } + + [TestMethod] + public void Ecdsa384() + { + _remoteSshdConfig.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.EcdsaSha2Nistp384) + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod("key_ecdsa_384_openssh")); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + } + } + + [TestMethod] + public void EcdsaA521() + { + _remoteSshdConfig.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.EcdsaSha2Nistp521) + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod("key_ecdsa_521_openssh")); + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + } + } + + private PrivateKeyAuthenticationMethod CreatePrivateKeyAuthenticationMethod(string keyResource) + { + var privateKey = CreatePrivateKeyFromManifestResource("Renci.SshNet.IntegrationTests.resources.client." + keyResource); + return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKey); + } + + private PrivateKeyFile CreatePrivateKeyFromManifestResource(string resourceName) + { + using (var stream = GetManifestResourceStream(resourceName)) + { + return new PrivateKeyFile(stream); + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/Program.cs b/src/Renci.SshNet.IntegrationTests/Program.cs new file mode 100644 index 000000000..af2b60d51 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/Program.cs @@ -0,0 +1,11 @@ +锘縩amespace Renci.SshNet.IntegrationTests +{ + class Program + { +#if NETFRAMEWORK + private static void Main() + { + } +#endif + } +} diff --git a/src/Renci.SshNet.IntegrationTests/RemoteSshd.cs b/src/Renci.SshNet.IntegrationTests/RemoteSshd.cs new file mode 100644 index 000000000..c81bf96f5 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/RemoteSshd.cs @@ -0,0 +1,246 @@ +锘縰sing Renci.SshNet.TestTools.OpenSSH; + +namespace Renci.SshNet.IntegrationTests +{ + internal class RemoteSshd + { + private readonly IConnectionInfoFactory _connectionInfoFactory; + + public RemoteSshd(IConnectionInfoFactory connectionInfoFactory) + { + _connectionInfoFactory = connectionInfoFactory; + } + + public RemoteSshdConfig OpenConfig() + { + return new RemoteSshdConfig(this, _connectionInfoFactory); + } + + public RemoteSshd Restart() + { + // Restart SSH daemon + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + // Kill all processes that start with 'sshd' and that run as root + var stopCommand = client.CreateCommand("sudo pkill -9 -U 0 sshd.pam"); + var stopOutput = stopCommand.Execute(); + if (stopCommand.ExitStatus != 0) + { + throw new ApplicationException($"Stopping ssh service failed with exit code {stopCommand.ExitStatus}.\r\n{stopOutput}\r\n{stopCommand.Error}"); + } + + var resetFailedCommand = client.CreateCommand("sudo /usr/sbin/sshd.pam"); + var resetFailedOutput = resetFailedCommand.Execute(); + if (resetFailedCommand.ExitStatus != 0) + { + throw new ApplicationException($"Reset failures for ssh service failed with exit code {resetFailedCommand.ExitStatus}.\r\n{resetFailedOutput}\r\n{resetFailedCommand.Error}"); + } + } + + return this; + } + } + + internal class RemoteSshdConfig + { + private const string SshdConfigFilePath = "/etc/ssh/sshd_config"; + private static readonly Encoding Utf8NoBom = new UTF8Encoding(false, true); + + private readonly RemoteSshd _remoteSshd; + private readonly IConnectionInfoFactory _connectionInfoFactory; + private readonly SshdConfig _config; + + public RemoteSshdConfig(RemoteSshd remoteSshd, IConnectionInfoFactory connectionInfoFactory) + { + _remoteSshd = remoteSshd; + _connectionInfoFactory = connectionInfoFactory; + + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var memoryStream = new MemoryStream()) + { + client.Download(SshdConfigFilePath, memoryStream); + + memoryStream.Position = 0; + _config = SshdConfig.LoadFrom(memoryStream, Encoding.UTF8); + } + } + } + + /// + /// Specifies whether challenge-response authentication is allowed. + /// + /// to allow challenge-response authentication. + /// + /// The current instance. + /// + public RemoteSshdConfig WithChallengeResponseAuthentication(bool? value) + { + _config.ChallengeResponseAuthentication = value; + return this; + } + + /// + /// Specifies whether to allow keyboard-interactive authentication. + /// + /// to allow keyboard-interactive authentication. + /// + /// The current instance. + /// + public RemoteSshdConfig WithKeyboardInteractiveAuthentication(bool value) + { + _config.KeyboardInteractiveAuthentication = value; + return this; + } + + /// + /// Specifies whether sshd should print /etc/motd when a user logs in interactively. + /// + /// if sshd should print /etc/motd when a user logs in interactively. + /// + /// The current instance. + /// + public RemoteSshdConfig PrintMotd(bool? value = true) + { + _config.PrintMotd = value; + return this; + } + + /// + /// Specifies whether TCP forwarding is permitted. + /// + /// to allow TCP forwarding. + /// + /// The current instance. + /// + public RemoteSshdConfig AllowTcpForwarding(bool? value = true) + { + _config.AllowTcpForwarding = value; + return this; + } + + public RemoteSshdConfig WithAuthenticationMethods(string user, string authenticationMethods) + { + var sshNetMatch = _config.Matches.FirstOrDefault(m => m.Users.Contains(user)); + if (sshNetMatch == null) + { + sshNetMatch = new Match(new[] { user }, new string[0]); + _config.Matches.Add(sshNetMatch); + } + + sshNetMatch.AuthenticationMethods = authenticationMethods; + + return this; + } + + public RemoteSshdConfig ClearCiphers() + { + _config.Ciphers.Clear(); + return this; + } + + public RemoteSshdConfig AddCipher(Cipher cipher) + { + _config.Ciphers.Add(cipher); + return this; + } + + public RemoteSshdConfig ClearKeyExchangeAlgorithms() + { + _config.KeyExchangeAlgorithms.Clear(); + return this; + } + + public RemoteSshdConfig AddKeyExchangeAlgorithm(KeyExchangeAlgorithm keyExchangeAlgorithm) + { + _config.KeyExchangeAlgorithms.Add(keyExchangeAlgorithm); + return this; + } + + public RemoteSshdConfig ClearPublicKeyAcceptedAlgorithms() + { + _config.PublicKeyAcceptedAlgorithms.Clear(); + return this; + } + + public RemoteSshdConfig AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm publicKeyAlgorithm) + { + _config.PublicKeyAcceptedAlgorithms.Add(publicKeyAlgorithm); + return this; + } + + public RemoteSshdConfig ClearHostKeyAlgorithms() + { + _config.HostKeyAlgorithms.Clear(); + return this; + } + + public RemoteSshdConfig AddHostKeyAlgorithm(HostKeyAlgorithm hostKeyAlgorithm) + { + _config.HostKeyAlgorithms.Add(hostKeyAlgorithm); + return this; + } + + public RemoteSshdConfig ClearSubsystems() + { + _config.Subsystems.Clear(); + return this; + } + + public RemoteSshdConfig AddSubsystem(Subsystem subsystem) + { + _config.Subsystems.Add(subsystem); + return this; + } + + public RemoteSshdConfig WithLogLevel(LogLevel logLevel) + { + _config.LogLevel = logLevel; + return this; + } + + public RemoteSshdConfig WithUsePAM(bool usePAM) + { + _config.UsePAM = usePAM; + return this; + } + + public RemoteSshdConfig ClearHostKeyFiles() + { + _config.HostKeyFiles.Clear(); + return this; + } + + public RemoteSshdConfig AddHostKeyFile(string hostKeyFile) + { + _config.HostKeyFiles.Add(hostKeyFile); + return this; + } + + public RemoteSshd Update() + { + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var memoryStream = new MemoryStream()) + using (var sw = new StreamWriter(memoryStream, Utf8NoBom)) + { + sw.NewLine = "\n"; + _config.SaveTo(sw); + sw.Flush(); + + memoryStream.Position = 0; + + client.Upload(memoryStream, SshdConfigFilePath); + } + } + + return _remoteSshd; + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/IntegrationTests.csproj b/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj similarity index 65% rename from src/Renci.SshNet.IntegrationTests/IntegrationTests.csproj rename to src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj index 2fdbcfd74..ae3505f10 100644 --- a/src/Renci.SshNet.IntegrationTests/IntegrationTests.csproj +++ b/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj @@ -3,7 +3,6 @@ net7.0 enable - enable false true @@ -16,16 +15,21 @@ We can stop producing XML docs for test projects (and remove the NoWarn for CS1591) once the following issue is fixed: https://github.com/dotnet/roslyn/issues/41640. --> - $(NoWarn);CS1591 + $(NoWarn);CS1591;SYSLIB0021;SYSLIB1045;SYSLIB0014;IDE0220;IDE0010 + + TRACE;FEATURE_MSTEST_DATATEST;FEATURE_SOCKET_EAP;FEATURE_ENCODING_ASCII;FEATURE_THREAD_SLEEP;FEATURE_THREAD_THREADPOOL + + - + + - + runtime; build; native; contentfiles; analyzers; buildtransitive @@ -44,7 +48,18 @@ + - + + + + + + + + + + + diff --git a/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs b/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs index 5db1fe51c..fc90554a5 100644 --- a/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs +++ b/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs @@ -1,6 +1,4 @@ -using Renci.SshNet; - -namespace IntegrationTests +namespace Renci.SshNet.IntegrationTests { /// /// The SCP client integration tests diff --git a/src/Renci.SshNet.IntegrationTests/ScpTests.cs b/src/Renci.SshNet.IntegrationTests/ScpTests.cs new file mode 100644 index 000000000..2fd4ea0ce --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/ScpTests.cs @@ -0,0 +1,2379 @@ +锘縰sing Renci.SshNet.Common; + +namespace Renci.SshNet.IntegrationTests +{ + // TODO SCP: UPLOAD / DOWNLOAD ZERO LENGTH FILES + // TODO SCP: UPLOAD / DOWNLOAD EMPTY DIRECTORY + // TODO SCP: UPLOAD DIRECTORY THAT ALREADY EXISTS ON REMOTE HOST + + [TestClass] + public class ScpTests : TestBase + { + private IConnectionInfoFactory _connectionInfoFactory; + private IRemotePathTransformation _remotePathTransformation; + + [TestInitialize] + public void SetUp() + { + _connectionInfoFactory = new LinuxVMConnectionFactory(SshServerHostName, SshServerPort); + _remotePathTransformation = RemotePathTransformation.ShellQuote; + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpDownloadStreamDirectoryDoesNotExistData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Download_Stream_DirectoryDoesNotExist() + { + foreach (var data in GetScpDownloadStreamDirectoryDoesNotExistData()) + { + Scp_Download_Stream_DirectoryDoesNotExist((IRemotePathTransformation) data[0], + (string) data[1], + (string) data[2]); + } + } +#endif + public void Scp_Download_Stream_DirectoryDoesNotExist(IRemotePathTransformation remotePathTransformation, + string remotePath, + string remoteFile) + { + var completeRemotePath = CombinePaths(remotePath, remoteFile); + + // remove complete directory if it's not the home directory of the user + // or else remove the remote file + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + + try + { + using (var downloaded = new MemoryStream()) + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + try + { + client.Download(completeRemotePath, downloaded); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {completeRemotePath}: No such file or directory", ex.Message); + } + } + } + finally + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpDownloadStreamFileDoesNotExistData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Download_Stream_FileDoesNotExist() + { + foreach (var data in GetScpDownloadStreamFileDoesNotExistData()) + { + Scp_Download_Stream_FileDoesNotExist((IRemotePathTransformation)data[0], + (string)data[1], + (string)data[2]); + } + } +#endif + public void Scp_Download_Stream_FileDoesNotExist(IRemotePathTransformation remotePathTransformation, + string remotePath, + string remoteFile) + { + var completeRemotePath = CombinePaths(remotePath, remoteFile); + + // remove complete directory if it's not the home directory of the user + // or else remove the remote file + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + + client.CreateDirectory(remotePath); + } + } + + try + { + using (var downloaded = new MemoryStream()) + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + try + { + client.Download(completeRemotePath, downloaded); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {completeRemotePath}: No such file or directory", ex.Message); + } + } + } + finally + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpDownloadDirectoryInfoDirectoryDoesNotExistData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Download_DirectoryInfo_DirectoryDoesNotExist() + { + foreach (var data in GetScpDownloadDirectoryInfoDirectoryDoesNotExistData()) + { + Scp_Download_DirectoryInfo_DirectoryDoesNotExist((IRemotePathTransformation)data[0], + (string)data[1]); + } + } +#endif + public void Scp_Download_DirectoryInfo_DirectoryDoesNotExist(IRemotePathTransformation remotePathTransformation, + string remotePath) + { + var localDirectory = Path.GetTempFileName(); + File.Delete(localDirectory); + Directory.CreateDirectory(localDirectory); + + try + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + try + { + client.Download(remotePath, new DirectoryInfo(localDirectory)); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {remotePath}: No such file or directory", ex.Message); + } + } + } + finally + { + Directory.Delete(localDirectory, true); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpDownloadDirectoryInfoExistingFileData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Download_DirectoryInfo_ExistingFile() + { + foreach (var data in GetScpDownloadDirectoryInfoExistingFileData()) + { + Scp_Download_DirectoryInfo_ExistingFile((IRemotePathTransformation)data[0], + (string)data[1]); + } + } +#endif + public void Scp_Download_DirectoryInfo_ExistingFile(IRemotePathTransformation remotePathTransformation, + string remotePath) + { + var content = CreateMemoryStream(100); + content.Position = 0; + + var localDirectory = Path.GetTempFileName(); + File.Delete(localDirectory); + Directory.CreateDirectory(localDirectory); + + var localFile = Path.Combine(localDirectory, PosixPath.GetFileName(remotePath)); + + try + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.UploadFile(content, remotePath); + } + + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + client.Download(remotePath, new DirectoryInfo(localDirectory)); + } + + Assert.IsTrue(File.Exists(localFile)); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remotePath, downloaded); + downloaded.Position = 0; + Assert.AreEqual(CreateFileHash(localFile), CreateHash(downloaded)); + } + } + } + finally + { + Directory.Delete(localDirectory, true); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remotePath)) + { + client.DeleteFile(remotePath); + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpDownloadDirectoryInfoExistingDirectoryData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Download_DirectoryInfo_ExistingDirectory() + { + foreach (var data in GetScpDownloadDirectoryInfoExistingDirectoryData()) + { + Scp_Download_DirectoryInfo_ExistingDirectory((IRemotePathTransformation)data[0], + (string)data[1]); + } + } +#endif + public void Scp_Download_DirectoryInfo_ExistingDirectory(IRemotePathTransformation remotePathTransformation, + string remotePath) + { + var localDirectory = Path.GetTempFileName(); + File.Delete(localDirectory); + Directory.CreateDirectory(localDirectory); + + var localPathFile1 = Path.Combine(localDirectory, "file1 23"); + var remotePathFile1 = CombinePaths(remotePath, "file1 23"); + var contentFile1 = CreateMemoryStream(1024); + contentFile1.Position = 0; + + var localPathFile2 = Path.Combine(localDirectory, "file2 #$%"); + var remotePathFile2 = CombinePaths(remotePath, "file2 #$%"); + var contentFile2 = CreateMemoryStream(2048); + contentFile2.Position = 0; + + var localPathSubDirectory = Path.Combine(localDirectory, "subdir $1%#"); + var remotePathSubDirectory = CombinePaths(remotePath, "subdir $1%#"); + + var localPathFile3 = Path.Combine(localPathSubDirectory, "file3 %$#"); + var remotePathFile3 = CombinePaths(remotePathSubDirectory, "file3 %$#"); + var contentFile3 = CreateMemoryStream(256); + contentFile3.Position = 0; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remotePathFile1)) + { + client.DeleteFile(remotePathFile1); + } + + if (client.Exists(remotePathFile2)) + { + client.DeleteFile(remotePathFile2); + } + + if (client.Exists(remotePathFile3)) + { + client.DeleteFile(remotePathFile3); + } + + if (client.Exists(remotePathSubDirectory)) + { + client.DeleteDirectory(remotePathSubDirectory); + } + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + + try + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (!client.Exists(remotePath)) + { + client.CreateDirectory(remotePath); + } + + client.UploadFile(contentFile1, remotePathFile1); + client.UploadFile(contentFile1, remotePathFile2); + + client.CreateDirectory(remotePathSubDirectory); + client.UploadFile(contentFile3, remotePathFile3); + } + + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + client.Download(remotePath, new DirectoryInfo(localDirectory)); + } + + var localFiles = Directory.GetFiles(localDirectory); + Assert.AreEqual(2, localFiles.Length); + Assert.IsTrue(localFiles.Contains(localPathFile1)); + Assert.IsTrue(localFiles.Contains(localPathFile2)); + + var localSubDirecties = Directory.GetDirectories(localDirectory); + Assert.AreEqual(1, localSubDirecties.Length); + Assert.AreEqual(localPathSubDirectory, localSubDirecties[0]); + + var localFilesSubDirectory = Directory.GetFiles(localPathSubDirectory); + Assert.AreEqual(1, localFilesSubDirectory.Length); + Assert.AreEqual(localPathFile3, localFilesSubDirectory[0]); + + Assert.AreEqual(0, Directory.GetDirectories(localPathSubDirectory).Length); + } + finally + { + Directory.Delete(localDirectory, true); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remotePathFile1)) + { + client.DeleteFile(remotePathFile1); + } + + if (client.Exists(remotePathFile2)) + { + client.DeleteFile(remotePathFile2); + } + + if (client.Exists(remotePathFile3)) + { + client.DeleteFile(remotePathFile3); + } + + if (client.Exists(remotePathSubDirectory)) + { + client.DeleteDirectory(remotePathSubDirectory); + } + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpDownloadFileInfoDirectoryDoesNotExistData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Download_FileInfo_DirectoryDoesNotExist() + { + foreach (var data in GetScpDownloadFileInfoDirectoryDoesNotExistData()) + { + Scp_Download_FileInfo_DirectoryDoesNotExist((IRemotePathTransformation)data[0], + (string)data[1], + (string)data[2]); + } + } +#endif + public void Scp_Download_FileInfo_DirectoryDoesNotExist(IRemotePathTransformation remotePathTransformation, + string remotePath, + string remoteFile) + { + var completeRemotePath = CombinePaths(remotePath, remoteFile); + + // remove complete directory if it's not the home directory of the user + // or else remove the remote file + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + + var fileInfo = new FileInfo(Path.GetTempFileName()); + + try + { + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + try + { + client.Download(completeRemotePath, fileInfo); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {completeRemotePath}: No such file or directory", ex.Message); + } + } + } + finally + { + fileInfo.Delete(); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpDownloadFileInfoFileDoesNotExistData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Download_FileInfo_FileDoesNotExist() + { + foreach (var data in GetScpDownloadFileInfoFileDoesNotExistData()) + { + Scp_Download_FileInfo_FileDoesNotExist((IRemotePathTransformation)data[0], + (string)data[1], + (string)data[2]); + } + } +#endif + public void Scp_Download_FileInfo_FileDoesNotExist(IRemotePathTransformation remotePathTransformation, + string remotePath, + string remoteFile) + { + var completeRemotePath = CombinePaths(remotePath, remoteFile); + + // remove complete directory if it's not the home directory of the user + // or else remove the remote file + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + + client.CreateDirectory(remotePath); + } + } + + var fileInfo = new FileInfo(Path.GetTempFileName()); + + try + { + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + try + { + client.Download(completeRemotePath, fileInfo); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {completeRemotePath}: No such file or directory", ex.Message); + } + } + } + finally + { + fileInfo.Delete(); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpDownloadFileInfoExistingDirectoryData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Download_FileInfo_ExistingDirectory() + { + foreach (var data in GetScpDownloadFileInfoExistingDirectoryData()) + { + Scp_Download_FileInfo_ExistingDirectory((IRemotePathTransformation)data[0], + (string)data[1]); + } + } +#endif + public void Scp_Download_FileInfo_ExistingDirectory(IRemotePathTransformation remotePathTransformation, + string remotePath) + { + // remove complete directory if it's not the home directory of the user + // or else remove the remote file + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + + client.CreateDirectory(remotePath); + } + } + + var fileInfo = new FileInfo(Path.GetTempFileName()); + fileInfo.Delete(); + + try + { + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + try + { + client.Download(remotePath, fileInfo); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {remotePath}: not a regular file", ex.Message); + } + + Assert.IsFalse(fileInfo.Exists); + } + } + finally + { + fileInfo.Delete(); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpDownloadFileInfoExistingFileData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Download_FileInfo_ExistingFile() + { + foreach (var data in GetScpDownloadFileInfoExistingFileData()) + { + Scp_Download_FileInfo_ExistingFile((IRemotePathTransformation)data[0], + (string)data[1], + (string)data[2], + (int)data[3]); + } + } +#endif + public void Scp_Download_FileInfo_ExistingFile(IRemotePathTransformation remotePathTransformation, + string remotePath, + string remoteFile, + int size) + { + var completeRemotePath = CombinePaths(remotePath, remoteFile); + + // remove complete directory if it's not the home directory of the user + // or else remove the remote file + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + + client.CreateDirectory(remotePath); + } + } + + var fileInfo = new FileInfo(Path.GetTempFileName()); + + try + { + var content = CreateMemoryStream(size); + content.Position = 0; + + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + client.Upload(content, completeRemotePath); + } + + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + client.Download(completeRemotePath, fileInfo); + } + + using (var fs = fileInfo.OpenRead()) + { + var downloadedBytes = new byte[fs.Length]; + Assert.AreEqual(downloadedBytes.Length, fs.Read(downloadedBytes, 0, downloadedBytes.Length)); + content.Position = 0; + Assert.AreEqual(CreateHash(content), CreateHash(downloadedBytes)); + } + } + finally + { + fileInfo.Delete(); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpDownloadStreamExistingDirectoryData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Download_Stream_ExistingDirectory() + { + foreach (var data in GetScpDownloadStreamExistingDirectoryData()) + { + Scp_Download_Stream_ExistingDirectory((IRemotePathTransformation)data[0], + (string)data[1]); + } + } +#endif + public void Scp_Download_Stream_ExistingDirectory(IRemotePathTransformation remotePathTransformation, + string remotePath) + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + + client.CreateDirectory(remotePath); + } + } + + var file = Path.GetTempFileName(); + File.Delete(file); + + try + { + using (var fs = File.OpenWrite(file)) + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + try + { + client.Download(remotePath, fs); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {remotePath}: not a regular file", ex.Message); + } + + Assert.AreEqual(0, fs.Length); + } + } + finally + { + File.Delete(file); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpDownloadStreamExistingFileData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Download_Stream_ExistingFile() + { + foreach (var data in GetScpDownloadStreamExistingFileData()) + { + Scp_Download_Stream_ExistingFile((IRemotePathTransformation)data[0], + (string)data[1], + (string)data[2], + (int)data[3]); + } + } +#endif + public void Scp_Download_Stream_ExistingFile(IRemotePathTransformation remotePathTransformation, + string remotePath, + string remoteFile, + int size) + { + var completeRemotePath = CombinePaths(remotePath, remoteFile); + + // remove complete directory if it's not the home directory of the user + // or else remove the remote file + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + + client.CreateDirectory(remotePath); + } + } + + var file = CreateTempFile(size); + + try + { + using (var fs = File.OpenRead(file)) + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + client.Upload(fs, completeRemotePath); + } + + using (var fs = File.OpenRead(file)) + using (var downloaded = new MemoryStream(size)) + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + client.Download(completeRemotePath, downloaded); + downloaded.Position = 0; + Assert.AreEqual(CreateHash(fs), CreateHash(downloaded)); + } + } + finally + { + File.Delete(file); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpUploadFileStreamDirectoryDoesNotExistData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Upload_FileStream_DirectoryDoesNotExist() + { + foreach (var data in GetScpUploadFileStreamDirectoryDoesNotExistData()) + { + Scp_Upload_FileStream_DirectoryDoesNotExist((IRemotePathTransformation)data[0], + (string)data[1], + (string)data[2]); + } + } +#endif + public void Scp_Upload_FileStream_DirectoryDoesNotExist(IRemotePathTransformation remotePathTransformation, + string remotePath, + string remoteFile) + { + var completeRemotePath = CombinePaths(remotePath, remoteFile); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + + var file = CreateTempFile(1000); + + try + { + using (var fs = File.OpenRead(file)) + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + try + { + client.Upload(fs, completeRemotePath); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {remotePath}: No such file or directory", ex.Message); + } + } + } + finally + { + File.Delete(file); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpUploadFileStreamExistingDirectoryData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Upload_FileStream_ExistingDirectory() + { + foreach (var data in GetScpUploadFileStreamExistingDirectoryData()) + { + Scp_Upload_FileStream_ExistingDirectory((IRemotePathTransformation)data[0], + (string)data[1]); + } + } +#endif + public void Scp_Upload_FileStream_ExistingDirectory(IRemotePathTransformation remotePathTransformation, + string remoteFile) + { + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var command = client.CreateCommand("rm -Rf " + _remotePathTransformation.Transform(remoteFile))) + { + command.Execute(); + } + } + + var file = CreateTempFile(1000); + + try + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.CreateDirectory(remoteFile); + } + + using (var fs = File.OpenRead(file)) + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + try + { + client.Upload(fs, remoteFile); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {remoteFile}: Is a directory", ex.Message); + } + } + } + finally + { + File.Delete(file); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteDirectory(remoteFile); + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(ScpUploadFileStreamExistingFileData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Upload_FileStream_ExistingFile() + { + foreach (var data in ScpUploadFileStreamExistingFileData()) + { + Scp_Upload_FileStream_ExistingFile((IRemotePathTransformation)data[0], + (string)data[1]); + } + } +#endif + public void Scp_Upload_FileStream_ExistingFile(IRemotePathTransformation remotePathTransformation, + string remoteFile) + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + + // original content is bigger than new content to ensure file is fully overwritten + var originalContent = CreateMemoryStream(2000); + var file = CreateTempFile(1000); + + try + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + originalContent.Position = 0; + client.UploadFile(originalContent, remoteFile); + } + + using (var fs = File.OpenRead(file)) + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + client.Upload(fs, remoteFile); + } + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var downloaded = new MemoryStream(1000)) + { + client.DownloadFile(remoteFile, downloaded); + downloaded.Position = 0; + Assert.AreEqual(CreateFileHash(file), CreateHash(downloaded)); + } + } + } + finally + { + File.Delete(file); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpUploadFileStreamFileDoesNotExistData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Upload_FileStream_FileDoesNotExist() + { + foreach (var data in GetScpUploadFileStreamFileDoesNotExistData()) + { + Scp_Upload_FileStream_FileDoesNotExist((IRemotePathTransformation)data[0], + (string)data[1], + (string)data[2], + (int)data[3]); + } + } +#endif + public void Scp_Upload_FileStream_FileDoesNotExist(IRemotePathTransformation remotePathTransformation, + string remotePath, + string remoteFile, + int size) + { + var completeRemotePath = CombinePaths(remotePath, remoteFile); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + // remove complete directory if it's not the home directory of the user + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + + var file = CreateTempFile(size); + + try + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + // create directory if it's not the home directory of the user + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (!client.Exists((remotePath))) + { + client.CreateDirectory(remotePath); + } + } + } + + using (var fs = File.OpenRead(file)) + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + client.Upload(fs, completeRemotePath); + } + + using (var fs = File.OpenRead(file)) + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var sftpFile = client.Get(completeRemotePath); + Assert.AreEqual(GetAbsoluteRemotePath(client, remotePath, remoteFile), sftpFile.FullName); + Assert.AreEqual(size, sftpFile.Length); + + var downloaded = client.ReadAllBytes(completeRemotePath); + Assert.AreEqual(CreateHash(fs), CreateHash(downloaded)); + } + } + finally + { + File.Delete(file); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + // remove complete directory if it's not the home directory of the user + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + } + + /// + /// https://github.com/sshnet/SSH.NET/issues/289 + /// +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpUploadFileInfoDirectoryDoesNotExistData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Upload_FileInfo_DirectoryDoesNotExist() + { + foreach (var data in GetScpUploadFileInfoDirectoryDoesNotExistData()) + { + Scp_Upload_FileInfo_DirectoryDoesNotExist((IRemotePathTransformation)data[0], + (string)data[1], + (string)data[2]); + } + } +#endif + public void Scp_Upload_FileInfo_DirectoryDoesNotExist(IRemotePathTransformation remotePathTransformation, + string remotePath, + string remoteFile) + { + var completeRemotePath = CombinePaths(remotePath, remoteFile); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + + var file = CreateTempFile(1000); + + try + { + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + try + { + client.Upload(new FileInfo(file), completeRemotePath); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {remotePath}: No such file or directory", ex.Message); + } + } + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + Assert.IsFalse(client.Exists(completeRemotePath)); + Assert.IsFalse(client.Exists(remotePath)); + } + } + finally + { + File.Delete(file); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + + /// + /// https://github.com/sshnet/SSH.NET/issues/286 + /// +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpUploadFileInfoExistingDirectoryData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Upload_FileInfo_ExistingDirectory() + { + foreach (var data in GetScpUploadFileInfoExistingDirectoryData()) + { + Scp_Upload_FileInfo_ExistingDirectory((IRemotePathTransformation)data[0], + (string)data[1]); + } + } +#endif + public void Scp_Upload_FileInfo_ExistingDirectory(IRemotePathTransformation remotePathTransformation, + string remoteFile) + { + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var command = client.CreateCommand("rm -Rf " + _remotePathTransformation.Transform(remoteFile))) + { + command.Execute(); + } + } + + var file = CreateTempFile(1000); + + try + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.CreateDirectory(remoteFile); + } + + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + try + { + client.Upload(new FileInfo(file), remoteFile); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {remoteFile}: Is a directory", ex.Message); + } + } + } + finally + { + File.Delete(file); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var command = client.CreateCommand("rm -Rf " + _remotePathTransformation.Transform(remoteFile))) + { + command.Execute(); + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpUploadFileInfoExistingFileData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Upload_FileInfo_ExistingFile() + { + foreach (var data in GetScpUploadFileInfoExistingFileData()) + { + Scp_Upload_FileInfo_ExistingFile((IRemotePathTransformation)data[0], + (string)data[1]); + } + } +#endif + public void Scp_Upload_FileInfo_ExistingFile(IRemotePathTransformation remotePathTransformation, + string remoteFile) + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + + // original content is bigger than new content to ensure file is fully overwritten + var originalContent = CreateMemoryStream(2000); + var file = CreateTempFile(1000); + + try + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + originalContent.Position = 0; + client.UploadFile(originalContent, remoteFile); + } + + var fileInfo = new FileInfo(file) + { + LastAccessTimeUtc = new DateTime(1973, 8, 13, 20, 15, 33, DateTimeKind.Utc), + LastWriteTimeUtc = new DateTime(1974, 1, 24, 3, 55, 12, DateTimeKind.Utc) + }; + + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + client.Upload(fileInfo, remoteFile); + } + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var uploadedFile = client.Get(remoteFile); + Assert.AreEqual(fileInfo.LastAccessTimeUtc, uploadedFile.LastAccessTimeUtc); + Assert.AreEqual(fileInfo.LastWriteTimeUtc, uploadedFile.LastWriteTimeUtc); + + using (var downloaded = new MemoryStream(1000)) + { + client.DownloadFile(remoteFile, downloaded); + downloaded.Position = 0; + Assert.AreEqual(CreateFileHash(file), CreateHash(downloaded)); + } + } + } + finally + { + File.Delete(file); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpUploadFileInfoFileDoesNotExistData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Upload_FileInfo_FileDoesNotExist() + { + foreach (var data in GetScpUploadFileInfoFileDoesNotExistData()) + { + Scp_Upload_FileInfo_FileDoesNotExist((IRemotePathTransformation)data[0], + (string)data[1], + (string)data[2], + (int)data[3]); + } + } +#endif + public void Scp_Upload_FileInfo_FileDoesNotExist(IRemotePathTransformation remotePathTransformation, + string remotePath, + string remoteFile, + int size) + { + var completeRemotePath = CombinePaths(remotePath, remoteFile); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.DeleteFile(completeRemotePath); + } + + // remove complete directory if it's not the home directory of the user + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + + var file = CreateTempFile(size); + + try + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + // create directory if it's not the home directory of the user + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (!client.Exists(remotePath)) + { + client.CreateDirectory(remotePath); + } + } + } + + var fileInfo = new FileInfo(file) + { + LastAccessTimeUtc = new DateTime(1973, 8, 13, 20, 15, 33, DateTimeKind.Utc), + LastWriteTimeUtc = new DateTime(1974, 1, 24, 3, 55, 12, DateTimeKind.Utc) + }; + + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + client.Upload(fileInfo, completeRemotePath); + } + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var uploadedFile = client.Get(completeRemotePath); + Assert.AreEqual(fileInfo.LastAccessTimeUtc, uploadedFile.LastAccessTimeUtc); + Assert.AreEqual(fileInfo.LastWriteTimeUtc, uploadedFile.LastWriteTimeUtc); + Assert.AreEqual(size, uploadedFile.Length); + + using (var downloaded = new MemoryStream(size)) + { + client.DownloadFile(completeRemotePath, downloaded); + downloaded.Position = 0; + Assert.AreEqual(CreateFileHash(file), CreateHash(downloaded)); + } + } + } + finally + { + File.Delete(file); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(completeRemotePath)) + { + client.Delete(completeRemotePath); + } + + // remove complete directory if it's not the home directory of the user + if (remotePath.Length > 0 && remotePath != client.WorkingDirectory) + { + if (client.Exists(remotePath)) + { + client.DeleteDirectory(remotePath); + } + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpUploadDirectoryInfoDirectoryDoesNotExistData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Upload_DirectoryInfo_DirectoryDoesNotExist() + { + foreach (var data in GetScpUploadDirectoryInfoDirectoryDoesNotExistData()) + { + Scp_Upload_DirectoryInfo_DirectoryDoesNotExist((IRemotePathTransformation)data[0], + (string)data[1]); + } + } +#endif + public void Scp_Upload_DirectoryInfo_DirectoryDoesNotExist(IRemotePathTransformation remotePathTransformation, + string remoteDirectory) + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists((remoteDirectory))) + { + client.DeleteDirectory(remoteDirectory); + } + } + + var localDirectory = Path.GetTempFileName(); + File.Delete(localDirectory); + Directory.CreateDirectory(localDirectory); + + try + { + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + try + { + client.Upload(new DirectoryInfo(localDirectory), remoteDirectory); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {remoteDirectory}: No such file or directory", ex.Message); + } + } + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + Assert.IsFalse(client.Exists(remoteDirectory)); + } + } + finally + { + Directory.Delete(localDirectory, true); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists((remoteDirectory))) + { + client.DeleteDirectory(remoteDirectory); + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpUploadDirectoryInfoExistingDirectoryData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Upload_DirectoryInfo_ExistingDirectory() + { + foreach (var data in GetScpUploadDirectoryInfoExistingDirectoryData()) + { + Scp_Upload_DirectoryInfo_ExistingDirectory((IRemotePathTransformation)data[0], + (string)data[1]); + } + } +#endif + public void Scp_Upload_DirectoryInfo_ExistingDirectory(IRemotePathTransformation remotePathTransformation, + string remoteDirectory) + { + string absoluteRemoteDirectory = GetAbsoluteRemotePath(_connectionInfoFactory, remoteDirectory); + + var remotePathFile1 = CombinePaths(remoteDirectory, "file1"); + var remotePathFile2 = CombinePaths(remoteDirectory, "file2"); + + var absoluteremoteSubDirectory1 = CombinePaths(absoluteRemoteDirectory, "sub1"); + var remoteSubDirectory1 = CombinePaths(remoteDirectory, "sub1"); + var remotePathSubFile1 = CombinePaths(remoteSubDirectory1, "file1"); + var remotePathSubFile2 = CombinePaths(remoteSubDirectory1, "file2"); + var absoluteremoteSubDirectory2 = CombinePaths(absoluteRemoteDirectory, "sub2"); + var remoteSubDirectory2 = CombinePaths(remoteDirectory, "sub2"); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remotePathSubFile1)) + { + client.DeleteFile(remotePathSubFile1); + } + if (client.Exists(remotePathSubFile2)) + { + client.DeleteFile(remotePathSubFile2); + } + if (client.Exists(remoteSubDirectory1)) + { + client.DeleteDirectory(remoteSubDirectory1); + } + if (client.Exists(remoteSubDirectory2)) + { + client.DeleteDirectory(remoteSubDirectory2); + } + if (client.Exists(remotePathFile1)) + { + client.DeleteFile(remotePathFile1); + } + if (client.Exists(remotePathFile2)) + { + client.DeleteFile(remotePathFile2); + } + + if (remoteDirectory.Length > 0 && remoteDirectory != "." && remoteDirectory != client.WorkingDirectory) + { + if (client.Exists(remoteDirectory)) + { + client.DeleteDirectory(remoteDirectory); + } + + client.CreateDirectory(remoteDirectory); + } + } + + var localDirectory = Path.GetTempFileName(); + File.Delete(localDirectory); + Directory.CreateDirectory(localDirectory); + + var localPathFile1 = Path.Combine(localDirectory, "file1"); + var localPathFile2 = Path.Combine(localDirectory, "file2"); + + var localSubDirectory1 = Path.Combine(localDirectory, "sub1"); + var localPathSubFile1 = Path.Combine(localSubDirectory1, "file1"); + var localPathSubFile2 = Path.Combine(localSubDirectory1, "file2"); + var localSubDirectory2 = Path.Combine(localDirectory, "sub2"); + + try + { + CreateFile(localPathFile1, 2000); + File.SetLastWriteTimeUtc(localPathFile1, new DateTime(2015, 8, 24, 5, 32, 16, DateTimeKind.Utc)); + + CreateFile(localPathFile2, 1000); + File.SetLastWriteTimeUtc(localPathFile2, new DateTime(2012, 3, 27, 23, 2, 54, DateTimeKind.Utc)); + + // create subdirectory with two files + Directory.CreateDirectory(localSubDirectory1); + CreateFile(localPathSubFile1, 1000); + File.SetLastWriteTimeUtc(localPathSubFile1, new DateTime(2013, 4, 12, 16, 54, 22, DateTimeKind.Utc)); + CreateFile(localPathSubFile2, 2000); + File.SetLastWriteTimeUtc(localPathSubFile2, new DateTime(2015, 8, 4, 12, 43, 12, DateTimeKind.Utc)); + Directory.SetLastWriteTimeUtc(localSubDirectory1, + new DateTime(2014, 6, 12, 13, 2, 44, DateTimeKind.Utc)); + + // create empty subdirectory + Directory.CreateDirectory(localSubDirectory2); + Directory.SetLastWriteTimeUtc(localSubDirectory2, + new DateTime(2011, 5, 14, 1, 5, 12, DateTimeKind.Utc)); + + Directory.SetLastWriteTimeUtc(localDirectory, new DateTime(2015, 10, 14, 22, 45, 11, DateTimeKind.Utc)); + + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + client.Upload(new DirectoryInfo(localDirectory), remoteDirectory); + } + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + Assert.IsTrue(client.Exists(remoteDirectory)); + + var remoteSftpDirectory = client.Get(remoteDirectory); + Assert.IsNotNull(remoteSftpDirectory); + Assert.AreEqual(absoluteRemoteDirectory, remoteSftpDirectory.FullName); + Assert.IsTrue(remoteSftpDirectory.IsDirectory); + Assert.IsFalse(remoteSftpDirectory.IsRegularFile); + + // Due to CVE-2018-20685, we can no longer set the times or modes on a file or directory + // that refers to the current directory ('.'), the parent directory ('..') or a directory + // containing a forward slash ('/'). + Assert.AreNotEqual(Directory.GetLastWriteTimeUtc(localDirectory), remoteSftpDirectory.LastWriteTimeUtc); + + Assert.IsTrue(client.Exists(remotePathFile1)); + Assert.AreEqual(CreateFileHash(localPathFile1), CreateRemoteFileHash(client, remotePathFile1)); + var remoteSftpFile = client.Get(remotePathFile1); + Assert.IsNotNull(remoteSftpFile); + Assert.IsFalse(remoteSftpFile.IsDirectory); + Assert.IsTrue(remoteSftpFile.IsRegularFile); + Assert.AreEqual(File.GetLastWriteTimeUtc(localPathFile1), remoteSftpFile.LastWriteTimeUtc); + + Assert.IsTrue(client.Exists(remotePathFile2)); + Assert.AreEqual(CreateFileHash(localPathFile2), CreateRemoteFileHash(client, remotePathFile2)); + remoteSftpFile = client.Get(remotePathFile2); + Assert.IsNotNull(remoteSftpFile); + Assert.IsFalse(remoteSftpFile.IsDirectory); + Assert.IsTrue(remoteSftpFile.IsRegularFile); + Assert.AreEqual(File.GetLastWriteTimeUtc(localPathFile2), remoteSftpFile.LastWriteTimeUtc); + + Assert.IsTrue(client.Exists(remoteSubDirectory1)); + remoteSftpDirectory = client.Get(remoteSubDirectory1); + Assert.IsNotNull(remoteSftpDirectory); + Assert.AreEqual(absoluteremoteSubDirectory1, remoteSftpDirectory.FullName); + Assert.IsTrue(remoteSftpDirectory.IsDirectory); + Assert.IsFalse(remoteSftpDirectory.IsRegularFile); + Assert.AreEqual(Directory.GetLastWriteTimeUtc(localSubDirectory1), remoteSftpDirectory.LastWriteTimeUtc); + + Assert.IsTrue(client.Exists(remotePathSubFile1)); + Assert.AreEqual(CreateFileHash(localPathSubFile1), CreateRemoteFileHash(client, remotePathSubFile1)); + + Assert.IsTrue(client.Exists(remotePathSubFile2)); + Assert.AreEqual(CreateFileHash(localPathSubFile2), CreateRemoteFileHash(client, remotePathSubFile2)); + + Assert.IsTrue(client.Exists(remoteSubDirectory2)); + remoteSftpDirectory = client.Get(remoteSubDirectory2); + Assert.IsNotNull(remoteSftpDirectory); + Assert.AreEqual(absoluteremoteSubDirectory2, remoteSftpDirectory.FullName); + Assert.IsTrue(remoteSftpDirectory.IsDirectory); + Assert.IsFalse(remoteSftpDirectory.IsRegularFile); + Assert.AreEqual(Directory.GetLastWriteTimeUtc(localSubDirectory2), remoteSftpDirectory.LastWriteTimeUtc); + } + } + finally + { + Directory.Delete(localDirectory, true); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remotePathSubFile1)) + { + client.DeleteFile(remotePathSubFile1); + } + if (client.Exists(remotePathSubFile2)) + { + client.DeleteFile(remotePathSubFile2); + } + if (client.Exists(remoteSubDirectory1)) + { + client.DeleteDirectory(remoteSubDirectory1); + } + if (client.Exists(remoteSubDirectory2)) + { + client.DeleteDirectory(remoteSubDirectory2); + } + if (client.Exists(remotePathFile1)) + { + client.DeleteFile(remotePathFile1); + } + if (client.Exists(remotePathFile2)) + { + client.DeleteFile(remotePathFile2); + } + + if (remoteDirectory.Length > 0 && remoteDirectory != "." && remoteDirectory != client.WorkingDirectory) + { + if (client.Exists(remoteDirectory)) + { + client.DeleteDirectory(remoteDirectory); + } + } + } + } + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetScpUploadDirectoryInfoExistingFileData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Scp_Upload_DirectoryInfo_ExistingFile() + { + foreach (var data in GetScpUploadDirectoryInfoExistingFileData()) + { + Scp_Upload_DirectoryInfo_ExistingFile((IRemotePathTransformation)data[0], + (string)data[1]); + } + } +#endif + public void Scp_Upload_DirectoryInfo_ExistingFile(IRemotePathTransformation remotePathTransformation, + string remoteDirectory) + { + var remotePathFile1 = CombinePaths(remoteDirectory, "file1"); + var remotePathFile2 = CombinePaths(remoteDirectory, "file2"); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + Console.WriteLine(client.ConnectionInfo.CurrentKeyExchangeAlgorithm); + + using (var command = client.CreateCommand("rm -Rf " + _remotePathTransformation.Transform(remoteDirectory))) + { + command.Execute(); + } + } + + var localDirectory = Path.GetTempFileName(); + File.Delete(localDirectory); + Directory.CreateDirectory(localDirectory); + + var localPathFile1 = Path.Combine(localDirectory, "file1"); + var localPathFile2 = Path.Combine(localDirectory, "file2"); + + try + { + CreateFile(localPathFile1, 50); + CreateFile(localPathFile2, 50); + + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + if (remotePathTransformation != null) + { + client.RemotePathTransformation = remotePathTransformation; + } + + client.Connect(); + + CreateRemoteFile(client, remoteDirectory, 10); + + try + { + client.Upload(new DirectoryInfo(localDirectory), remoteDirectory); + Assert.Fail(); + } + catch (ScpException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual($"scp: {remoteDirectory}: Not a directory", ex.Message); + } + } + } + finally + { + Directory.Delete(localDirectory, true); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remotePathFile1)) + { + client.DeleteFile(remotePathFile1); + } + if (client.Exists(remotePathFile2)) + { + client.DeleteFile(remotePathFile2); + } + if (client.Exists((remoteDirectory))) + { + client.DeleteFile(remoteDirectory); + } + } + } + } + + private static IEnumerable GetScpDownloadStreamDirectoryDoesNotExistData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-directorydoesnotexist", "scp-file" }; + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-directorydoesnotexist", "scp-file" }; + } + + private static IEnumerable GetScpUploadFileInfoFileDoesNotExistData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet", "test123", 0 }; + yield return new object[] { RemotePathTransformation.None, "/home/sshnet", "test123", 5 * 1024 * 1024 }; + yield return new object[] { RemotePathTransformation.ShellQuote, "/home/sshnet/dir|&;<>()$`\"'sp\u0100ce \\tab\tlf\n*?[#~=%", "file123", 1024 }; + yield return new object[] { null, "/home/sshnet/scp test", "file 123", 1024 }; + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-test", "file|&;<>()$`\"'sp\u0100ce \\tab\tlf*?[#~=%", 1024 }; + yield return new object[] { null, "", "scp-issue280", 1024 }; + } + + private static IEnumerable GetScpUploadFileStreamFileDoesNotExistData() + { + yield return new object[] { RemotePathTransformation.ShellQuote, "/home/sshnet/dir|&;<>()$`\"'sp\u0100ce \\tab\tlf\n*?[#~=%", "file123", 0 }; + yield return new object[] { RemotePathTransformation.ShellQuote, "/home/sshnet/dir|&;<>()$`\"'sp\u0100ce \\tab\tlf\n*?[#~=%", "file123", 1024 }; + yield return new object[] { null, "/home/sshnet/scp test", "file 123", 1024 }; + yield return new object[] { RemotePathTransformation.ShellQuote, "/home/sshnet/scp-test", "file|&;<>()$`\"'sp\u0100ce \\tab\tlf*?[#~=%", 1024 }; + yield return new object[] { RemotePathTransformation.None, "", "scp-issue280", 1024 }; + } + + private static IEnumerable GetScpUploadDirectoryInfoExistingDirectoryData() + { + yield return new object[] { RemotePathTransformation.None, "scp-directorydoesnotexist" }; + yield return new object[] { RemotePathTransformation.None, "." }; + yield return new object[] { RemotePathTransformation.ShellQuote, "/home/sshnet/dir|&;<>()$`\"'sp\u0100ce \\tab\tlf*?[#~=%" }; + } + + private static IEnumerable GetScpUploadDirectoryInfoExistingFileData() + { + yield return new object[] { RemotePathTransformation.None, "scp-upload-file" }; + } + + private static IEnumerable ScpUploadFileStreamExistingFileData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-upload-file" }; + } + + private static IEnumerable GetScpDownloadStreamFileDoesNotExistData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet", "scp-filedoesnotexist" }; + } + + private static IEnumerable GetScpDownloadDirectoryInfoDirectoryDoesNotExistData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-download" }; + } + + private static IEnumerable GetScpDownloadDirectoryInfoExistingFileData() + { + yield return new object[] { RemotePathTransformation.None, "scp-download" }; + } + + private static IEnumerable GetScpDownloadDirectoryInfoExistingDirectoryData() + { + yield return new object[] { RemotePathTransformation.None, "scp-download" }; + yield return new object[] { RemotePathTransformation.ShellQuote, "/home/sshnet/dir|&;<>()$`\"'space \\tab\tlf*?[#~=%" }; + } + + private static IEnumerable GetScpDownloadFileInfoDirectoryDoesNotExistData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-directorydoesnotexist", "scp-file" }; + } + + private static IEnumerable GetScpDownloadFileInfoFileDoesNotExistData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet", "scp-filedoesnotexist" }; + } + + private static IEnumerable GetScpDownloadFileInfoExistingDirectoryData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-test" }; + } + + private static IEnumerable GetScpDownloadFileInfoExistingFileData() + { + yield return new object[] { null, "", "file 123", 0 }; + yield return new object[] { null, "", "file 123", 1024 }; + yield return new object[] { RemotePathTransformation.ShellQuote, "", "file|&;<>()$`\"'sp\u0100ce \\tab\tlf*?[#~=%", 1024 }; + yield return new object[] { null, "/home/sshnet/scp test", "file 123", 1024 }; + yield return new object[] { RemotePathTransformation.ShellQuote, "/home/sshnet/dir|&;<>()$`\"'sp\u0100ce \\tab\tlf\n*?[#~=%", "file123", 1024 }; + yield return new object[] { RemotePathTransformation.ShellQuote, "/home/sshnet/scp-test", "file|&;<>()$`\"'sp\u0100ce \\tab\tlf*?[#~=%", 1024 }; + } + + private static IEnumerable GetScpDownloadStreamExistingDirectoryData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-test" }; + } + + private static IEnumerable GetScpDownloadStreamExistingFileData() + { + yield return new object[] { null, "", "file 123", 0 }; + yield return new object[] { null, "", "file 123", 1024 }; + yield return new object[] { RemotePathTransformation.ShellQuote, "", "file|&;<>()$`\"'sp\u0100ce \\tab\tlf*?[#~=%", 1024 }; + yield return new object[] { null, "/home/sshnet/scp test", "file 123", 1024 }; + yield return new object[] { RemotePathTransformation.ShellQuote, "/home/sshnet/dir|&;<>()$`\"'sp\u0100ce \\tab\tlf\n*?[#~=%", "file123", 1024 }; + yield return new object[] { RemotePathTransformation.ShellQuote, "/home/sshnet/scp-test", "file|&;<>()$`\"'sp\u0100ce \\tab\tlf*?[#~=%", 1024 }; + } + + private static IEnumerable GetScpUploadFileStreamDirectoryDoesNotExistData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-issue289", "file123" }; + } + + private static IEnumerable GetScpUploadFileStreamExistingDirectoryData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-issue286" }; + } + + private static IEnumerable GetScpUploadFileInfoDirectoryDoesNotExistData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-issue289", "file123" }; + } + + private static IEnumerable GetScpUploadFileInfoExistingDirectoryData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-issue286" }; + } + + private static IEnumerable GetScpUploadFileInfoExistingFileData() + { + yield return new object[] { RemotePathTransformation.None, "/home/sshnet/scp-upload-file" }; + } + + private static IEnumerable GetScpUploadDirectoryInfoDirectoryDoesNotExistData() + { + yield return new object[] { RemotePathTransformation.None, "scp-directorydoesnotexist" }; + } + + private static void CreateRemoteFile(ScpClient client, string remoteFile, int size) + { + var file = CreateTempFile(size); + + try + { + using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + client.Upload(fs, remoteFile); + } + } + finally + { + File.Delete(file); + } + } + + private static string GetAbsoluteRemotePath(SftpClient client, string directoryName, string fileName) + { + var absolutePath = string.Empty; + + if (directoryName.Length == 0) + { + absolutePath += client.WorkingDirectory; + } + else + { + if (directoryName[0] != '/') + { + absolutePath += client.WorkingDirectory + "/" + directoryName; + } + else + { + absolutePath = directoryName; + } + } + + return absolutePath + "/" + fileName; + } + + private static string GetAbsoluteRemotePath(IConnectionInfoFactory connectionInfoFactory, string directoryName) + { + var absolutePath = string.Empty; + + if (directoryName.Length == 0 || directoryName == ".") + { + using (var client = new SftpClient(connectionInfoFactory.Create())) + { + client.Connect(); + + absolutePath += client.WorkingDirectory; + } + } + else + { + if (directoryName[0] != '/') + { + using (var client = new SftpClient(connectionInfoFactory.Create())) + { + client.Connect(); + + absolutePath += client.WorkingDirectory + "/" + directoryName; + } + } + else + { + absolutePath = directoryName; + } + } + + return absolutePath; + } + + private static string CreateRemoteFileHash(SftpClient client, string remotePath) + { + using (var fs = client.OpenRead(remotePath)) + { + return CreateHash(fs); + } + } + + private static string CombinePaths(string path1, string path2) + { + if (path1.Length == 0) + { + return path2; + } + + if (path2.Length == 0) + { + return path1; + } + + return path1 + "/" + path2; + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs b/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs index 9e91ad70d..ee0258cdc 100644 --- a/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs +++ b/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs @@ -1,7 +1,6 @@ -using Renci.SshNet; using Renci.SshNet.Common; -namespace IntegrationTests +namespace Renci.SshNet.IntegrationTests { /// /// The SFTP client integration tests diff --git a/src/Renci.SshNet.IntegrationTests/SftpTests.cs b/src/Renci.SshNet.IntegrationTests/SftpTests.cs new file mode 100644 index 000000000..dc316cfbc --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/SftpTests.cs @@ -0,0 +1,6234 @@ +锘縰sing System.Diagnostics; + +using Renci.SshNet.Common; +using Renci.SshNet.IntegrationTests.Common; +using Renci.SshNet.Sftp; + +namespace Renci.SshNet.IntegrationTests +{ + // TODO: DeleteDirectory (fail + success + // TODO: DeleteFile (fail + success + // TODO: Delete (fail + success + + [TestClass] + public class SftpTests : TestBase + { + private IConnectionInfoFactory _connectionInfoFactory; + private IConnectionInfoFactory _adminConnectionInfoFactory; + private IRemotePathTransformation _remotePathTransformation; + + [TestInitialize] + public void SetUp() + { + _connectionInfoFactory = new LinuxVMConnectionFactory(SshServerHostName, SshServerPort); + _adminConnectionInfoFactory = new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort); + _remotePathTransformation = RemotePathTransformation.ShellQuote; + } + +#if FEATURE_MSTEST_DATATEST + [DataTestMethod] + [DynamicData(nameof(GetSftpUploadFileFileStreamData), DynamicDataSourceType.Method)] +#else + [TestMethod] + public void Sftp_Upload_DirectoryInfo_ExistingFile() + { + foreach (var data in GetSftpUploadFileFileStreamData()) + { + Sftp_UploadFile_FileStream((int) data[0]); + } + } +#endif + public void Sftp_UploadFile_FileStream(int size) + { + var file = CreateTempFile(size); + + using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read)) + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.Delete(remoteFile); + } + + try + { + client.UploadFile(fs, remoteFile); + + using (var memoryStream = new MemoryStream(size)) + { + client.DownloadFile(remoteFile, memoryStream); + memoryStream.Position = 0; + Assert.AreEqual(CreateFileHash(file), CreateHash(memoryStream)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.Delete(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ConnectDisconnect_Serial() + { + const int iterations = 100; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + for (var i = 1; i <= iterations; i++) + { + client.Connect(); + client.Disconnect(); + } + } + } + + [TestMethod] + public void Sftp_ConnectDisconnect_Parallel() + { + const int iterations = 10; + const int threads = 20; + + var startEvent = new ManualResetEvent(false); + + var tasks = Enumerable.Range(1, threads).Select(i => + { + return Task.Factory.StartNew(() => + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + startEvent.WaitOne(); + + for (var j = 0; j < iterations; j++) + { + client.Connect(); + client.Disconnect(); + } + } + }); + }).ToArray(); + + startEvent.Set(); + + Task.WaitAll(tasks); + } + + [TestMethod] + public void Sftp_BeginUploadFile() + { + const string content = "SftpBeginUploadFile"; + + var expectedByteCount = (ulong) Encoding.ASCII.GetByteCount(content); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.Delete(remoteFile); + } + + try + { + using (var memoryStream = new MemoryStream(Encoding.ASCII.GetBytes(content))) + { + IAsyncResult asyncResultCallback = null; + + var asyncResult = client.BeginUploadFile(memoryStream, remoteFile, ar => asyncResultCallback = ar); + + Assert.IsTrue(asyncResult.AsyncWaitHandle.WaitOne(10000)); + + // check async result + var sftpUploadAsyncResult = asyncResult as SftpUploadAsyncResult; + Assert.IsNotNull(sftpUploadAsyncResult); + Assert.IsFalse(sftpUploadAsyncResult.IsUploadCanceled); + Assert.IsTrue(sftpUploadAsyncResult.IsCompleted); + Assert.IsFalse(sftpUploadAsyncResult.CompletedSynchronously); + Assert.AreEqual(expectedByteCount, sftpUploadAsyncResult.UploadedBytes); + + // check async result callback + var sftpUploadAsyncResultCallback = asyncResultCallback as SftpUploadAsyncResult; + Assert.IsNotNull(sftpUploadAsyncResultCallback); + Assert.IsFalse(sftpUploadAsyncResultCallback.IsUploadCanceled); + Assert.IsTrue(sftpUploadAsyncResultCallback.IsCompleted); + Assert.IsFalse(sftpUploadAsyncResultCallback.CompletedSynchronously); + Assert.AreEqual(expectedByteCount, sftpUploadAsyncResultCallback.UploadedBytes); + } + + // check uploaded file + using (var memoryStream = new MemoryStream()) + { + client.DownloadFile(remoteFile, memoryStream); + memoryStream.Position = 0; + var remoteContent = Encoding.ASCII.GetString(memoryStream.ToArray()); + Assert.AreEqual(content, remoteContent); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.Delete(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Create_ExistingFile() + { + var encoding = Encoding.UTF8; + var initialContent = "Gert & Ann & Lisa"; + var newContent1 = "Sofie"; + var newContent1Bytes = GetBytesWithPreamble(newContent1, encoding); + var newContent2 = "Lisa & Sofie"; + var newContent2Bytes = GetBytesWithPreamble(newContent2, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent); + + #region Write less bytes than the current content, overwriting part of that content + + using (var fs = client.Create(remoteFile)) + using (var sw = new StreamWriter(fs, encoding)) + { + sw.Write(newContent1); + } + + var actualContent1 = client.ReadAllBytes(remoteFile); + Assert.IsTrue(newContent1Bytes.IsEqualTo(actualContent1)); + + #endregion Write less bytes than the current content, overwriting part of that content + + #region Write more bytes than the current content, overwriting and appending to that content + + using (var fs = client.Create(remoteFile)) + using (var sw = new StreamWriter(fs, encoding)) + { + sw.Write(newContent2); + } + + var actualContent2 = client.ReadAllBytes(remoteFile); + Assert.IsTrue(newContent2Bytes.IsEqualTo(actualContent2)); + + #endregion Write more bytes than the current content, overwriting and appending to that content + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Create_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + SftpFileStream fs = null; + + try + { + fs = client.Create(remoteFile); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + fs?.Dispose(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Create_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.BufferSize = 512 * 1024; + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var imageStream = GetResourceStream("Renci.SshNet.IntegrationTests.resources.issue #70.png")) + { + using (var fs = client.Create(remoteFile)) + { + byte[] buffer = new byte[Math.Min(client.BufferSize, imageStream.Length)]; + int bytesRead; + + while ((bytesRead = imageStream.Read(buffer, offset: 0, buffer.Length)) > 0) + { + fs.Write(buffer, offset: 0, bytesRead); + } + } + + using (var memoryStream = new MemoryStream()) + { + client.DownloadFile(remoteFile, memoryStream); + + memoryStream.Position = 0; + imageStream.Position = 0; + + Assert.AreEqual(CreateHash(imageStream), CreateHash(memoryStream)); + } + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendAllLines_NoEncoding_ExistingFile() + { + var initialContent = "\u0100ert & Ann"; + IEnumerable linesToAppend = new[] { "Forever", "&", "\u0116ver" }; + var expectedContent = initialContent + string.Join(Environment.NewLine, linesToAppend) + + Environment.NewLine; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent); + client.AppendAllLines(remoteFile, linesToAppend); + + var text = client.ReadAllText(remoteFile); + Assert.AreEqual(expectedContent, text); + + // ensure we didn't write an UTF-8 BOM + using (var fs = client.OpenRead(remoteFile)) + { + var firstByte = fs.ReadByte(); + Assert.AreEqual(Encoding.UTF8.GetBytes(expectedContent)[0], firstByte); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendAllLines_NoEncoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + IEnumerable linesToAppend = new[] { "\u0139isa", "&", "Sofie" }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.AppendAllLines(remoteFile, linesToAppend); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendAllLines_NoEncoding_FileDoesNotExist() + { + IEnumerable linesToAppend = new[] { "\u0139isa", "&", "Sofie" }; + var expectedContent = string.Join(Environment.NewLine, linesToAppend) + Environment.NewLine; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.AppendAllLines(remoteFile, linesToAppend); + + var text = client.ReadAllText(remoteFile); + Assert.AreEqual(expectedContent, text); + + // ensure we didn't write an UTF-8 BOM + using (var fs = client.OpenRead(remoteFile)) + { + var firstByte = fs.ReadByte(); + Assert.AreEqual(Encoding.UTF8.GetBytes(expectedContent)[0], firstByte); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendAllText_NoEncoding_ExistingFile() + { + var initialContent = "\u0100ert & Ann"; + var contentToAppend = "Forever&\u0116ver"; + var expectedContent = initialContent + contentToAppend; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent); + client.AppendAllText(remoteFile, contentToAppend); + + var text = client.ReadAllText(remoteFile); + Assert.AreEqual(expectedContent, text); + + // ensure we didn't write an UTF-8 BOM + using (var fs = client.OpenRead(remoteFile)) + { + var firstByte = fs.ReadByte(); + Assert.AreEqual(Encoding.UTF8.GetBytes(expectedContent)[0], firstByte); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendAllText_NoEncoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + var contentToAppend = "Forever&\u0116ver"; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.AppendAllText(remoteFile, contentToAppend); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendAllText_NoEncoding_FileDoesNotExist() + { + var contentToAppend = "Forever&\u0116ver"; + var expectedContent = contentToAppend; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.AppendAllText(remoteFile, contentToAppend); + + var text = client.ReadAllText(remoteFile); + Assert.AreEqual(expectedContent, text); + + // ensure we didn't write an UTF-8 BOM + using (var fs = client.OpenRead(remoteFile)) + { + var firstByte = fs.ReadByte(); + Assert.AreEqual(Encoding.UTF8.GetBytes(expectedContent)[0], firstByte); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendText_NoEncoding_ExistingFile() + { + var initialContent = "\u0100ert & Ann"; + var contentToAppend = "Forever&\u0116ver"; + var expectedContent = initialContent + contentToAppend; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent); + + using (var sw = client.AppendText(remoteFile)) + { + sw.Write(contentToAppend); + } + + var text = client.ReadAllText(remoteFile); + Assert.AreEqual(expectedContent, text); + + // ensure we didn't write an UTF-8 BOM + using (var fs = client.OpenRead(remoteFile)) + { + var firstByte = fs.ReadByte(); + Assert.AreEqual(Encoding.UTF8.GetBytes(expectedContent)[0], firstByte); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendText_NoEncoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + StreamWriter sw = null; + + try + { + sw = client.AppendText(remoteFile); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + sw?.Dispose(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendText_NoEncoding_FileDoesNotExist() + { + var contentToAppend = "\u0100ert & Ann"; + var expectedContent = contentToAppend; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var sw = client.AppendText(remoteFile)) + { + sw.Write(contentToAppend); + } + + // ensure we didn't write an UTF-8 BOM + using (var fs = client.OpenRead(remoteFile)) + { + var firstByte = fs.ReadByte(); + Assert.AreEqual(Encoding.UTF8.GetBytes(expectedContent)[0], firstByte); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendAllLines_Encoding_ExistingFile() + { + var initialContent = "\u0100ert & Ann"; + IEnumerable linesToAppend = new[] { "Forever", "&", "\u0116ver" }; + var expectedContent = initialContent + string.Join(Environment.NewLine, linesToAppend) + + Environment.NewLine; + var encoding = GetRandomEncoding(); + var expectedBytes = GetBytesWithPreamble(expectedContent, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent, encoding); + client.AppendAllLines(remoteFile, linesToAppend, encoding); + + var text = client.ReadAllText(remoteFile, encoding); + Assert.AreEqual(expectedContent, text); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendAllLines_Encoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + IEnumerable linesToAppend = new[] { "Forever", "&", "\u0116ver" }; + var encoding = GetRandomEncoding(); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.AppendAllLines(remoteFile, linesToAppend, encoding); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendAllLines_Encoding_FileDoesNotExist() + { + IEnumerable linesToAppend = new[] { "\u0139isa", "&", "Sofie" }; + var expectedContent = string.Join(Environment.NewLine, linesToAppend) + Environment.NewLine; + var encoding = GetRandomEncoding(); + var expectedBytes = GetBytesWithPreamble(expectedContent, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.AppendAllLines(remoteFile, linesToAppend, encoding); + + var text = client.ReadAllText(remoteFile, encoding); + Assert.AreEqual(expectedContent, text); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendAllText_Encoding_ExistingFile() + { + var initialContent = "\u0100ert & Ann"; + var contentToAppend = "Forever&\u0116ver"; + var expectedContent = initialContent + contentToAppend; + var encoding = GetRandomEncoding(); + var expectedBytes = GetBytesWithPreamble(expectedContent, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent, encoding); + client.AppendAllText(remoteFile, contentToAppend, encoding); + + var text = client.ReadAllText(remoteFile, encoding); + Assert.AreEqual(expectedContent, text); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendAllText_Encoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + const string contentToAppend = "Forever&\u0116ver"; + var encoding = GetRandomEncoding(); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.AppendAllText(remoteFile, contentToAppend, encoding); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendAllText_Encoding_FileDoesNotExist() + { + const string contentToAppend = "Forever&\u0116ver"; + var expectedContent = contentToAppend; + var encoding = GetRandomEncoding(); + var expectedBytes = GetBytesWithPreamble(expectedContent, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.AppendAllText(remoteFile, contentToAppend, encoding); + + var text = client.ReadAllText(remoteFile, encoding); + Assert.AreEqual(expectedContent, text); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendText_Encoding_ExistingFile() + { + const string initialContent = "\u0100ert & Ann"; + const string contentToAppend = "Forever&\u0116ver"; + var expectedContent = initialContent + contentToAppend; + var encoding = GetRandomEncoding(); + var expectedBytes = GetBytesWithPreamble(expectedContent, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent, encoding); + + using (var sw = client.AppendText(remoteFile, encoding)) + { + sw.Write(contentToAppend); + } + + var text = client.ReadAllText(remoteFile, encoding); + Assert.AreEqual(expectedContent, text); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + } + } + } + + [TestMethod] + public void Sftp_AppendText_Encoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + var encoding = GetRandomEncoding(); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + StreamWriter sw = null; + + try + { + sw = client.AppendText(remoteFile, encoding); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + sw?.Dispose(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_AppendText_Encoding_FileDoesNotExist() + { + var encoding = GetRandomEncoding(); + const string contentToAppend = "\u0100ert & Ann"; + var expectedBytes = GetBytesWithPreamble(contentToAppend, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var sw = client.AppendText(remoteFile, encoding)) + { + sw.Write(contentToAppend); + } + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_CreateText_NoEncoding_ExistingFile() + { + var encoding = new UTF8Encoding(false, true); + const string initialContent = "\u0100ert & Ann"; + var initialContentBytes = GetBytesWithPreamble(initialContent, encoding); + const string newContent = "\u0116ver"; + const string expectedContent = "\u0116ver" + " & Ann"; + var expectedContentBytes = GetBytesWithPreamble(expectedContent, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent); + + using (client.CreateText(remoteFile)) + { + } + + // verify that original content is left untouched + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(initialContentBytes.IsEqualTo(actualBytes)); + } + + // write content that is less bytes than original content + using (var sw = client.CreateText(remoteFile)) + { + sw.Write(newContent); + } + + // verify that original content is only partially overwritten + var text = client.ReadAllText(remoteFile); + Assert.AreEqual(expectedContent, text); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedContentBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_CreateText_NoEncoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + StreamWriter sw = null; + + try + { + sw = client.CreateText(remoteFile); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + sw?.Dispose(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_CreateText_NoEncoding_FileDoesNotExist() + { + var encoding = new UTF8Encoding(false, true); + var initialContent = "\u0100ert & Ann"; + var initialContentBytes = GetBytesWithPreamble(initialContent, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (client.CreateText(remoteFile)) + { + } + + // verify that empty file was created + Assert.IsTrue(client.Exists(remoteFile)); + + var file = client.GetAttributes(remoteFile); + Assert.AreEqual(0, file.Size); + + client.DeleteFile(remoteFile); + + using (var sw = client.CreateText(remoteFile)) + { + sw.Write(initialContent); + } + + // verify that content is written to file + var text = client.ReadAllText(remoteFile); + Assert.AreEqual(initialContent, text); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(initialContentBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_CreateText_Encoding_ExistingFile() + { + var encoding = GetRandomEncoding(); + var initialContent = "\u0100ert & Ann"; + var initialContentBytes = GetBytesWithPreamble(initialContent, encoding); + var newContent = "\u0116ver"; + var expectedContent = "\u0116ver" + " & Ann"; + var expectedContentBytes = GetBytesWithPreamble(expectedContent, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent, encoding); + + using (client.CreateText(remoteFile)) + { + } + + // verify that original content is left untouched + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(initialContentBytes.IsEqualTo(actualBytes)); + } + + // write content that is less bytes than original content + using (var sw = client.CreateText(remoteFile, encoding)) + { + sw.Write(newContent); + } + + // verify that original content is only partially overwritten + var text = client.ReadAllText(remoteFile, encoding); + Assert.AreEqual(expectedContent, text); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedContentBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_CreateText_Encoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + var encoding = GetRandomEncoding(); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + StreamWriter sw = null; + + try + { + sw = client.CreateText(remoteFile, encoding); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + sw?.Dispose(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_CreateText_Encoding_FileDoesNotExist() + { + var encoding = GetRandomEncoding(); + var initialContent = "\u0100ert & Ann"; + var initialContentBytes = GetBytesWithPreamble(initialContent, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (client.CreateText(remoteFile, encoding)) + { + } + + // verify that file containing only preamble was created + Assert.IsTrue(client.Exists(remoteFile)); + + var file = client.GetAttributes(remoteFile); + Assert.AreEqual(encoding.GetPreamble().Length, file.Size); + + client.DeleteFile(remoteFile); + + using (var sw = client.CreateText(remoteFile, encoding)) + { + sw.Write(initialContent); + } + + // verify that content is written to file + var text = client.ReadAllText(remoteFile, encoding); + Assert.AreEqual(initialContent, text); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(initialContentBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_DownloadFile_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + using (var ms = new MemoryStream()) + { + try + { + client.DownloadFile(remoteFile, ms); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + + // ensure file was not created by us + Assert.IsFalse(client.Exists(remoteFile)); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + } + + [TestMethod] + public void Sftp_ReadAllBytes_ExistingFile() + { + var encoding = GetRandomEncoding(); + var content = "\u0100ert & Ann"; + var contentBytes = GetBytesWithPreamble(content, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, content, encoding); + + var actualBytes = client.ReadAllBytes(remoteFile); + Assert.IsTrue(contentBytes.IsEqualTo(actualBytes)); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadAllBytes_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.ReadAllBytes(remoteFile); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + + // ensure file was not created by us + Assert.IsFalse(client.Exists(remoteFile)); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadAllLines_NoEncoding_ExistingFile() + { + var encoding = new UTF8Encoding(false, true); + var lines = new[] { "\u0100ert & Ann", "Forever", "&", "\u0116ver" }; + var linesBytes = GetBytesWithPreamble(string.Join(Environment.NewLine, lines) + Environment.NewLine, + encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var sw = client.AppendText(remoteFile)) + { + for (var i = 0; i < lines.Length; i++) + { + sw.WriteLine(lines[i]); + } + } + + var actualLines = client.ReadAllLines(remoteFile); + Assert.IsNotNull(actualLines); + Assert.AreEqual(lines.Length, actualLines.Length); + + for (var i = 0; i < lines.Length; i++) + { + Assert.AreEqual(lines[i], actualLines[i]); + } + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(linesBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadAllLines_NoEncoding_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.ReadAllLines(remoteFile); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + + // ensure file was not created by us + Assert.IsFalse(client.Exists(remoteFile)); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadAllLines_Encoding_ExistingFile() + { + var encoding = GetRandomEncoding(); + var lines = new[] { "\u0100ert & Ann", "Forever", "&", "\u0116ver" }; + var linesBytes = GetBytesWithPreamble(string.Join(Environment.NewLine, lines) + Environment.NewLine, + encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var sw = client.AppendText(remoteFile, encoding)) + { + for (var i = 0; i < lines.Length; i++) + { + sw.WriteLine(lines[i]); + } + } + + var actualLines = client.ReadAllLines(remoteFile, encoding); + Assert.IsNotNull(actualLines); + Assert.AreEqual(lines.Length, actualLines.Length); + + for (var i = 0; i < lines.Length; i++) + { + Assert.AreEqual(lines[i], actualLines[i]); + } + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(linesBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadAllLines_Encoding_FileDoesNotExist() + { + var encoding = GetRandomEncoding(); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.ReadAllLines(remoteFile, encoding); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + + // ensure file was not created by us + Assert.IsFalse(client.Exists(remoteFile)); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadAllText_NoEncoding_ExistingFile() + { + var encoding = new UTF8Encoding(false, true); + var lines = new[] { "\u0100ert & Ann", "Forever", "&", "\u0116ver" }; + var expectedText = string.Join(Environment.NewLine, lines) + Environment.NewLine; + var expectedBytes = GetBytesWithPreamble(expectedText, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var sw = client.AppendText(remoteFile)) + { + for (var i = 0; i < lines.Length; i++) + { + sw.WriteLine(lines[i]); + } + } + + var actualText = client.ReadAllText(remoteFile); + Assert.AreEqual(actualText, expectedText); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadAllText_NoEncoding_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.ReadAllText(remoteFile); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + + // ensure file was not created by us + Assert.IsFalse(client.Exists(remoteFile)); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadAllText_Encoding_ExistingFile() + { + var encoding = GetRandomEncoding(); + var lines = new[] { "\u0100ert & Ann", "Forever", "&", "\u0116ver" }; + var expectedText = string.Join(Environment.NewLine, lines) + Environment.NewLine; + var expectedBytes = GetBytesWithPreamble(expectedText, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var sw = client.AppendText(remoteFile, encoding)) + { + for (var i = 0; i < lines.Length; i++) + { + sw.WriteLine(lines[i]); + } + } + + var actualText = client.ReadAllText(remoteFile, encoding); + Assert.AreEqual(expectedText, actualText); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadAllText_Encoding_FileDoesNotExist() + { + var encoding = GetRandomEncoding(); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.ReadAllText(remoteFile, encoding); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + + // ensure file was not created by us + Assert.IsFalse(client.Exists(remoteFile)); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadLines_NoEncoding_ExistingFile() + { + var lines = new[] { "\u0100ert & Ann", "Forever", "&", "\u0116ver" }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var sw = client.AppendText(remoteFile)) + { + for (var i = 0; i < lines.Length; i++) + { + sw.WriteLine(lines[i]); + } + } + + var actualLines = client.ReadLines(remoteFile); + Assert.IsNotNull(actualLines); + + var actualLinesEnum = actualLines.GetEnumerator(); + for (var i = 0; i < lines.Length; i++) + { + Assert.IsTrue(actualLinesEnum.MoveNext()); + var actualLine = actualLinesEnum.Current; + Assert.AreEqual(lines[i], actualLine); + } + + Assert.IsFalse(actualLinesEnum.MoveNext()); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadLines_NoEncoding_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.ReadLines(remoteFile); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + + // ensure file was not created by us + Assert.IsFalse(client.Exists(remoteFile)); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadLines_Encoding_ExistingFile() + { + var encoding = GetRandomEncoding(); + var lines = new[] { "\u0100ert & Ann", "Forever", "&", "\u0116ver" }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var sw = client.AppendText(remoteFile, encoding)) + { + for (var i = 0; i < lines.Length; i++) + { + sw.WriteLine(lines[i]); + } + } + + var actualLines = client.ReadLines(remoteFile, encoding); + Assert.IsNotNull(actualLines); + + using (var actualLinesEnum = actualLines.GetEnumerator()) + { + for (var i = 0; i < lines.Length; i++) + { + Assert.IsTrue(actualLinesEnum.MoveNext()); + + var actualLine = actualLinesEnum.Current; + Assert.AreEqual(lines[i], actualLine); + } + + Assert.IsFalse(actualLinesEnum.MoveNext()); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_ReadLines_Encoding_FileDoesNotExist() + { + var encoding = GetRandomEncoding(); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.ReadLines(remoteFile, encoding); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + + // ensure file was not created by us + Assert.IsFalse(client.Exists(remoteFile)); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllBytes_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + var content = GenerateRandom(size: 5); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllBytes(remoteFile, content); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllBytes_ExistingFile() + { + var initialContent = GenerateRandom(size: 13); + var newContent1 = GenerateRandom(size: 5); + var expectedContent1 = new ArrayBuilder().Add(newContent1) + .Add(initialContent, newContent1.Length, initialContent.Length - newContent1.Length) + .Build(); + var newContent2 = GenerateRandom(size: 50000); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var fs = client.Create(remoteFile)) + { + fs.Write(initialContent, offset: 0, initialContent.Length); + } + + #region Write less bytes than the current content, overwriting part of that content + + client.WriteAllBytes(remoteFile, newContent1); + + var actualContent1 = client.ReadAllBytes(remoteFile); + Assert.IsTrue(expectedContent1.IsEqualTo(actualContent1)); + + #endregion Write less bytes than the initial content, overwriting part of that content + + #region Write more bytes than the current content, overwriting and appending to that content + + client.WriteAllBytes(remoteFile, newContent2); + + var actualContent2 = client.ReadAllBytes(remoteFile); + Assert.IsTrue(newContent2.IsEqualTo(actualContent2)); + + #endregion Write less bytes than the initial content, overwriting part of that content + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllBytes_FileDoesNotExist() + { + var content = GenerateRandom(size: 13); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllBytes(remoteFile, content); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(content.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + + [TestMethod] + public void Sftp_WriteAllLines_IEnumerable_NoEncoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + IEnumerable linesToWrite = new[] { "Forever", "&", "\u0116ver" }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllLines(remoteFile, linesToWrite); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllLines_IEnumerable_NoEncoding_ExistingFile() + { + var encoding = new UTF8Encoding(false, true); + var initialContent = "\u0100ert & Ann Forever & Ever Lisa & Sofie"; + var initialContentBytes = GetBytesWithPreamble(initialContent, encoding); + IEnumerable linesToWrite1 = new[] { "Forever", "&", "\u0116ver" }; + var linesToWrite1Bytes = + GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite1) + Environment.NewLine, encoding); + var expectedBytes1 = new ArrayBuilder().Add(linesToWrite1Bytes) + .Add(initialContentBytes, + linesToWrite1Bytes.Length, + initialContentBytes.Length - linesToWrite1Bytes.Length) + .Build(); + IEnumerable linesToWrite2 = new[] { "Forever", "&", "\u0116ver", "Gert & Ann", "Lisa + Sofie" }; + var linesToWrite2Bytes = + GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite2) + Environment.NewLine, encoding); + var expectedBytes2 = linesToWrite2Bytes; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + // create initial content + client.WriteAllText(remoteFile, initialContent); + + #region Write less bytes than the current content, overwriting part of that content + + client.WriteAllLines(remoteFile, linesToWrite1); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes1.IsEqualTo(actualBytes)); + } + + #endregion Write less bytes than the current content, overwriting part of that content + + #region Write more bytes than the current content, overwriting and appending to that content + + client.WriteAllLines(remoteFile, linesToWrite2); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes2.IsEqualTo(actualBytes)); + } + + #endregion Write more bytes than the current content, overwriting and appending to that content + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllLines_IEnumerable_NoEncoding_FileDoesNotExist() + { + var encoding = new UTF8Encoding(false, true); + IEnumerable linesToWrite = new[] { "\u0139isa", "&", "Sofie" }; + var linesToWriteBytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite) + Environment.NewLine, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllLines(remoteFile, linesToWrite); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(linesToWriteBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllLines_IEnumerable_Encoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + var encoding = GetRandomEncoding(); + IEnumerable linesToWrite = new[] { "Forever", "&", "\u0116ver" }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllLines(remoteFile, linesToWrite, encoding); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllLines_IEnumerable_Encoding_ExistingFile() + { + var encoding = GetRandomEncoding(); + const string initialContent = "\u0100ert & Ann Forever & Ever Lisa & Sofie"; + var initialContentBytes = GetBytesWithPreamble(initialContent, encoding); + IEnumerable linesToWrite1 = new[] { "Forever", "&", "\u0116ver" }; + var linesToWrite1Bytes = + GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite1) + Environment.NewLine, encoding); + var expectedBytes1 = new ArrayBuilder().Add(linesToWrite1Bytes) + .Add(initialContentBytes, + linesToWrite1Bytes.Length, + initialContentBytes.Length - linesToWrite1Bytes.Length) + .Build(); + IEnumerable linesToWrite2 = new[] { "Forever", "&", "\u0116ver", "Gert & Ann", "Lisa + Sofie" }; + var linesToWrite2Bytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite2) + Environment.NewLine, encoding); + var expectedBytes2 = linesToWrite2Bytes; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + // create initial content + client.WriteAllText(remoteFile, initialContent, encoding); + + #region Write less bytes than the current content, overwriting part of that content + + client.WriteAllLines(remoteFile, linesToWrite1, encoding); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes1.IsEqualTo(actualBytes)); + } + + #endregion Write less bytes than the current content, overwriting part of that content + + #region Write more bytes than the current content, overwriting and appending to that content + + client.WriteAllLines(remoteFile, linesToWrite2, encoding); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes2.IsEqualTo(actualBytes)); + } + + #endregion Write more bytes than the current content, overwriting and appending to that content + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllLines_IEnumerable_Encoding_FileDoesNotExist() + { + var encoding = GetRandomEncoding(); + IEnumerable linesToWrite = new[] { "\u0139isa", "&", "Sofie" }; + var linesToWriteBytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite) + Environment.NewLine, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllLines(remoteFile, linesToWrite, encoding); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(linesToWriteBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllLines_Array_NoEncoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + var linesToWrite = new[] { "Forever", "&", "\u0116ver" }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllLines(remoteFile, linesToWrite); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllLines_Array_NoEncoding_ExistingFile() + { + var encoding = new UTF8Encoding(false, true); + const string initialContent = "\u0100ert & Ann Forever & Ever Lisa & Sofie"; + var initialContentBytes = GetBytesWithPreamble(initialContent, encoding); + var linesToWrite1 = new[] { "Forever", "&", "\u0116ver" }; + var linesToWrite1Bytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite1) + Environment.NewLine, encoding); + var expectedBytes1 = new ArrayBuilder().Add(linesToWrite1Bytes) + .Add(initialContentBytes, linesToWrite1Bytes.Length, initialContentBytes.Length - linesToWrite1Bytes.Length) + .Build(); + var linesToWrite2 = new[] { "Forever", "&", "\u0116ver", "Gert & Ann", "Lisa + Sofie" }; + var linesToWrite2Bytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite2) + Environment.NewLine, encoding); + var expectedBytes2 = linesToWrite2Bytes; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + // create initial content + client.WriteAllText(remoteFile, initialContent); + + #region Write less bytes than the current content, overwriting part of that content + + client.WriteAllLines(remoteFile, linesToWrite1); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes1.IsEqualTo(actualBytes)); + } + + #endregion Write less bytes than the current content, overwriting part of that content + + #region Write more bytes than the current content, overwriting and appending to that content + + client.WriteAllLines(remoteFile, linesToWrite2); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes2.IsEqualTo(actualBytes)); + } + + #endregion Write more bytes than the current content, overwriting and appending to that content + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllLines_Array_NoEncoding_FileDoesNotExist() + { + var encoding = new UTF8Encoding(false, true); + var linesToWrite = new[] { "\u0139isa", "&", "Sofie" }; + var linesToWriteBytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite) + Environment.NewLine, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllLines(remoteFile, linesToWrite); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(linesToWriteBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllLines_Array_Encoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + var encoding = GetRandomEncoding(); + var linesToWrite = new[] { "Forever", "&", "\u0116ver" }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllLines(remoteFile, linesToWrite, encoding); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllLines_Array_Encoding_ExistingFile() + { + const string initialContent = "\u0100ert & Ann Forever & Ever Lisa & Sofie"; + + var encoding = GetRandomEncoding(); + var initialContentBytes = GetBytesWithPreamble(initialContent, encoding); + var linesToWrite1 = new[] { "Forever", "&", "\u0116ver" }; + var linesToWrite1Bytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite1) + Environment.NewLine, encoding); + var expectedBytes1 = new ArrayBuilder().Add(linesToWrite1Bytes) + .Add(initialContentBytes, linesToWrite1Bytes.Length, initialContentBytes.Length - linesToWrite1Bytes.Length) + .Build(); + var linesToWrite2 = new[] { "Forever", "&", "\u0116ver", "Gert & Ann", "Lisa + Sofie" }; + var linesToWrite2Bytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite2) + Environment.NewLine, encoding); + var expectedBytes2 = linesToWrite2Bytes; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + // create initial content + client.WriteAllText(remoteFile, initialContent, encoding); + + #region Write less bytes than the current content, overwriting part of that content + + client.WriteAllLines(remoteFile, linesToWrite1, encoding); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes1.IsEqualTo(actualBytes)); + } + + #endregion Write less bytes than the current content, overwriting part of that content + + #region Write more bytes than the current content, overwriting and appending to that content + + client.WriteAllLines(remoteFile, linesToWrite2, encoding); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes2.IsEqualTo(actualBytes)); + } + + #endregion Write more bytes than the current content, overwriting and appending to that content + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllLines_Array_Encoding_FileDoesNotExist() + { + var encoding = GetRandomEncoding(); + var linesToWrite = new[] { "\u0139isa", "&", "Sofie" }; + var linesToWriteBytes = GetBytesWithPreamble(string.Join(Environment.NewLine, linesToWrite) + Environment.NewLine, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllLines(remoteFile, linesToWrite, encoding); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(linesToWriteBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + + } + } + + [TestMethod] + public void Sftp_WriteAllText_NoEncoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + const string initialContent = "\u0100ert & Ann Forever & \u0116ver Lisa & Sofie"; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllText_NoEncoding_ExistingFile() + { + const string initialContent = "\u0100ert & Ann Forever & \u0116ver Lisa & Sofie"; + const string newContent1 = "For\u0116ver & Ever"; + + var encoding = new UTF8Encoding(false, true); + var initialContentBytes = GetBytesWithPreamble(initialContent, encoding); + var newContent1Bytes = GetBytesWithPreamble(newContent1, encoding); + var expectedBytes1 = new ArrayBuilder().Add(newContent1Bytes) + .Add(initialContentBytes, newContent1Bytes.Length, initialContentBytes.Length - newContent1Bytes.Length) + .Build(); + var newContent2 = "Sofie & Lisa For\u0116ver & Ever with \u0100ert & Ann"; + var newContent2Bytes = GetBytesWithPreamble(newContent2, encoding); + var expectedBytes2 = newContent2Bytes; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent); + + #region Write less bytes than the current content, overwriting part of that content + + client.WriteAllText(remoteFile, newContent1); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes1.IsEqualTo(actualBytes)); + } + + #endregion Write less bytes than the current content, overwriting part of that content + + #region Write more bytes than the current content, overwriting and appending to that content + + client.WriteAllText(remoteFile, newContent2); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes2.IsEqualTo(actualBytes)); + } + + #endregion Write more bytes than the current content, overwriting and appending to that content + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllText_NoEncoding_FileDoesNotExist() + { + const string initialContent = "\u0100ert & Ann Forever & \u0116ver Lisa & Sofie"; + + var encoding = new UTF8Encoding(false, true); + var initialContentBytes = GetBytesWithPreamble(initialContent, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(initialContentBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllText_Encoding_DirectoryDoesNotExist() + { + const string remoteFile = "/home/sshnet/directorydoesnotexist/test"; + + var encoding = GetRandomEncoding(); + const string content = "For\u0116ver & Ever"; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, content, encoding); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllText_Encoding_ExistingFile() + { + const string initialContent = "\u0100ert & Ann Forever & \u0116ver Lisa & Sofie"; + const string newContent1 = "For\u0116ver & Ever"; + const string newContent2 = "Sofie & Lisa For\u0116ver & Ever with \u0100ert & Ann"; + + var encoding = GetRandomEncoding(); + var initialContentBytes = GetBytesWithPreamble(initialContent, encoding); + var newContent1Bytes = GetBytesWithPreamble(newContent1, encoding); + var expectedBytes1 = new ArrayBuilder().Add(newContent1Bytes) + .Add(initialContentBytes, newContent1Bytes.Length, initialContentBytes.Length - newContent1Bytes.Length) + .Build(); + var newContent2Bytes = GetBytesWithPreamble(newContent2, encoding); + var expectedBytes2 = newContent2Bytes; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent, encoding); + + #region Write less bytes than the current content, overwriting part of that content + + client.WriteAllText(remoteFile, newContent1, encoding); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes1.IsEqualTo(actualBytes)); + } + + #endregion Write less bytes than the current content, overwriting part of that content + + #region Write more bytes than the current content, overwriting and appending to that content + + client.WriteAllText(remoteFile, newContent2, encoding); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(expectedBytes2.IsEqualTo(actualBytes)); + } + + #endregion Write more bytes than the current content, overwriting and appending to that content + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_WriteAllText_Encoding_FileDoesNotExist() + { + const string initialContent = "\u0100ert & Ann Forever & \u0116ver Lisa & Sofie"; + + var encoding = GetRandomEncoding(); + var initialContentBytes = GetBytesWithPreamble(initialContent, encoding); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, initialContent, encoding); + + using (var fs = client.OpenRead(remoteFile)) + { + var actualBytes = new byte[fs.Length]; + fs.Read(actualBytes, offset: 0, actualBytes.Length); + Assert.IsTrue(initialContentBytes.IsEqualTo(actualBytes)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_BeginDownloadFile_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var ms = new MemoryStream()) + { + var asyncResult = client.BeginDownloadFile(remoteFile, ms); + try + { + client.EndDownloadFile(asyncResult); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + + // ensure file was not created by us + Assert.IsFalse(client.Exists(remoteFile)); + } + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_BeginListDirectory_DirectoryDoesNotExist() + { + const string remoteDirectory = "/home/sshnet/test123"; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var command = client.CreateCommand("rm -Rf " + _remotePathTransformation.Transform(remoteDirectory))) + { + command.Execute(); + } + } + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var asyncResult = client.BeginListDirectory(remoteDirectory, null, null); + try + { + client.EndListDirectory(asyncResult); + Assert.Fail(); + } + catch (SftpPathNotFoundException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("No such file", ex.Message); + + // ensure directory was not created by us + Assert.IsFalse(client.Exists(remoteDirectory)); + } + } + } + + [TestMethod] + public void Sftp_BeginUploadFile_InputAndPath_DirectoryDoesNotExist() + { + const int size = 50 * 1024 * 1024; + const string remoteDirectory = "/home/sshnet/test123"; + const string remoteFile = remoteDirectory + "/test"; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var command = client.CreateCommand("rm -Rf " + _remotePathTransformation.Transform(remoteDirectory))) + { + command.Execute(); + } + } + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var memoryStream = CreateMemoryStream(size); + memoryStream.Position = 0; + + var asyncResult = client.BeginUploadFile(memoryStream, remoteFile); + try + { + client.EndUploadFile(asyncResult); + Assert.Fail(); + } + catch (SftpPathNotFoundException) + { + } + } + } + + [TestMethod] + public void Sftp_BeginUploadFile_InputAndPath_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + var uploadMemoryStream = new MemoryStream(); + var sw = new StreamWriter(uploadMemoryStream, Encoding.UTF8); + sw.Write("Gert & Ann"); + sw.Flush(); + uploadMemoryStream.Position = 0; + + var asyncResult = client.BeginUploadFile(uploadMemoryStream, remoteFile); + client.EndUploadFile(asyncResult); + + using (var downloadMemoryStream = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloadMemoryStream); + + downloadMemoryStream.Position = 0; + + using (var sr = new StreamReader(downloadMemoryStream, Encoding.UTF8)) + { + var content = sr.ReadToEnd(); + Assert.AreEqual("Gert & Ann", content); + } + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_BeginUploadFile_InputAndPath_ExistingFile() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, "Gert & Ann & Lisa"); + + var uploadMemoryStream = new MemoryStream(); + var sw = new StreamWriter(uploadMemoryStream, Encoding.UTF8); + sw.Write("Ann & Gert"); + sw.Flush(); + uploadMemoryStream.Position = 0; + + var asyncResult = client.BeginUploadFile(uploadMemoryStream, remoteFile); + client.EndUploadFile(asyncResult); + + using (var downloadMemoryStream = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloadMemoryStream); + + downloadMemoryStream.Position = 0; + + using (var sr = new StreamReader(downloadMemoryStream, Encoding.UTF8)) + { + var content = sr.ReadToEnd(); + Assert.AreEqual("Ann & Gert", content); + } + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_BeginUploadFile_InputAndPathAndCanOverride_CanOverrideIsFalse_DirectoryDoesNotExist() + { + const int size = 50 * 1024 * 1024; + const string remoteDirectory = "/home/sshnet/test123"; + const string remoteFile = remoteDirectory + "/test"; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var command = client.CreateCommand("rm -Rf " + _remotePathTransformation.Transform(remoteDirectory))) + { + command.Execute(); + } + } + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var memoryStream = CreateMemoryStream(size); + memoryStream.Position = 0; + + var asyncResult = client.BeginUploadFile(memoryStream, remoteFile, false, null, null); + try + { + client.EndUploadFile(asyncResult); + Assert.Fail(); + } + catch (SftpPathNotFoundException) + { + } + } + } + + [TestMethod] + public void Sftp_BeginUploadFile_InputAndPathAndCanOverride_CanOverrideIsFalse_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var uploadMemoryStream = new MemoryStream()) + using (var sw = new StreamWriter(uploadMemoryStream, Encoding.UTF8)) + { + sw.Write("Gert & Ann"); + sw.Flush(); + uploadMemoryStream.Position = 0; + + var asyncResult = client.BeginUploadFile(uploadMemoryStream, remoteFile, false, null, null); + client.EndUploadFile(asyncResult); + } + + using (var downloadMemoryStream = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloadMemoryStream); + + downloadMemoryStream.Position = 0; + + using (var sr = new StreamReader(downloadMemoryStream, Encoding.UTF8)) + { + var content = sr.ReadToEnd(); + Assert.AreEqual("Gert & Ann", content); + } + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_BeginUploadFile_InputAndPathAndCanOverride_CanOverrideIsFalse_ExistingFile() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, "Gert & Ann & Lisa"); + + var uploadMemoryStream = new MemoryStream(); + var sw = new StreamWriter(uploadMemoryStream, Encoding.UTF8); + sw.Write("Ann & Gert"); + sw.Flush(); + uploadMemoryStream.Position = 0; + + var asyncResult = client.BeginUploadFile(uploadMemoryStream, remoteFile, false, null, null); + + try + { + client.EndUploadFile(asyncResult); + Assert.Fail(); + } + catch (SshException ex) + { + Assert.AreEqual(typeof(SshException), ex.GetType()); + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Failure", ex.Message); + } + } + finally + { + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_BeginUploadFile_InputAndPathAndCanOverride_CanOverrideIsTrue_DirectoryDoesNotExist() + { + const int size = 50 * 1024 * 1024; + const string remoteDirectory = "/home/sshnet/test123"; + const string remoteFile = remoteDirectory + "/test"; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var command = client.CreateCommand("rm -Rf " + _remotePathTransformation.Transform(remoteDirectory))) + { + command.Execute(); + } + } + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var memoryStream = CreateMemoryStream(size); + memoryStream.Position = 0; + + var asyncResult = client.BeginUploadFile(memoryStream, remoteFile, true, null, null); + try + { + client.EndUploadFile(asyncResult); + Assert.Fail(); + } + catch (SftpPathNotFoundException) + { + } + } + } + + [TestMethod] + public void Sftp_BeginUploadFile_InputAndPathAndCanOverride_CanOverrideIsTrue_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var uploadMemoryStream = new MemoryStream()) + using (var sw = new StreamWriter(uploadMemoryStream, Encoding.UTF8)) + { + sw.Write("Gert & Ann"); + sw.Flush(); + uploadMemoryStream.Position = 0; + + var asyncResult = client.BeginUploadFile(uploadMemoryStream, remoteFile, true, null, null); + client.EndUploadFile(asyncResult); + } + + using (var downloadMemoryStream = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloadMemoryStream); + + downloadMemoryStream.Position = 0; + + using (var sr = new StreamReader(downloadMemoryStream, Encoding.UTF8)) + { + var content = sr.ReadToEnd(); + Assert.AreEqual("Gert & Ann", content); + } + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_BeginUploadFile_InputAndPathAndCanOverride_CanOverrideIsTrue_ExistingFile() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllText(remoteFile, "Gert & Ann & Lisa"); + + using (var uploadMemoryStream = new MemoryStream()) + using (var sw = new StreamWriter(uploadMemoryStream, Encoding.UTF8)) + { + sw.Write("Ann & Gert"); + sw.Flush(); + uploadMemoryStream.Position = 0; + + var asyncResult = client.BeginUploadFile(uploadMemoryStream, remoteFile, true, null, null); + client.EndUploadFile(asyncResult); + } + + using (var downloadMemoryStream = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloadMemoryStream); + + downloadMemoryStream.Position = 0; + + using (var sr = new StreamReader(downloadMemoryStream, Encoding.UTF8)) + { + var content = sr.ReadToEnd(); + Assert.AreEqual("Ann & Gert", content); + } + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_UploadAndDownloadBigFile() + { + const int size = 50 * 1024 * 1024; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.Delete(remoteFile); + } + + try + { + var memoryStream = CreateMemoryStream(size); + memoryStream.Position = 0; + + client.UploadFile(memoryStream, remoteFile); + + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + // check uploaded file + memoryStream = new MemoryStream(); + client.DownloadFile(remoteFile, memoryStream); + + Assert.AreEqual(size, memoryStream.Length); + + stopwatch.Stop(); + + Console.WriteLine(@"Elapsed: {0} ms", stopwatch.ElapsedMilliseconds); + Console.WriteLine(@"Transfer speed: {0:N2} KB/s", + CalculateTransferSpeed(memoryStream.Length, stopwatch.ElapsedMilliseconds)); + } + finally + { + if (client.Exists(remoteFile)) + { + client.Delete(remoteFile); + } + } + } + } + + /// + /// Issue 1672 + /// + [TestMethod] + public void Sftp_CurrentWorkingDirectory() + { + const string homeDirectory = "/home/sshnet"; + const string otherDirectory = homeDirectory + "/dir"; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(otherDirectory)) + { + client.DeleteDirectory(otherDirectory); + } + + try + { + client.CreateDirectory(otherDirectory); + client.ChangeDirectory(otherDirectory); + + using (var s = CreateStreamWithContent("A")) + { + client.UploadFile(s, "a.txt"); + } + + using (var s = new MemoryStream()) + { + client.DownloadFile("a.txt", s); + s.Position = 0; + + var content = Encoding.ASCII.GetString(s.ToArray()); + Assert.AreEqual("A", content); + } + + Assert.IsTrue(client.Exists(otherDirectory + "/a.txt")); + client.DeleteFile("a.txt"); + Assert.IsFalse(client.Exists(otherDirectory + "/a.txt")); + client.DeleteDirectory("."); + Assert.IsFalse(client.Exists(otherDirectory)); + } + finally + { + if (client.Exists(otherDirectory)) + { + client.DeleteDirectory(otherDirectory); + } + } + } + } + + [TestMethod] + public void Sftp_Exists() + { + const string remoteHome = "/home/sshnet"; + + #region Setup + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + #region Clean-up + + using (var command = client.CreateCommand($"rm -Rf {remoteHome + "/DoesNotExist"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + using (var command = client.CreateCommand($"rm -Rf {remoteHome + "/symlink.to.directory.exists"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + using (var command = client.CreateCommand($"rm -Rf {remoteHome + "/directory.exists"}") + ) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + using (var command = client.CreateCommand($"rm -Rf {remoteHome + "/symlink.to.file.exists"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + using (var command = client.CreateCommand($"rm -f {remoteHome + "/file.exists"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + #endregion Clean-up + + #region Setup + + using (var command = client.CreateCommand($"touch {remoteHome + "/file.exists"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + using (var command = client.CreateCommand($"mkdir {remoteHome + "/directory.exists"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + using (var command = client.CreateCommand($"ln -s {remoteHome + "/file.exists"} {remoteHome + "/symlink.to.file.exists"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + using (var command = client.CreateCommand($"ln -s {remoteHome + "/directory.exists"} {remoteHome + "/symlink.to.directory.exists"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + #endregion Setup + } + + #endregion Setup + + #region Assert + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + Assert.IsFalse(client.Exists(remoteHome + "/DoesNotExist")); + Assert.IsTrue(client.Exists(remoteHome + "/file.exists")); + Assert.IsTrue(client.Exists(remoteHome + "/symlink.to.file.exists")); + Assert.IsTrue(client.Exists(remoteHome + "/directory.exists")); + Assert.IsTrue(client.Exists(remoteHome + "/symlink.to.directory.exists")); + } + + #endregion Assert + + #region Teardown + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var command = client.CreateCommand($"rm -Rf {remoteHome + "/DoesNotExist"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + using (var command = client.CreateCommand($"rm -Rf {remoteHome + "/symlink.to.directory.exists"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + using (var command = client.CreateCommand($"rm -Rf {remoteHome + "/directory.exists"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + using (var command = client.CreateCommand($"rm -Rf {remoteHome + "/symlink.to.file.exists"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + + using (var command = client.CreateCommand($"rm -f {remoteHome + "/file.exists"}")) + { + command.Execute(); + Assert.AreEqual(0, command.ExitStatus, command.Error); + } + } + + #endregion Teardown + } + + [TestMethod] + public void Sftp_ListDirectory() + { + const string remoteDirectory = "/home/sshnet/test123"; + + try + { + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.RunCommand($@"rm -Rf ""{remoteDirectory}"""); + client.RunCommand($@"mkdir -p ""{remoteDirectory}"""); + client.RunCommand($@"mkdir -p ""{remoteDirectory}/sub"""); + client.RunCommand($@"touch ""{remoteDirectory}/file1"""); + client.RunCommand($@"touch ""{remoteDirectory}/file2"""); + } + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + client.ChangeDirectory(remoteDirectory); + + var directoryContent = client.ListDirectory(".").OrderBy(p => p.Name).ToList(); + Assert.AreEqual(5, directoryContent.Count); + + Assert.AreEqual(".", directoryContent[0].Name); + Assert.AreEqual($"{remoteDirectory}/.", directoryContent[0].FullName); + Assert.IsTrue(directoryContent[0].IsDirectory); + + Assert.AreEqual("..", directoryContent[1].Name); + Assert.AreEqual($"{remoteDirectory}/..", directoryContent[1].FullName); + Assert.IsTrue(directoryContent[1].IsDirectory); + + Assert.AreEqual("file1", directoryContent[2].Name); + Assert.AreEqual($"{remoteDirectory}/file1", directoryContent[2].FullName); + Assert.IsFalse(directoryContent[2].IsDirectory); + + Assert.AreEqual("file2", directoryContent[3].Name); + Assert.AreEqual($"{remoteDirectory}/file2", directoryContent[3].FullName); + Assert.IsFalse(directoryContent[3].IsDirectory); + + Assert.AreEqual("sub", directoryContent[4].Name); + Assert.AreEqual($"{remoteDirectory}/sub", directoryContent[4].FullName); + Assert.IsTrue(directoryContent[4].IsDirectory); + } + } + finally + { + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var command = client.CreateCommand("rm -Rf " + _remotePathTransformation.Transform(remoteDirectory))) + { + command.Execute(); + } + } + } + } + + [TestMethod] + public void Sftp_ChangeDirectory_DirectoryDoesNotExist() + { + const string remoteDirectory = "/home/sshnet/test123"; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var command = client.CreateCommand("rm -Rf " + _remotePathTransformation.Transform(remoteDirectory))) + { + command.Execute(); + } + } + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + try + { + client.ChangeDirectory(remoteDirectory); + Assert.Fail(); + } + catch (SftpPathNotFoundException) + { + } + } + } + + [TestMethod] + public void Sftp_ChangeDirectory_DirectoryExists() + { + const string remoteDirectory = "/home/sshnet/test123"; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var command = client.CreateCommand("rm -Rf " + _remotePathTransformation.Transform(remoteDirectory))) + { + command.Execute(); + } + + using (var command = client.CreateCommand("mkdir -p " + _remotePathTransformation.Transform(remoteDirectory))) + { + command.Execute(); + } + } + + try + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + client.ChangeDirectory(remoteDirectory); + + Assert.AreEqual(remoteDirectory, client.WorkingDirectory); + + using (var uploadStream = CreateMemoryStream(100)) + { + uploadStream.Position = 0; + + client.UploadFile(uploadStream, "gert.txt"); + + uploadStream.Position = 0; + + using (var downloadStream = client.OpenRead(remoteDirectory + "/gert.txt")) + { + Assert.AreEqual(CreateHash(uploadStream), CreateHash(downloadStream)); + } + } + } + } + finally + { + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var command = client.CreateCommand("rm -Rf " + _remotePathTransformation.Transform(remoteDirectory))) + { + command.Execute(); + } + } + } + } + + [TestMethod] + public void Sftp_DownloadFile_MemoryStream() + { + const int fileSize = 500 * 1024; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + SftpCreateRemoteFile(client, remoteFile, fileSize); + + try + { + using (var memoryStream = new MemoryStream()) + { + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + client.DownloadFile(remoteFile, memoryStream); + stopwatch.Stop(); + + var transferSpeed = CalculateTransferSpeed(memoryStream.Length, stopwatch.ElapsedMilliseconds); + Console.WriteLine(@"Elapsed: {0} ms", stopwatch.ElapsedMilliseconds); + Console.WriteLine(@"Transfer speed: {0:N2} KB/s", transferSpeed); + + Assert.AreEqual(fileSize, memoryStream.Length); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_SubsystemExecution_Failed() + { + var remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig(); + + // Disable SFTP subsystem + remoteSshdConfig.ClearSubsystems() + .Update() + .Restart(); + + var remoteSshdReconfiguredToDefaultState = false; + + try + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + try + { + client.Connect(); + Assert.Fail("Establishing SFTP connection should have failed."); + } + catch (SshException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("Subsystem 'sftp' could not be executed.", ex.Message); + } + + // Re-enable SFTP subsystem + remoteSshdConfig.Reset(); + + remoteSshdReconfiguredToDefaultState = true; + + // ensure we can reconnect the same SftpClient instance + client.Connect(); + // ensure SFTP session is correctly established + Assert.IsTrue(client.Exists(".")); + } + } + finally + { + if (!remoteSshdReconfiguredToDefaultState) + { + remoteSshdConfig.Reset(); + } + } + } + + [TestMethod] + public void Sftp_SftpFileStream_ReadAndWrite() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var s = client.Open(remoteFile, FileMode.CreateNew, FileAccess.Write)) + { + s.Write(new byte[] { 5, 4, 3, 2, 1 }, 1, 3); + } + + // switch from read to write mode + using (var s = client.Open(remoteFile, FileMode.Open, FileAccess.ReadWrite)) + { + Assert.AreEqual(4, s.ReadByte()); + Assert.AreEqual(3, s.ReadByte()); + + Assert.AreEqual(2, s.Position); + + s.WriteByte(7); + s.Write(new byte[] { 8, 9, 10, 11, 12 }, 1, 3); + + Assert.AreEqual(6, s.Position); + } + + using (var s = client.Open(remoteFile, FileMode.Open, FileAccess.Read)) + { + Assert.AreEqual(6, s.Length); + + var buffer = new byte[s.Length]; + Assert.AreEqual(6, s.Read(buffer, offset: 0, buffer.Length)); + + CollectionAssert.AreEqual(new byte[] { 4, 3, 7, 9, 10, 11 }, buffer); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, s.ReadByte()); + } + + // switch from read to write mode, and back to read mode and finally + // append a byte + using (var s = client.Open(remoteFile, FileMode.Open, FileAccess.ReadWrite)) + { + Assert.AreEqual(4, s.ReadByte()); + Assert.AreEqual(3, s.ReadByte()); + Assert.AreEqual(7, s.ReadByte()); + + s.Write(new byte[] { 0, 1, 6, 4 }, 1, 2); + + Assert.AreEqual(11, s.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, s.ReadByte()); + + s.WriteByte(12); + } + + // switch from write to read mode, and back to write mode + using (var s = client.Open(remoteFile, FileMode.Open, FileAccess.ReadWrite)) + { + s.WriteByte(5); + Assert.AreEqual(3, s.ReadByte()); + s.WriteByte(13); + + Assert.AreEqual(3, s.Position); + } + + using (var s = client.Open(remoteFile, FileMode.Open, FileAccess.Read)) + { + Assert.AreEqual(7, s.Length); + + var buffer = new byte[s.Length]; + Assert.AreEqual(7, s.Read(buffer, offset: 0, buffer.Length)); + + CollectionAssert.AreEqual(new byte[] { 5, 3, 13, 1, 6, 11, 12 }, buffer); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, s.ReadByte()); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_SftpFileStream_SetLength_ReduceLength() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var s = client.Open(remoteFile, FileMode.CreateNew, FileAccess.Write)) + { + s.Write(new byte[] { 5, 4, 3, 2, 1 }, 1, 3); + } + + // reduce length while in write mode, with data in write buffer, and before + // current position + using (var s = client.Open(remoteFile, FileMode.Append, FileAccess.Write)) + { + s.Position = 3; + s.Write(new byte[] { 6, 7, 8, 9 }, offset: 0, count: 4); + + Assert.AreEqual(7, s.Position); + + // verify buffer has not yet been flushed + using (var fs = client.Open(remoteFile, FileMode.Open, FileAccess.Read)) + { + Assert.AreEqual(4, fs.ReadByte()); + Assert.AreEqual(3, fs.ReadByte()); + Assert.AreEqual(2, fs.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + s.SetLength(5); + + Assert.AreEqual(5, s.Position); + + // verify that buffer was flushed and size has been modified + using (var fs = client.Open(remoteFile, FileMode.Open, FileAccess.Read)) + { + Assert.AreEqual(4, fs.ReadByte()); + Assert.AreEqual(3, fs.ReadByte()); + Assert.AreEqual(2, fs.ReadByte()); + Assert.AreEqual(6, fs.ReadByte()); + Assert.AreEqual(7, fs.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + s.WriteByte(1); + } + + // verify that last byte was correctly written to the file + using (var s = client.Open(remoteFile, FileMode.Open, FileAccess.Read)) + { + Assert.AreEqual(6, s.Length); + + var buffer = new byte[s.Length + 2]; + Assert.AreEqual(6, s.Read(buffer, offset: 0, buffer.Length)); + + CollectionAssert.AreEqual(new byte[] { 4, 3, 2, 6, 7, 1, 0, 0 }, buffer); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, s.ReadByte()); + } + + // reduce length while in read mode, but beyond current position + using (var s = client.Open(remoteFile, FileMode.Open, FileAccess.ReadWrite)) + { + var buffer = new byte[1]; + Assert.AreEqual(1, s.Read(buffer, offset: 0, buffer.Length)); + + CollectionAssert.AreEqual(new byte[] { 4 }, buffer); + + s.SetLength(3); + + using (var w = client.Open(remoteFile, FileMode.Open, FileAccess.Write)) + { + w.Write(new byte[] { 8, 1, 6, 2 }, offset: 0, count: 4); + } + + // verify that position was not changed + Assert.AreEqual(1, s.Position); + + // verify that read buffer was cleared + Assert.AreEqual(1, s.ReadByte()); + Assert.AreEqual(6, s.ReadByte()); + Assert.AreEqual(2, s.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, s.ReadByte()); + + Assert.AreEqual(4, s.Length); + } + + // reduce length while in read mode, but before current position + using (var s = client.Open(remoteFile, FileMode.Open, FileAccess.ReadWrite)) + { + var buffer = new byte[4]; + Assert.AreEqual(4, s.Read(buffer, offset: 0, buffer.Length)); + + CollectionAssert.AreEqual(new byte[] { 8, 1, 6, 2 }, buffer); + + Assert.AreEqual(4, s.Position); + + s.SetLength(3); + + // verify that position was moved to last byte + Assert.AreEqual(3, s.Position); + + using (var w = client.Open(remoteFile, FileMode.Open, FileAccess.Read)) + { + Assert.AreEqual(3, w.Length); + + Assert.AreEqual(8, w.ReadByte()); + Assert.AreEqual(1, w.ReadByte()); + Assert.AreEqual(6, w.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, w.ReadByte()); + } + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, s.ReadByte()); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_SftpFileStream_Seek_BeyondEndOfFile_SeekOriginBegin() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.BufferSize = 500; + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + // seek beyond EOF but not beyond buffer size + // do not write anything + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(offset: 3L, SeekOrigin.Begin); + + Assert.AreEqual(3, newPosition); + Assert.AreEqual(3, fs.Position); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(1, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + // seek beyond EOF and beyond buffer size + // do not write anything + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(offset: 700L, SeekOrigin.Begin); + + Assert.AreEqual(700, newPosition); + Assert.AreEqual(700, fs.Position); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(1, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + // seek beyond EOF but not beyond buffer size + // write less bytes than buffer size + var seekOffset = 3L; + + // buffer holding the data that we'll write to the file + var writeBuffer = GenerateRandom(size: 7); + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(seekOffset, SeekOrigin.Begin); + + Assert.AreEqual(seekOffset, newPosition); + Assert.AreEqual(seekOffset, fs.Position); + + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(seekOffset + writeBuffer.Length, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + var soughtOverReadBufferffer = new byte[seekOffset - 1]; + Assert.AreEqual(soughtOverReadBufferffer.Length, fs.Read(soughtOverReadBufferffer, offset: 0, soughtOverReadBufferffer.Length)); + Assert.IsTrue(new byte[soughtOverReadBufferffer.Length].IsEqualTo(soughtOverReadBufferffer)); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(readBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + // seek beyond EOF and beyond buffer size + // write less bytes than buffer size + seekOffset = 700L; + + // buffer holding the data that we'll write to the file + writeBuffer = GenerateRandom(size: 4); + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(seekOffset, SeekOrigin.Begin); + + Assert.AreEqual(seekOffset, newPosition); + Assert.AreEqual(seekOffset, fs.Position); + + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(seekOffset + writeBuffer.Length, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + var soughtOverReadBufferffer = new byte[seekOffset - 1]; + Assert.AreEqual(soughtOverReadBufferffer.Length, fs.Read(soughtOverReadBufferffer, offset: 0, soughtOverReadBufferffer.Length)); + Assert.IsTrue(new byte[soughtOverReadBufferffer.Length].IsEqualTo(soughtOverReadBufferffer)); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(readBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + // seek beyond EOF but not beyond buffer size + // write more bytes than buffer size + writeBuffer = GenerateRandom(size: 600); + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(offset: 3L, SeekOrigin.Begin); + + Assert.AreEqual(3, newPosition); + Assert.AreEqual(3, fs.Position); + + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(3 + writeBuffer.Length, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + Assert.AreEqual(0x00, fs.ReadByte()); + Assert.AreEqual(0x00, fs.ReadByte()); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(writeBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + // seek beyond EOF and beyond buffer size + // write more bytes than buffer size + writeBuffer = GenerateRandom(size: 600); + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(offset: 550, SeekOrigin.Begin); + + Assert.AreEqual(550, newPosition); + Assert.AreEqual(550, fs.Position); + + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(550 + writeBuffer.Length, fs.Length); + + Assert.AreEqual(0x04, fs.ReadByte()); + + var soughtOverReadBuffer = new byte[550 - 1]; + Assert.AreEqual(550 - 1, fs.Read(soughtOverReadBuffer, offset: 0, soughtOverReadBuffer.Length)); + Assert.IsTrue(new byte[550 - 1].IsEqualTo(soughtOverReadBuffer)); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(writeBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_SftpFileStream_Seek_BeyondEndOfFile_SeekOriginEnd() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.BufferSize = 500; + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + // seek beyond EOF but not beyond buffer size + // do not write anything + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(offset: 3L, SeekOrigin.End); + + Assert.AreEqual(4, newPosition); + Assert.AreEqual(4, fs.Position); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(1, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + // seek beyond EOF and beyond buffer size + // do not write anything + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(offset: 700L, SeekOrigin.End); + + Assert.AreEqual(701, newPosition); + Assert.AreEqual(701, fs.Position); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(1, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + // seek beyond EOF but not beyond buffer size + // write less bytes than buffer size + var seekOffset = 3L; + + // buffer holding the data that we'll write to the file + var writeBuffer = GenerateRandom(size: 7); + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(seekOffset, SeekOrigin.End); + + Assert.AreEqual(4, newPosition); + Assert.AreEqual(4, fs.Position); + + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(1 + seekOffset + writeBuffer.Length, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + var soughtOverReadBuffer = new byte[seekOffset]; + Assert.AreEqual(soughtOverReadBuffer.Length, fs.Read(soughtOverReadBuffer, offset: 0, soughtOverReadBuffer.Length)); + Assert.IsTrue(new byte[soughtOverReadBuffer.Length].IsEqualTo(soughtOverReadBuffer)); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(readBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + // seek beyond EOF and beyond buffer size + // write less bytes than buffer size + seekOffset = 700L; + + // buffer holding the data that we'll write to the file + writeBuffer = GenerateRandom(size: 4); + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(seekOffset, SeekOrigin.End); + + Assert.AreEqual(1 + seekOffset, newPosition); + Assert.AreEqual(1 + seekOffset, fs.Position); + + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(1 + seekOffset + writeBuffer.Length, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + var soughtOverReadBuffer = new byte[seekOffset]; + Assert.AreEqual(soughtOverReadBuffer.Length, fs.Read(soughtOverReadBuffer, offset: 0, soughtOverReadBuffer.Length)); + Assert.IsTrue(new byte[soughtOverReadBuffer.Length].IsEqualTo(soughtOverReadBuffer)); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(readBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + // seek beyond EOF but not beyond buffer size + // write more bytes than buffer size + seekOffset = 3L; + writeBuffer = GenerateRandom(size: 600); + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(seekOffset, SeekOrigin.End); + + Assert.AreEqual(1 + seekOffset, newPosition); + Assert.AreEqual(1 + seekOffset, fs.Position); + + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(1 + seekOffset + writeBuffer.Length, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + var soughtOverReadBuffer = new byte[seekOffset]; + Assert.AreEqual(soughtOverReadBuffer.Length, fs.Read(soughtOverReadBuffer, offset: 0, soughtOverReadBuffer.Length)); + Assert.IsTrue(new byte[soughtOverReadBuffer.Length].IsEqualTo(soughtOverReadBuffer)); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(writeBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + // seek beyond EOF and beyond buffer size + // write more bytes than buffer size + seekOffset = 550L; + writeBuffer = GenerateRandom(size: 600); + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(seekOffset, SeekOrigin.End); + + Assert.AreEqual(1 + seekOffset, newPosition); + Assert.AreEqual(1 + seekOffset, fs.Position); + + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(1 + seekOffset + writeBuffer.Length, fs.Length); + + Assert.AreEqual(0x04, fs.ReadByte()); + + var soughtOverReadBuffer = new byte[seekOffset]; + Assert.AreEqual(soughtOverReadBuffer.Length, fs.Read(soughtOverReadBuffer, offset: 0, soughtOverReadBuffer.Length)); + Assert.IsTrue(new byte[soughtOverReadBuffer.Length].IsEqualTo(soughtOverReadBuffer)); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(writeBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_SftpFileStream_Seek_NegativeOffSet_SeekOriginEnd() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.BufferSize = 500; + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + fs.WriteByte(0x07); + fs.WriteByte(0x05); + } + + // seek within file and not beyond buffer size + // do not write anything + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(offset: -2L, SeekOrigin.End); + + Assert.AreEqual(1, newPosition); + Assert.AreEqual(1, fs.Position); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(3, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + Assert.AreEqual(0x07, fs.ReadByte()); + Assert.AreEqual(0x05, fs.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // buffer holding the data that we'll write to the file + var writeBuffer = GenerateRandom(size: (int) client.BufferSize + 200); + + using (var fs = client.OpenWrite(remoteFile)) + { + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + // seek within EOF and beyond buffer size + // do not write anything + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(offset: -100L, SeekOrigin.End); + + Assert.AreEqual(600, newPosition); + Assert.AreEqual(600, fs.Position); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(writeBuffer.Length, fs.Length); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(writeBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // seek within EOF and within buffer size + // write less bytes than buffer size + using (var fs = client.OpenWrite(remoteFile)) + { + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + + var newPosition = fs.Seek(offset: -3, SeekOrigin.End); + + Assert.AreEqual(697, newPosition); + Assert.AreEqual(697, fs.Position); + + fs.WriteByte(0x01); + fs.WriteByte(0x05); + fs.WriteByte(0x04); + fs.WriteByte(0x07); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(writeBuffer.Length + 1, fs.Length); + + var readBuffer = new byte[writeBuffer.Length - 3]; + Assert.AreEqual(readBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(readBuffer.SequenceEqual(writeBuffer.Take(readBuffer.Length))); + + Assert.AreEqual(0x01, fs.ReadByte()); + Assert.AreEqual(0x05, fs.ReadByte()); + Assert.AreEqual(0x04, fs.ReadByte()); + Assert.AreEqual(0x07, fs.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + // buffer holding the data that we'll write to the file + writeBuffer = GenerateRandom(size: (int) client.BufferSize * 4); + + // seek within EOF and beyond buffer size + // write less bytes than buffer size + using (var fs = client.OpenWrite(remoteFile)) + { + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + + var newPosition = fs.Seek(offset: -(client.BufferSize * 2), SeekOrigin.End); + + Assert.AreEqual(1000, newPosition); + Assert.AreEqual(1000, fs.Position); + + fs.WriteByte(0x01); + fs.WriteByte(0x05); + fs.WriteByte(0x04); + fs.WriteByte(0x07); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(writeBuffer.Length, fs.Length); + + // First part of file should not have been touched + var readBuffer = new byte[(int) client.BufferSize * 2]; + Assert.AreEqual(readBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(readBuffer.SequenceEqual(writeBuffer.Take(readBuffer.Length))); + + // Check part that should have been updated + Assert.AreEqual(0x01, fs.ReadByte()); + Assert.AreEqual(0x05, fs.ReadByte()); + Assert.AreEqual(0x04, fs.ReadByte()); + Assert.AreEqual(0x07, fs.ReadByte()); + + // Remaining bytes should not have been touched + readBuffer = new byte[((int) client.BufferSize * 2) - 4]; + Assert.AreEqual(readBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(readBuffer.SequenceEqual(writeBuffer.Skip(((int)client.BufferSize * 2) + 4).Take(readBuffer.Length))); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + /// https://github.com/sshnet/SSH.NET/issues/253 + [TestMethod] + public void Sftp_SftpFileStream_Seek_Issue253() + { + var buf = Encoding.UTF8.GetBytes("123456"); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var ws = client.OpenWrite(remoteFile)) + { + ws.Write(buf, offset: 0, count: 3); + } + + using (var ws = client.OpenWrite(remoteFile)) + { + var newPosition = ws.Seek(offset: 3, SeekOrigin.Begin); + + Assert.AreEqual(3, newPosition); + Assert.AreEqual(3, ws.Position); + + ws.Write(buf, 3, 3); + } + + var actual = client.ReadAllText(remoteFile, Encoding.UTF8); + Assert.AreEqual("123456", actual); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_SftpFileStream_Seek_WithinReadBuffer() + { + var originalContent = GenerateRandom(size: 800); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.BufferSize = 500; + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var fs = client.OpenWrite(remoteFile)) + { + fs.Write(originalContent, offset: 0, originalContent.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + var readBuffer = new byte[200]; + + Assert.AreEqual(readBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + + var newPosition = fs.Seek(offset: 3L, SeekOrigin.Begin); + + Assert.AreEqual(3L, newPosition); + Assert.AreEqual(3L, fs.Position); + } + + client.DeleteFile(remoteFile); + + #region Seek beyond EOF and beyond buffer size do not write anything + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(1, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(offset: 700L, SeekOrigin.Begin); + + Assert.AreEqual(700L, newPosition); + Assert.AreEqual(700L, fs.Position); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(1, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + #endregion Seek beyond EOF and beyond buffer size do not write anything + + #region Seek beyond EOF but not beyond buffer size and write less bytes than buffer size + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + var seekOffset = 3L; + var writeBuffer = GenerateRandom(size: 7); + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(seekOffset, SeekOrigin.Begin); + + Assert.AreEqual(seekOffset, newPosition); + Assert.AreEqual(seekOffset, fs.Position); + + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(seekOffset + writeBuffer.Length, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + var soughtOverReadBuffer = new byte[seekOffset - 1]; + Assert.AreEqual(soughtOverReadBuffer.Length, fs.Read(soughtOverReadBuffer, offset: 0, soughtOverReadBuffer.Length)); + Assert.IsTrue(new byte[soughtOverReadBuffer.Length].IsEqualTo(soughtOverReadBuffer)); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(readBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + #endregion Seek beyond EOF but not beyond buffer size and write less bytes than buffer size + + #region Seek beyond EOF and beyond buffer size and write less bytes than buffer size + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + seekOffset = 700L; + writeBuffer = GenerateRandom(size: 4); + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(seekOffset, SeekOrigin.Begin); + + Assert.AreEqual(seekOffset, newPosition); + Assert.AreEqual(seekOffset, fs.Position); + + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(seekOffset + writeBuffer.Length, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + + var soughtOverReadBufferffer = new byte[seekOffset - 1]; + Assert.AreEqual(soughtOverReadBufferffer.Length, fs.Read(soughtOverReadBufferffer, offset: 0, soughtOverReadBufferffer.Length)); + Assert.IsTrue(new byte[soughtOverReadBufferffer.Length].IsEqualTo(soughtOverReadBufferffer)); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(readBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + #endregion Seek beyond EOF and beyond buffer size and write less bytes than buffer size + + #region Seek beyond EOF but not beyond buffer size and write more bytes than buffer size + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + seekOffset = 3L; + writeBuffer = GenerateRandom(size: 600); + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(seekOffset, SeekOrigin.Begin); + + Assert.AreEqual(seekOffset, newPosition); + Assert.AreEqual(seekOffset, fs.Position); + + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(seekOffset + writeBuffer.Length, fs.Length); + Assert.AreEqual(0x04, fs.ReadByte()); + Assert.AreEqual(0x00, fs.ReadByte()); + Assert.AreEqual(0x00, fs.ReadByte()); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(writeBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + #endregion Seek beyond EOF but not beyond buffer size and write more bytes than buffer size + + #region Seek beyond EOF and beyond buffer size and write more bytes than buffer size + + // create single-byte file + using (var fs = client.OpenWrite(remoteFile)) + { + fs.WriteByte(0x04); + } + + seekOffset = 550L; + writeBuffer = GenerateRandom(size: 600); + + using (var fs = client.OpenWrite(remoteFile)) + { + var newPosition = fs.Seek(seekOffset, SeekOrigin.Begin); + + Assert.AreEqual(seekOffset, newPosition); + Assert.AreEqual(seekOffset, fs.Position); + + fs.Write(writeBuffer, offset: 0, writeBuffer.Length); + } + + using (var fs = client.OpenRead(remoteFile)) + { + Assert.AreEqual(seekOffset + writeBuffer.Length, fs.Length); + + Assert.AreEqual(0x04, fs.ReadByte()); + + var soughtOverReadBufferffer = new byte[seekOffset - 1]; + Assert.AreEqual(seekOffset - 1, fs.Read(soughtOverReadBufferffer, offset: 0, soughtOverReadBufferffer.Length)); + Assert.IsTrue(new byte[seekOffset - 1].IsEqualTo(soughtOverReadBufferffer)); + + var readBuffer = new byte[writeBuffer.Length]; + Assert.AreEqual(writeBuffer.Length, fs.Read(readBuffer, offset: 0, readBuffer.Length)); + Assert.IsTrue(writeBuffer.IsEqualTo(readBuffer)); + + // Ensure we've reached end of the stream + Assert.AreEqual(-1, fs.ReadByte()); + } + + client.DeleteFile(remoteFile); + + #endregion Seek beyond EOF and beyond buffer size and write more bytes than buffer size + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_SftpFileStream_SetLength_FileDoesNotExist() + { + var size = new Random().Next(500, 5000); + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + using (var s = client.Open(remoteFile, FileMode.Append, FileAccess.Write)) + { + s.SetLength(size); + } + + Assert.IsTrue(client.Exists(remoteFile)); + + var attributes = client.GetAttributes(remoteFile); + Assert.IsTrue(attributes.IsRegularFile); + Assert.AreEqual(size, attributes.Size); + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + downloaded.Position = 0; + Assert.AreEqual(CreateHash(new byte[size]), CreateHash(downloaded)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_Append_Write_ExistingFile() + { + const int fileSize = 5 * 1024; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + using (var input = CreateMemoryStream(fileSize)) + { + input.Position = 0; + + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.UploadFile(input, remoteFile); + + using (var s = client.Open(remoteFile, FileMode.Append, FileAccess.Write)) + { + var buffer = new byte[] { 0x05, 0x0f, 0x0d, 0x0a, 0x04 }; + s.Write(buffer, offset: 0, buffer.Length); + input.Write(buffer, offset: 0, buffer.Length); + } + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + + input.Position = 0; + downloaded.Position = 0; + Assert.AreEqual(CreateHash(input), CreateHash(downloaded)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_Append_Write_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + #region Verify if merely opening the file for append creates a zero-byte file + + using (client.Open(remoteFile, FileMode.Append, FileAccess.Write)) + { + } + + Assert.IsTrue(client.Exists(remoteFile)); + + var attributes = client.GetAttributes(remoteFile); + Assert.IsTrue(attributes.IsRegularFile); + Assert.AreEqual(0L, attributes.Size); + + #endregion Verify if merely opening the file for append creates it + + client.DeleteFile(remoteFile); + + #region Verify if content is actually written to the file + + var content = GenerateRandom(size: 100); + + using (var s = client.Open(remoteFile, FileMode.Append, FileAccess.Write)) + { + s.Write(content, offset: 0, content.Length); + } + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + downloaded.Position = 0; + Assert.AreEqual(CreateHash(content), CreateHash(downloaded)); + } + + #endregion Verify if content is actually written to the file + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + + + [TestMethod] + public void Sftp_Open_PathAndMode_ModeIsCreate_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + #region Verify if merely opening the file for create creates a zero-byte file + + using (client.Open(remoteFile, FileMode.Create)) + { + } + + Assert.IsTrue(client.Exists(remoteFile)); + + var attributes = client.GetAttributes(remoteFile); + Assert.IsTrue(attributes.IsRegularFile); + Assert.AreEqual(0L, attributes.Size); + + #endregion Verify if merely opening the file for create creates a zero-byte file + + client.DeleteFile(remoteFile); + + #region Verify if content is actually written to the file + + var content = GenerateRandom(size: 100); + + using (var s = client.Open(remoteFile, FileMode.Create)) + { + s.Write(content, offset: 0, content.Length); + } + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + downloaded.Position = 0; + Assert.AreEqual(CreateHash(content), CreateHash(downloaded)); + } + + #endregion Verify if content is actually written to the file + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_PathAndMode_ModeIsCreate_ExistingFile() + { + const int fileSize = 5 * 1024; + var newContent = new byte[] { 0x07, 0x03, 0x02, 0x0b }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + using (var input = CreateMemoryStream(fileSize)) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + input.Position = 0; + client.UploadFile(input, remoteFile); + + using (var stream = client.Open(remoteFile, FileMode.Create)) + { + // Verify if merely opening the file for create overwrites the file + var attributes = client.GetAttributes(remoteFile); + Assert.IsTrue(attributes.IsRegularFile); + Assert.AreEqual(0L, attributes.Size); + + stream.Write(newContent, offset: 0, newContent.Length); + stream.Position = 0; + + Assert.AreEqual(CreateHash(newContent), CreateHash(stream)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_PathAndModeAndAccess_ModeIsCreate_AccessIsReadWrite_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + #region Verify if merely opening the file for create creates a zero-byte file + + using (client.Open(remoteFile, FileMode.Create, FileAccess.ReadWrite)) + { + } + + Assert.IsTrue(client.Exists(remoteFile)); + + var attributes = client.GetAttributes(remoteFile); + Assert.IsTrue(attributes.IsRegularFile); + Assert.AreEqual(0L, attributes.Size); + + #endregion Verify if merely opening the file for create creates a zero-byte file + + client.DeleteFile(remoteFile); + + #region Verify if content is actually written to the file + + var content = GenerateRandom(size: 100); + + using (var s = client.Open(remoteFile, FileMode.Create, FileAccess.ReadWrite)) + { + s.Write(content, offset: 0, content.Length); + } + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + downloaded.Position = 0; + Assert.AreEqual(CreateHash(content), CreateHash(downloaded)); + } + + #endregion Verify if content is actually written to the file + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_PathAndModeAndAccess_ModeIsCreate_AccessIsReadWrite_ExistingFile() + { + const int fileSize = 5 * 1024; + var newContent = new byte[] { 0x07, 0x03, 0x02, 0x0b }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + using (var input = CreateMemoryStream(fileSize)) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + input.Position = 0; + client.UploadFile(input, remoteFile); + + using (var stream = client.Open(remoteFile, FileMode.Create, FileAccess.ReadWrite)) + { + // Verify if merely opening the file for create overwrites the file + var attributes = client.GetAttributes(remoteFile); + Assert.IsTrue(attributes.IsRegularFile); + Assert.AreEqual(0L, attributes.Size); + + stream.Write(newContent, offset: 0, newContent.Length); + stream.Position = 0; + + Assert.AreEqual(CreateHash(newContent), CreateHash(stream)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_PathAndModeAndAccess_ModeIsCreate_AccessIsWrite_ExistingFile() + { + // use new content that contains less bytes than original content to + // verify whether file is first truncated + var originalContent = new byte[] { 0x05, 0x0f, 0x0d, 0x0a, 0x04 }; + var newContent = new byte[] { 0x07, 0x03, 0x02, 0x0b }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllBytes(remoteFile, originalContent); + + using (var s = client.Open(remoteFile, FileMode.Create, FileAccess.Write)) + { + s.Write(newContent, offset: 0, newContent.Length); + } + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + + downloaded.Position = 0; + Assert.AreEqual(CreateHash(newContent), CreateHash(downloaded)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_PathAndModeAndAccess_ModeIsCreate_AccessIsWrite_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + #region Verify if merely opening the file for create creates a zero-byte file + + using (client.Open(remoteFile, FileMode.Create, FileAccess.Write)) + { + } + + Assert.IsTrue(client.Exists(remoteFile)); + + var attributes = client.GetAttributes(remoteFile); + Assert.IsTrue(attributes.IsRegularFile); + Assert.AreEqual(0L, attributes.Size); + + #endregion Verify if merely opening the file for create creates a zero-byte file + + client.DeleteFile(remoteFile); + + #region Verify if content is actually written to the file + + var content = GenerateRandom(size: 100); + + using (var s = client.Open(remoteFile, FileMode.Create, FileAccess.Write)) + { + s.Write(content, offset: 0, content.Length); + } + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + downloaded.Position = 0; + Assert.AreEqual(CreateHash(content), CreateHash(downloaded)); + } + + #endregion Verify if content is actually written to the file + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_CreateNew_Write_ExistingFile() + { + const int fileSize = 5 * 1024; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + using (var input = CreateMemoryStream(fileSize)) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + input.Position = 0; + + try + { + client.UploadFile(input, remoteFile); + + Stream stream = null; + + try + { + stream = client.Open(remoteFile, FileMode.CreateNew, FileAccess.Write); + Assert.Fail(); + } + catch (SshException) + { + } + finally + { + stream?.Dispose(); + } + + // Verify that the file was not modified + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + + input.Position = 0; + downloaded.Position = 0; + Assert.AreEqual(CreateHash(input), CreateHash(downloaded)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_CreateNew_Write_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + #region Verify if merely opening the file creates a zero-byte file + + using (client.Open(remoteFile, FileMode.CreateNew, FileAccess.Write)) + { + } + + Assert.IsTrue(client.Exists(remoteFile)); + + var attributes = client.GetAttributes(remoteFile); + Assert.IsTrue(attributes.IsRegularFile); + Assert.AreEqual(0L, attributes.Size); + + #endregion Verify if merely opening the file creates it + + client.DeleteFile(remoteFile); + + #region Verify if content is actually written to the file + + var content = GenerateRandom(size: 100); + + using (var s = client.Open(remoteFile, FileMode.CreateNew, FileAccess.Write)) + { + s.Write(content, offset: 0, content.Length); + } + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + downloaded.Position = 0; + Assert.AreEqual(CreateHash(content), CreateHash(downloaded)); + } + + #endregion Verify if content is actually written to the file + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_Open_Write_ExistingFile() + { + // use new content that contains less bytes than original content to + // verify whether file is first truncated + var originalContent = new byte[] { 0x05, 0x0f, 0x0d, 0x0a, 0x04 }; + var newContent = new byte[] { 0x07, 0x03, 0x02, 0x0b }; + var expectedContent = new byte[] { 0x07, 0x03, 0x02, 0x0b, 0x04 }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllBytes(remoteFile, originalContent); + + using (var s = client.Open(remoteFile, FileMode.Open, FileAccess.Write)) + { + s.Write(newContent, offset: 0, newContent.Length); + } + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + + downloaded.Position = 0; + Assert.AreEqual(CreateHash(expectedContent), CreateHash(downloaded)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_Open_Write_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + Stream stream = null; + + try + { + stream = client.Open(remoteFile, FileMode.Open, FileAccess.Write); + Assert.Fail(); + } + catch (SshException) + { + } + finally + { + stream?.Dispose(); + } + + Assert.IsFalse(client.Exists(remoteFile)); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_OpenOrCreate_Write_ExistingFile() + { + // use new content that contains less bytes than original content to + // verify whether file is first truncated + var originalContent = new byte[] { 0x05, 0x0f, 0x0d, 0x0a, 0x04 }; + var newContent = new byte[] { 0x07, 0x03, 0x02, 0x0b }; + var expectedContent = new byte[] { 0x07, 0x03, 0x02, 0x0b, 0x04 }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + client.WriteAllBytes(remoteFile, originalContent); + + using (var s = client.Open(remoteFile, FileMode.OpenOrCreate, FileAccess.Write)) + { + s.Write(newContent, offset: 0, newContent.Length); + } + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + + downloaded.Position = 0; + Assert.AreEqual(CreateHash(expectedContent), CreateHash(downloaded)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_OpenOrCreate_Write_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + #region Verify if merely opening the file creates a zero-byte file + + using (client.Open(remoteFile, FileMode.OpenOrCreate, FileAccess.Write)) + { + } + + Assert.IsTrue(client.Exists(remoteFile)); + + var attributes = client.GetAttributes(remoteFile); + Assert.IsTrue(attributes.IsRegularFile); + Assert.AreEqual(0L, attributes.Size); + + #endregion Verify if merely opening the file creates it + + client.DeleteFile(remoteFile); + + #region Verify if content is actually written to the file + + var content = GenerateRandom(size: 100); + + using (var s = client.Open(remoteFile, FileMode.OpenOrCreate, FileAccess.Write)) + { + s.Write(content, offset: 0, content.Length); + } + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + downloaded.Position = 0; + Assert.AreEqual(CreateHash(content), CreateHash(downloaded)); + } + + #endregion Verify if content is actually written to the file + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + + + + + + + [TestMethod] + public void Sftp_Open_Truncate_Write_ExistingFile() + { + const int fileSize = 5 * 1024; + + // use new content that contains less bytes than original content to + // verify whether file is first truncated + var originalContent = new byte[] { 0x05, 0x0f, 0x0d, 0x0a, 0x04 }; + var newContent = new byte[] { 0x07, 0x03, 0x02, 0x0b }; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + using (var input = CreateMemoryStream(fileSize)) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + input.Position = 0; + + try + { + client.WriteAllBytes(remoteFile, originalContent); + + using (var s = client.Open(remoteFile, FileMode.Truncate, FileAccess.Write)) + { + s.Write(newContent, offset: 0, newContent.Length); + } + + using (var downloaded = new MemoryStream()) + { + client.DownloadFile(remoteFile, downloaded); + + input.Position = 0; + downloaded.Position = 0; + Assert.AreEqual(CreateHash(newContent), CreateHash(downloaded)); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_Open_Truncate_Write_FileDoesNotExist() + { + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + try + { + Stream stream = null; + + try + { + stream = client.Open(remoteFile, FileMode.Truncate, FileAccess.Write); + Assert.Fail(); + } + catch (SshException) + { + } + + Assert.IsFalse(client.Exists(remoteFile)); + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + [TestMethod] + public void Sftp_OpenRead() + { + const int fileSize = 5 * 1024 * 1024; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var remoteFile = GenerateUniqueRemoteFileName(); + + SftpCreateRemoteFile(client, remoteFile, fileSize); + + try + { + using (var s = client.OpenRead(remoteFile)) + { + var buffer = new byte[s.Length]; + + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + var bytesRead = s.Read(buffer, offset: 0, buffer.Length); + + stopwatch.Stop(); + + var transferSpeed = CalculateTransferSpeed(bytesRead, stopwatch.ElapsedMilliseconds); + Console.WriteLine(@"Elapsed: {0} ms", stopwatch.ElapsedMilliseconds); + Console.WriteLine(@"Transfer speed: {0:N2} KB/s", transferSpeed); + + Assert.AreEqual(fileSize, bytesRead); + } + } + finally + { + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + } + } + } + + private static IEnumerable GetSftpUploadFileFileStreamData() + { + yield return new object[] { 0 }; + yield return new object[] { 5 * 1024 * 1024 }; + } + + private static Encoding GetRandomEncoding() + { + var random = new Random().Next(1, 3); + switch (random) + { + case 1: + return Encoding.Unicode; + case 2: + return Encoding.UTF8; + case 3: + return Encoding.UTF32; + default: + throw new NotImplementedException(); + } + } + + private static byte[] GetBytesWithPreamble(string text, Encoding encoding) + { + var preamble = encoding.GetPreamble(); + var textBytes = encoding.GetBytes(text); + + if (preamble.Length != 0) + { + var textAndPreambleBytes = new byte[preamble.Length + textBytes.Length]; + Buffer.BlockCopy(preamble, srcOffset: 0, textAndPreambleBytes, dstOffset: 0, preamble.Length); + Buffer.BlockCopy(textBytes, srcOffset: 0, textAndPreambleBytes, preamble.Length, textBytes.Length); + return textAndPreambleBytes; + } + + return textBytes; + } + + private static Stream GetResourceStream(string resourceName) + { + var type = typeof(SftpTests); + var resourceStream = type.Assembly.GetManifestResourceStream(resourceName); + if (resourceStream == null) + { + throw new ArgumentException($"Resource '{resourceName}' not found in assembly '{type.Assembly.FullName}'.", nameof(resourceName)); + } + return resourceStream; + } + + private static decimal CalculateTransferSpeed(long length, long elapsedMilliseconds) + { + return (length / 1024m) / (elapsedMilliseconds / 1000m); + } + + private static void SftpCreateRemoteFile(SftpClient client, string remoteFile, int size) + { + var file = CreateTempFile(size); + + try + { + using (var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + client.UploadFile(fs, remoteFile); + } + } + finally + { + File.Delete(file); + } + } + + private static byte[] GenerateRandom(int size) + { + var random = new Random(); + var randomContent = new byte[size]; + random.NextBytes(randomContent); + return randomContent; + } + + private static Stream CreateStreamWithContent(string content) + { + var memoryStream = new MemoryStream(); + var sw = new StreamWriter(memoryStream, Encoding.ASCII, 1024); + sw.Write(content); + sw.Flush(); + memoryStream.Position = 0; + return memoryStream; + } + + private static string GenerateUniqueRemoteFileName() + { + return $"/home/sshnet/{Guid.NewGuid():D}"; + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/SshClientTests.cs b/src/Renci.SshNet.IntegrationTests/SshClientTests.cs index 867514441..b737b343f 100644 --- a/src/Renci.SshNet.IntegrationTests/SshClientTests.cs +++ b/src/Renci.SshNet.IntegrationTests/SshClientTests.cs @@ -1,6 +1,4 @@ -using Renci.SshNet; - -namespace IntegrationTests +namespace Renci.SshNet.IntegrationTests { /// /// The SSH client integration tests diff --git a/src/Renci.SshNet.IntegrationTests/SshConnectionDisruptor.cs b/src/Renci.SshNet.IntegrationTests/SshConnectionDisruptor.cs new file mode 100644 index 000000000..741134114 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/SshConnectionDisruptor.cs @@ -0,0 +1,41 @@ +锘縩amespace Renci.SshNet.IntegrationTests +{ + internal class SshConnectionDisruptor + { + private readonly IConnectionInfoFactory _connectionInfoFactory; + + public SshConnectionDisruptor(IConnectionInfoFactory connectionInfoFactory) + { + _connectionInfoFactory = connectionInfoFactory; + } + + public SshConnectionRestorer BreakConnections() + { + var client = new SshClient(_connectionInfoFactory.Create()); + + client.Connect(); + + PauseSshd(client); + + return new SshConnectionRestorer(client); + } + + private static void PauseSshd(SshClient client) + { + var command = client.CreateCommand("sudo echo 'DenyUsers sshnet' >> /etc/ssh/sshd_config"); + var output = command.Execute(); + if (command.ExitStatus != 0) + { + throw new ApplicationException( + $"Blocking user sshnet failed with exit code {command.ExitStatus}.\r\n{output}\r\n{command.Error}"); + } + command = client.CreateCommand("sudo pkill -9 -U sshnet -f sshd.pam"); + output = command.Execute(); + if (command.ExitStatus != 0) + { + throw new ApplicationException( + $"Killing sshd.pam service failed with exit code {command.ExitStatus}.\r\n{output}\r\n{command.Error}"); + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/SshConnectionRestorer.cs b/src/Renci.SshNet.IntegrationTests/SshConnectionRestorer.cs new file mode 100644 index 000000000..d7c6437db --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/SshConnectionRestorer.cs @@ -0,0 +1,36 @@ +锘縩amespace Renci.SshNet.IntegrationTests +{ + internal class SshConnectionRestorer : IDisposable + { + private SshClient _sshClient; + + public SshConnectionRestorer(SshClient sshClient) + { + _sshClient = sshClient; + } + + public void RestoreConnections() + { + var command = _sshClient.CreateCommand("sudo sed -i '/DenyUsers sshnet/d' /etc/ssh/sshd_config"); + var output = command.Execute(); + if (command.ExitStatus != 0) + { + throw new ApplicationException( + $"Unblocking user sshnet failed with exit code {command.ExitStatus}.\r\n{output}\r\n{command.Error}"); + } + command = _sshClient.CreateCommand("sudo /usr/sbin/sshd.pam"); + output = command.Execute(); + if (command.ExitStatus != 0) + { + throw new ApplicationException( + $"Resuming ssh service failed with exit code {command.ExitStatus}.\r\n{output}\r\n{command.Error}"); + } + } + + public void Dispose() + { + _sshClient?.Dispose(); + _sshClient = null; + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/SshTests.cs b/src/Renci.SshNet.IntegrationTests/SshTests.cs new file mode 100644 index 000000000..5f3e58984 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/SshTests.cs @@ -0,0 +1,972 @@ +锘縰sing System.ComponentModel; +using System.Net; +using System.Net.Sockets; + +using Renci.SshNet.Common; +using Renci.SshNet.IntegrationTests.Common; + +namespace Renci.SshNet.IntegrationTests +{ + [TestClass] + public class SshTests : TestBase + { + private IConnectionInfoFactory _connectionInfoFactory; + private IConnectionInfoFactory _adminConnectionInfoFactory; + private RemoteSshdConfig _remoteSshdConfig; + + [TestInitialize] + public void SetUp() + { + _connectionInfoFactory = new LinuxVMConnectionFactory(SshServerHostName, SshServerPort); + _adminConnectionInfoFactory = new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort); + + _remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig(); + _remoteSshdConfig.AllowTcpForwarding() + .PrintMotd(false) + .Update() + .Restart(); + } + + [TestCleanup] + public void TearDown() + { + _remoteSshdConfig?.Reset(); + } + + /// + /// Test for a channel that is being closed by the server. + /// + [TestMethod] + public void Ssh_ShellStream_Exit() + { + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var terminalModes = new Dictionary + { + { TerminalModes.ECHO, 0 } + }; + + using (var shellStream = client.CreateShellStream("xterm", 80, 24, 800, 600, 1024, terminalModes)) + { + shellStream.WriteLine("echo Hello!"); + shellStream.WriteLine("exit"); + + Thread.Sleep(1000); + + try + { + shellStream.Write("ABC"); + Assert.Fail(); + } + catch (ObjectDisposedException ex) + { + Assert.IsNull(ex.InnerException); + Assert.AreEqual("ShellStream", ex.ObjectName); + Assert.AreEqual($"Cannot access a disposed object.{Environment.NewLine}Object name: '{ex.ObjectName}'.", ex.Message); + } + + var line = shellStream.ReadLine(); + Assert.IsNotNull(line); + Assert.IsTrue(line.EndsWith("Hello!"), line); + + // TODO: ReadLine should return null when the buffer is empty and the channel has been closed (issue #672) + try + { + line = shellStream.ReadLine(); + Assert.Fail(line); + } + catch (NullReferenceException) + { + + } + } + } + } + + /// + /// https://github.com/sshnet/SSH.NET/issues/63 + /// + [TestMethod] + [Category("Reproduction Tests")] + [Ignore] + public void Ssh_ShellStream_IntermittendOutput() + { + const string remoteFile = "/home/sshnet/test.sh"; + + var expectedResult = string.Join("\n", + "Line 1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "Line 2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "Line 4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "Line 5 ", + "Line 6"); + + var scriptBuilder = new StringBuilder(); + scriptBuilder.Append("#!/bin/sh\n"); + scriptBuilder.Append("echo Line 1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + scriptBuilder.Append("sleep .5\n"); + scriptBuilder.Append("echo Line 2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + scriptBuilder.Append("echo Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + scriptBuilder.Append("echo Line 4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + scriptBuilder.Append("sleep 2\n"); + scriptBuilder.Append("echo \"Line 5 \"\n"); + scriptBuilder.Append("echo Line 6 \n"); + scriptBuilder.Append("exit 13\n"); + + using (var sshClient = new SshClient(_connectionInfoFactory.Create())) + { + sshClient.Connect(); + + CreateShellScript(_connectionInfoFactory, remoteFile, scriptBuilder.ToString()); + + try + { + var terminalModes = new Dictionary + { + { TerminalModes.ECHO, 0 } + }; + + using (var shellStream = sshClient.CreateShellStream("xterm", 80, 24, 800, 600, 1024, terminalModes)) + { + shellStream.WriteLine(remoteFile); + Thread.Sleep(1200); + using (var reader = new StreamReader(shellStream, new UTF8Encoding(false), false, 10)) + { + var lines = new List(); + string line = null; + while ((line = reader.ReadLine()) != null) + { + lines.Add(line); + } + Assert.AreEqual(6, lines.Count, string.Join("\n", lines)); + Assert.AreEqual(expectedResult, string.Join("\n", lines)); + } + } + } + finally + { + RemoveFileOrDirectory(sshClient, remoteFile); + } + } + } + + /// + /// Issue 1555 + /// + [TestMethod] + public void Ssh_CreateShell() + { + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var input = new MemoryStream()) + using (var output = new MemoryStream()) + using (var extOutput = new MemoryStream()) + { + var shell = client.CreateShell(input, output, extOutput); + shell.Start(); + + var inputWriter = new StreamWriter(input, Encoding.ASCII, 1024); + inputWriter.WriteLine("echo $PATH"); + + var outputReader = new StreamReader(output, Encoding.ASCII, false, 1024); + Console.WriteLine(outputReader.ReadToEnd()); + + shell.Stop(); + } + } + } + + [TestMethod] + public void Ssh_Command_IntermittendOutput_EndExecute() + { + const string remoteFile = "/home/sshnet/test.sh"; + + var expectedResult = string.Join("\n", + "Line 1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "Line 2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "Line 4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "Line 5 ", + "Line 6", + ""); + + var scriptBuilder = new StringBuilder(); + scriptBuilder.Append("#!/bin/sh\n"); + scriptBuilder.Append("echo Line 1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + scriptBuilder.Append("sleep .5\n"); + scriptBuilder.Append("echo Line 2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + scriptBuilder.Append("echo Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + scriptBuilder.Append("echo Line 4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + scriptBuilder.Append("sleep 2\n"); + scriptBuilder.Append("echo \"Line 5 \"\n"); + scriptBuilder.Append("echo Line 6 \n"); + scriptBuilder.Append("exit 13\n"); + + using (var sshClient = new SshClient(_connectionInfoFactory.Create())) + { + sshClient.Connect(); + + CreateShellScript(_connectionInfoFactory, remoteFile, scriptBuilder.ToString()); + + try + { + using (var cmd = sshClient.CreateCommand("chmod 777 " + remoteFile)) + { + cmd.Execute(); + + Assert.AreEqual(0, cmd.ExitStatus, cmd.Error); + } + + using (var command = sshClient.CreateCommand(remoteFile)) + { + var asyncResult = command.BeginExecute(); + var actualResult = command.EndExecute(asyncResult); + + Assert.AreEqual(expectedResult, actualResult); + Assert.AreEqual(expectedResult, command.Result); + Assert.AreEqual(13, command.ExitStatus); + } + } + finally + { + RemoveFileOrDirectory(sshClient, remoteFile); + } + } + } + + /// + /// Ignored for now, because: + /// * OutputStream.Read(...) does not block when no data is available + /// * SshCommand.(Begin)Execute consumes *OutputStream*, advancing its position. + /// + /// https://github.com/sshnet/SSH.NET/issues/650 + /// + [TestMethod] + [Ignore] + public void Ssh_Command_IntermittendOutput_OutputStream() + { + const string remoteFile = "/home/sshnet/test.sh"; + + var expectedResult = string.Join("\n", + "Line 1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "Line 2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "Line 4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "Line 5 ", + "Line 6"); + + var scriptBuilder = new StringBuilder(); + scriptBuilder.Append("#!/bin/sh\n"); + scriptBuilder.Append("echo Line 1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + scriptBuilder.Append("sleep .5\n"); + scriptBuilder.Append("echo Line 2 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + scriptBuilder.Append("echo Line 3 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + scriptBuilder.Append("echo Line 4 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"); + scriptBuilder.Append("sleep 2\n"); + scriptBuilder.Append("echo \"Line 5 \"\n"); + scriptBuilder.Append("echo Line 6 \n"); + scriptBuilder.Append("exit 13\n"); + + using (var sshClient = new SshClient(_connectionInfoFactory.Create())) + { + sshClient.Connect(); + + CreateShellScript(_connectionInfoFactory, remoteFile, scriptBuilder.ToString()); + + try + { + using (var cmd = sshClient.CreateCommand("chmod 777 " + remoteFile)) + { + cmd.Execute(); + + Assert.AreEqual(0, cmd.ExitStatus, cmd.Error); + } + + using (var command = sshClient.CreateCommand(remoteFile)) + { + var asyncResult = command.BeginExecute(); + + using (var reader = new StreamReader(command.OutputStream, new UTF8Encoding(false), false, 10)) + { + var lines = new List(); + string line = null; + while ((line = reader.ReadLine()) != null) + { + lines.Add(line); + } + + Assert.AreEqual(6, lines.Count, string.Join("\n", lines)); + Assert.AreEqual(expectedResult, string.Join("\n", lines)); + Assert.AreEqual(13, command.ExitStatus); + } + + var actualResult = command.EndExecute(asyncResult); + + Assert.AreEqual(expectedResult, actualResult); + Assert.AreEqual(expectedResult, command.Result); + } + } + finally + { + RemoveFileOrDirectory(sshClient, remoteFile); + } + } + } + + [TestMethod] + public void Ssh_DynamicPortForwarding_DisposeSshClientWithoutStoppingPort() + { + const string searchText = "HTTP/1.1 301 Moved Permanently"; + const string hostName = "github.com"; + + var httpGetRequest = Encoding.ASCII.GetBytes($"GET / HTTP/1.1\r\nHost: {hostName}\r\n\r\n"); + Socket socksSocket; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.ConnectionInfo.Timeout = TimeSpan.FromSeconds(200); + client.Connect(); + + var forwardedPort = new ForwardedPortDynamic(1080); + forwardedPort.Exception += (sender, args) => Console.WriteLine(args.Exception.ToString()); + client.AddForwardedPort(forwardedPort); + forwardedPort.Start(); + + var socksClient = new Socks5Handler(new IPEndPoint(IPAddress.Loopback, 1080), + string.Empty, + string.Empty); + + socksSocket = socksClient.Connect(hostName, 80); + socksSocket.Send(httpGetRequest); + + var httpResponse = GetHttpResponse(socksSocket, Encoding.ASCII); + Assert.IsTrue(httpResponse.Contains(searchText), httpResponse); + } + + Assert.IsTrue(socksSocket.Connected); + + // check if client socket was properly closed + Assert.AreEqual(0, socksSocket.Receive(new byte[1], 0, 1, SocketFlags.None)); + } + + [TestMethod] + public void Ssh_DynamicPortForwarding_DomainName() + { + const string searchText = "HTTP/1.1 301 Moved Permanently"; + const string hostName = "github.com"; + + // Set-up a host alias for google.be on the remote server that is not known locally; this allows us to + // verify whether the host name is resolved remotely. + const string hostNameAlias = "dynamicportforwarding-test.for.sshnet"; + + // Construct a HTTP request for which we expected the response to contain the search text. + var httpGetRequest = Encoding.ASCII.GetBytes($"GET / HTTP/1.1\r\nHost: {hostName}\r\n\r\n"); + + var ipAddresses = Dns.GetHostAddresses(hostName); + var hostsFileUpdated = AddOrUpdateHostsEntry(_adminConnectionInfoFactory, ipAddresses[0], hostNameAlias); + + try + { + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.ConnectionInfo.Timeout = TimeSpan.FromSeconds(200); + client.Connect(); + + var forwardedPort = new ForwardedPortDynamic(1080); + forwardedPort.Exception += (sender, args) => Console.WriteLine(args.Exception.ToString()); + client.AddForwardedPort(forwardedPort); + forwardedPort.Start(); + + var socksClient = new Socks5Handler(new IPEndPoint(IPAddress.Loopback, 1080), + string.Empty, + string.Empty); + var socksSocket = socksClient.Connect(hostNameAlias, 80); + + socksSocket.Send(httpGetRequest); + var httpResponse = GetHttpResponse(socksSocket, Encoding.ASCII); + Assert.IsTrue(httpResponse.Contains(searchText), httpResponse); + + // Verify if port is still open + socksSocket.Send(httpGetRequest); + GetHttpResponse(socksSocket, Encoding.ASCII); + + forwardedPort.Stop(); + + Assert.IsTrue(socksSocket.Connected); + + // check if client socket was properly closed + Assert.AreEqual(0, socksSocket.Receive(new byte[1], 0, 1, SocketFlags.None)); + + forwardedPort.Start(); + + // create new SOCKS connection and very whether the forwarded port is functional again + socksSocket = socksClient.Connect(hostNameAlias, 80); + + socksSocket.Send(httpGetRequest); + httpResponse = GetHttpResponse(socksSocket, Encoding.ASCII); + Assert.IsTrue(httpResponse.Contains(searchText), httpResponse); + + forwardedPort.Dispose(); + + Assert.IsTrue(socksSocket.Connected); + + // check if client socket was properly closed + Assert.AreEqual(0, socksSocket.Receive(new byte[1], 0, 1, SocketFlags.None)); + + forwardedPort.Dispose(); + } + } + finally + { + if (hostsFileUpdated) + { + RemoveHostsEntry(_adminConnectionInfoFactory, ipAddresses[0], hostNameAlias); + } + } + } + + [TestMethod] + public void Ssh_DynamicPortForwarding_IPv4() + { + const string searchText = "HTTP/1.1 301 Moved Permanently"; + const string hostName = "github.com"; + + var httpGetRequest = Encoding.ASCII.GetBytes($"GET /null HTTP/1.1\r\nHost: {hostName}\r\n\r\n"); + + var ipv4 = Dns.GetHostAddresses(hostName).FirstOrDefault(p => p.AddressFamily == AddressFamily.InterNetwork); + Assert.IsNotNull(ipv4, $@"No IPv4 address found for '{hostName}'."); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.ConnectionInfo.Timeout = TimeSpan.FromSeconds(200); + client.Connect(); + + var forwardedPort = new ForwardedPortDynamic(1080); + forwardedPort.Exception += (sender, args) => Console.WriteLine(args.Exception.ToString()); + client.AddForwardedPort(forwardedPort); + forwardedPort.Start(); + + var socksClient = new Socks5Handler(new IPEndPoint(IPAddress.Loopback, 1080), + string.Empty, + string.Empty); + var socksSocket = socksClient.Connect(new IPEndPoint(ipv4, 80)); + + socksSocket.Send(httpGetRequest); + var httpResponse = GetHttpResponse(socksSocket, Encoding.ASCII); + Assert.IsTrue(httpResponse.Contains(searchText), httpResponse); + + forwardedPort.Dispose(); + + // check if client socket was properly closed + Assert.AreEqual(0, socksSocket.Receive(new byte[1], 0, 1, SocketFlags.None)); + } + } + + /// + /// Verifies whether channels are effectively closed. + /// + [TestMethod] + public void Ssh_LocalPortForwardingCloseChannels() + { + const string hostNameAlias = "localportforwarding-test.for.sshnet"; + const string hostName = "github.com"; + + var ipAddress = Dns.GetHostAddresses(hostName)[0]; + + var hostsFileUpdated = AddOrUpdateHostsEntry(_adminConnectionInfoFactory, ipAddress, hostNameAlias); + + try + { + var connectionInfo = _connectionInfoFactory.Create(); + connectionInfo.MaxSessions = 1; + + using (var client = new SshClient(connectionInfo)) + { + client.Connect(); + + var localEndPoint = new IPEndPoint(IPAddress.Loopback, 1225); + + for (var i = 0; i < (connectionInfo.MaxSessions + 1); i++) + { + var forwardedPort = new ForwardedPortLocal(localEndPoint.Address.ToString(), + (uint)localEndPoint.Port, + hostNameAlias, + 80); + client.AddForwardedPort(forwardedPort); + forwardedPort.Start(); + + try + { + var httpRequest = (HttpWebRequest) WebRequest.Create("http://" + localEndPoint); + httpRequest.Host = hostName; + httpRequest.Method = "GET"; + httpRequest.AllowAutoRedirect = false; + + try + { + using (var httpResponse = (HttpWebResponse)httpRequest.GetResponse()) + { + Assert.AreEqual(HttpStatusCode.MovedPermanently, httpResponse.StatusCode); + } + } + catch (WebException ex) + { + Assert.AreEqual(WebExceptionStatus.ProtocolError, ex.Status); + Assert.IsNotNull(ex.Response); + + using (var httpResponse = ex.Response as HttpWebResponse) + { + Assert.IsNotNull(httpResponse); + Assert.AreEqual(HttpStatusCode.MovedPermanently, httpResponse.StatusCode); + } + } + } + finally + { + client.RemoveForwardedPort(forwardedPort); + } + } + } + } + finally + { + if (hostsFileUpdated) + { + RemoveHostsEntry(_adminConnectionInfoFactory, ipAddress, hostNameAlias); + } + } + } + + [TestMethod] + public void Ssh_LocalPortForwarding() + { + const string hostNameAlias = "localportforwarding-test.for.sshnet"; + const string hostName = "github.com"; + + var ipAddress = Dns.GetHostAddresses(hostName)[0]; + + var hostsFileUpdated = AddOrUpdateHostsEntry(_adminConnectionInfoFactory, ipAddress, hostNameAlias); + + try + { + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + var localEndPoint = new IPEndPoint(IPAddress.Loopback, 1225); + + var forwardedPort = new ForwardedPortLocal(localEndPoint.Address.ToString(), + (uint)localEndPoint.Port, + hostNameAlias, + 80); + forwardedPort.Exception += + (sender, args) => Console.WriteLine(@"ForwardedPort exception: " + args.Exception); + client.AddForwardedPort(forwardedPort); + forwardedPort.Start(); + + try + { + var httpRequest = (HttpWebRequest) WebRequest.Create("http://" + localEndPoint); + httpRequest.Host = hostName; + httpRequest.Method = "GET"; + httpRequest.Accept = "text/html"; + httpRequest.AllowAutoRedirect = false; + + try + { + using (var httpResponse = (HttpWebResponse)httpRequest.GetResponse()) + { + Assert.AreEqual(HttpStatusCode.MovedPermanently, httpResponse.StatusCode); + } + } + catch (WebException ex) + { + Assert.AreEqual(WebExceptionStatus.ProtocolError, ex.Status); + Assert.IsNotNull(ex.Response); + + using (var httpResponse = ex.Response as HttpWebResponse) + { + Assert.IsNotNull(httpResponse); + Assert.AreEqual(HttpStatusCode.MovedPermanently, httpResponse.StatusCode); + } + } + } + finally + { + client.RemoveForwardedPort(forwardedPort); + } + } + } + finally + { + if (hostsFileUpdated) + { + RemoveHostsEntry(_adminConnectionInfoFactory, ipAddress, hostNameAlias); + } + } + } + + [TestMethod] + public void Ssh_RemotePortForwarding() + { + var hostAddresses = Dns.GetHostAddresses(Dns.GetHostName()); + var ipv4HostAddress = hostAddresses.First(p => p.AddressFamily == AddressFamily.InterNetwork); + + var endpoint1 = new IPEndPoint(ipv4HostAddress, 666); + var endpoint2 = new IPEndPoint(ipv4HostAddress, 667); + + var bytesReceivedOnListener1 = new List(); + var bytesReceivedOnListener2 = new List(); + + using (var socketListener1 = new AsyncSocketListener(endpoint1)) + using (var socketListener2 = new AsyncSocketListener(endpoint2)) + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + socketListener1.BytesReceived += (received, socket) => bytesReceivedOnListener1.AddRange(received); + socketListener1.Start(); + + socketListener2.BytesReceived += (received, socket) => bytesReceivedOnListener2.AddRange(received); + socketListener2.Start(); + + client.Connect(); + + var forwardedPort1 = new ForwardedPortRemote(IPAddress.Loopback, + 10000, + endpoint1.Address, + (uint)endpoint1.Port); + forwardedPort1.Exception += (sender, args) => Console.WriteLine(@"forwardedPort1 exception: " + args.Exception); + client.AddForwardedPort(forwardedPort1); + forwardedPort1.Start(); + + var forwardedPort2 = new ForwardedPortRemote(IPAddress.Loopback, + 10001, + endpoint2.Address, + (uint)endpoint2.Port); + forwardedPort2.Exception += (sender, args) => Console.WriteLine(@"forwardedPort2 exception: " + args.Exception); + client.AddForwardedPort(forwardedPort2); + forwardedPort2.Start(); + + using (var s = client.CreateShellStream("a", 80, 25, 800, 600, 200)) + { + s.WriteLine($"telnet {forwardedPort1.BoundHost} {forwardedPort1.BoundPort}"); + s.Expect($"Connected to {forwardedPort1.BoundHost}\r\n"); + s.WriteLine("ABC"); + s.Flush(); + s.Expect("ABC"); + s.Close(); + } + + using (var s = client.CreateShellStream("b", 80, 25, 800, 600, 200)) + { + s.WriteLine($"telnet {forwardedPort2.BoundHost} {forwardedPort2.BoundPort}"); + s.Expect($"Connected to {forwardedPort2.BoundHost}\r\n"); + s.WriteLine("DEF"); + s.Flush(); + s.Expect("DEF"); + s.Close(); + } + + forwardedPort1.Stop(); + forwardedPort2.Stop(); + } + + var textReceivedOnListener1 = Encoding.ASCII.GetString(bytesReceivedOnListener1.ToArray()); + Assert.AreEqual("ABC\r\n", textReceivedOnListener1); + + var textReceivedOnListener2 = Encoding.ASCII.GetString(bytesReceivedOnListener2.ToArray()); + Assert.AreEqual("DEF\r\n", textReceivedOnListener2); + } + + /// + /// Issue 1591 + /// + [TestMethod] + public void Ssh_ExecuteShellScript() + { + const string remoteFile = "/home/sshnet/run.sh"; + const string content = "#\bin\bash\necho Hello World!"; + + using (var client = new SftpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + if (client.Exists(remoteFile)) + { + client.DeleteFile(remoteFile); + } + + using (var memoryStream = new MemoryStream()) + using (var sw = new StreamWriter(memoryStream, Encoding.ASCII)) + { + sw.Write(content); + sw.Flush(); + memoryStream.Position = 0; + client.UploadFile(memoryStream, remoteFile); + } + } + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + try + { + var runChmod = client.RunCommand("chmod u+x " + remoteFile); + runChmod.Execute(); + Assert.AreEqual(0, runChmod.ExitStatus, runChmod.Error); + + var runLs = client.RunCommand("ls " + remoteFile); + var asyncResultLs = runLs.BeginExecute(); + + var runScript = client.RunCommand(remoteFile); + var asyncResultScript = runScript.BeginExecute(); + + Assert.IsTrue(asyncResultScript.AsyncWaitHandle.WaitOne(10000)); + var resultScript = runScript.EndExecute(asyncResultScript); + Assert.AreEqual("Hello World!\n", resultScript); + + Assert.IsTrue(asyncResultLs.AsyncWaitHandle.WaitOne(10000)); + var resultLs = runLs.EndExecute(asyncResultLs); + Assert.AreEqual(remoteFile + "\n", resultLs); + } + finally + { + RemoveFileOrDirectory(client, remoteFile); + } + } + } + + /// + /// Verifies if a hosts file contains an entry for a given combination of IP address and hostname, + /// and if necessary add either the host entry or an alias to an exist entry for the specified IP + /// address. + /// + /// + /// + /// + /// + /// if an entry was added or updated in the specified hosts file; otherwise, + /// . + /// + private static bool AddOrUpdateHostsEntry(IConnectionInfoFactory linuxAdminConnectionFactory, + IPAddress ipAddress, + string hostName) + { + const string hostsFile = "/etc/hosts"; + + using (var client = new ScpClient(linuxAdminConnectionFactory.Create())) + { + client.Connect(); + + var hostConfig = HostConfig.Read(client, hostsFile); + + var hostEntry = hostConfig.Entries.SingleOrDefault(h => h.IPAddress.Equals(ipAddress)); + if (hostEntry != null) + { + if (hostEntry.HostName == hostName) + { + return false; + } + + foreach (var alias in hostEntry.Aliases) + { + if (alias == hostName) + { + return false; + } + } + + hostEntry.Aliases.Add(hostName); + } + else + { + bool mappingFound = false; + + for (var i = (hostConfig.Entries.Count - 1); i >= 0; i--) + { + hostEntry = hostConfig.Entries[i]; + + if (hostEntry.HostName == hostName) + { + if (hostEntry.IPAddress.Equals(ipAddress)) + { + mappingFound = true; + continue; + } + + // If hostname is currently mapped to another IP address, then remove the + // current mapping + hostConfig.Entries.RemoveAt(i); + } + else + { + for (var j = (hostEntry.Aliases.Count - 1); j >= 0; j--) + { + var alias = hostEntry.Aliases[j]; + + if (alias == hostName) + { + hostEntry.Aliases.RemoveAt(j); + } + } + } + } + + if (!mappingFound) + { + hostEntry = new HostEntry(ipAddress, hostName); + hostConfig.Entries.Add(hostEntry); + } + } + + hostConfig.Write(client, hostsFile); + return true; + } + } + + /// + /// Remove the mapping between a given IP address and host name from the remote hosts file either by + /// removing a host entry entirely (if no other aliases are defined for the IP address) or removing + /// the aliases that match the host name for the IP address. + /// + /// + /// + /// + /// + /// if the hosts file was updated; otherwise, . + /// + private static bool RemoveHostsEntry(IConnectionInfoFactory linuxAdminConnectionFactory, + IPAddress ipAddress, + string hostName) + { + const string hostsFile = "/etc/hosts"; + + using (var client = new ScpClient(linuxAdminConnectionFactory.Create())) + { + client.Connect(); + + var hostConfig = HostConfig.Read(client, hostsFile); + + var hostEntry = hostConfig.Entries.SingleOrDefault(h => h.IPAddress.Equals(ipAddress)); + if (hostEntry == null) + { + return false; + } + + if (hostEntry.HostName == hostName) + { + if (hostEntry.Aliases.Count == 0) + { + hostConfig.Entries.Remove(hostEntry); + } + else + { + // Use one of the aliases (that are different from the specified host name) as host name + // of the host entry. + + for (var i = hostEntry.Aliases.Count - 1; i >= 0; i--) + { + var alias = hostEntry.Aliases[i]; + if (alias == hostName) + { + hostEntry.Aliases.RemoveAt(i); + } + else if (hostEntry.HostName == hostName) + { + // If we haven't already used one of the aliases as host name of the host entry + // then do this now and remove the alias. + + hostEntry.HostName = alias; + hostEntry.Aliases.RemoveAt(i); + } + } + + // If for some reason the host name of the host entry matched the specified host name + // and it only had aliases that match the host name, then remove the host entry altogether. + if (hostEntry.Aliases.Count == 0 && hostEntry.HostName == hostName) + { + hostConfig.Entries.Remove(hostEntry); + } + } + } + else + { + var aliasRemoved = false; + + for (var i = hostEntry.Aliases.Count - 1; i >= 0; i--) + { + if (hostEntry.Aliases[i] == hostName) + { + hostEntry.Aliases.RemoveAt(i); + aliasRemoved = true; + } + } + + if (!aliasRemoved) + { + return false; + } + } + + hostConfig.Write(client, hostsFile); + return true; + } + } + + private static string GetHttpResponse(Socket socket, Encoding encoding) + { + var httpResponseBuffer = new byte[2048]; + + // We expect: + // * The response to contain the searchText in the first receive. + // * The full response to be returned in the first receive. + + var bytesReceived = socket.Receive(httpResponseBuffer, + 0, + httpResponseBuffer.Length, + SocketFlags.None); + if (bytesReceived == 0) + { + return null; + } + + if (bytesReceived == httpResponseBuffer.Length) + { + throw new Exception("We expect the HTTP response to be less than the buffer size. If not, we won't consume the full response."); + } + + using (var sr = new StringReader(encoding.GetString(httpResponseBuffer, 0, bytesReceived))) + { + return sr.ReadToEnd(); + } + } + + private static void CreateShellScript(IConnectionInfoFactory connectionInfoFactory, string remoteFile, string script) + { + using (var sftpClient = new SftpClient(connectionInfoFactory.Create())) + { + sftpClient.Connect(); + + using (var sw = sftpClient.CreateText(remoteFile, new UTF8Encoding(false))) + { + sw.Write(script); + } + + sftpClient.ChangePermissions(remoteFile, 0x1FF); + } + } + + private static void RemoveFileOrDirectory(SshClient client, string remoteFile) + { + using (var cmd = client.CreateCommand("rm -Rf " + remoteFile)) + { + cmd.Execute(); + Assert.AreEqual(0, cmd.ExitStatus, cmd.Error); + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/TestBase.cs b/src/Renci.SshNet.IntegrationTests/TestBase.cs new file mode 100644 index 000000000..511bb144d --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/TestBase.cs @@ -0,0 +1,80 @@ +锘縰sing System.Security.Cryptography; + +namespace Renci.SshNet.IntegrationTests +{ + public abstract class TestBase : IntegrationTestBase + { + protected static MemoryStream CreateMemoryStream(int size) + { + var memoryStream = new MemoryStream(); + FillStream(memoryStream, size); + return memoryStream; + } + + protected static void FillStream(Stream stream, int size) + { + var randomContent = new byte[50]; + var random = new Random(); + + var numberOfBytesToWrite = size; + + while (numberOfBytesToWrite > 0) + { + random.NextBytes(randomContent); + + var numberOfCharsToWrite = Math.Min(numberOfBytesToWrite, randomContent.Length); + stream.Write(randomContent, 0, numberOfCharsToWrite); + numberOfBytesToWrite -= numberOfCharsToWrite; + } + } + + protected static string CreateHash(Stream stream) + { + MD5 md5 = new MD5CryptoServiceProvider(); + var hash = md5.ComputeHash(stream); + return Encoding.ASCII.GetString(hash); + } + + protected static string CreateHash(byte[] buffer) + { + using (var ms = new MemoryStream(buffer)) + { + return CreateHash(ms); + } + } + + protected static string CreateFileHash(string path) + { + using (var fs = File.OpenRead(path)) + { + return CreateHash(fs); + } + } + + protected static string CreateTempFile(int size) + { + var file = Path.GetTempFileName(); + CreateFile(file, size); + return file; + } + + protected static void CreateFile(string fileName, int size) + { + using (var fs = File.OpenWrite(fileName)) + { + FillStream(fs, size); + } + } + + protected Stream GetManifestResourceStream(string resourceName) + { + var type = GetType(); + var resourceStream = type.Assembly.GetManifestResourceStream(resourceName); + if (resourceStream == null) + { + throw new ArgumentException($"Resource '{resourceName}' not found in assembly '{type.Assembly.FullName}'.", nameof(resourceName)); + } + return resourceStream; + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/TestInitializer.cs b/src/Renci.SshNet.IntegrationTests/TestInitializer.cs index 16b0a3eca..0c058781e 100644 --- a/src/Renci.SshNet.IntegrationTests/TestInitializer.cs +++ b/src/Renci.SshNet.IntegrationTests/TestInitializer.cs @@ -1,4 +1,4 @@ -namespace IntegrationTests +namespace Renci.SshNet.IntegrationTests { [TestClass] public class TestInitializer diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs b/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs index 63e6c70ce..b98de1267 100644 --- a/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs +++ b/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs @@ -1,8 +1,8 @@ -锘縰sing DotNet.Testcontainers.Images; -using DotNet.Testcontainers.Builders; +锘縰sing DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Containers; +using DotNet.Testcontainers.Images; -namespace IntegrationTests.TestsFixtures +namespace Renci.SshNet.IntegrationTests.TestsFixtures { public sealed class InfrastructureFixture : IDisposable { @@ -20,11 +20,11 @@ public static InfrastructureFixture Instance } } - private IContainer? _sshServer; + private IContainer _sshServer; - private IFutureDockerImage? _sshServerImage; + private IFutureDockerImage _sshServerImage; - public string? SshServerHostName { get; set; } + public string SshServerHostName { get; set; } public ushort SshServerPort { get; set; } diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs b/src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs index 521f947cc..1d6658fc2 100644 --- a/src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs +++ b/src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs @@ -1,4 +1,4 @@ -锘縩amespace IntegrationTests.TestsFixtures +锘縩amespace Renci.SshNet.IntegrationTests.TestsFixtures { /// /// The base class for integration tests @@ -10,7 +10,7 @@ public abstract class IntegrationTestBase /// /// The SSH Server host name. /// - public string? SshServerHostName + public string SshServerHostName { get { @@ -62,5 +62,24 @@ private void ShowInfrastructureInformation() Console.WriteLine($"SSH Server host name: {_infrastructureFixture.SshServerHostName}"); Console.WriteLine($"SSH Server port: {_infrastructureFixture.SshServerPort}"); } + + /// + /// Creates the test file. + /// + /// Name of the file. + /// Size in megabytes. + protected void CreateTestFile(string fileName, int size) + { + using (var testFile = File.Create(fileName)) + { + var random = new Random(); + for (int i = 0; i < 1024 * size; i++) + { + var buffer = new byte[1024]; + random.NextBytes(buffer); + testFile.Write(buffer, 0, buffer.Length); + } + } + } } } diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs b/src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs index 5f2ee4d56..9a67f65c3 100644 --- a/src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs +++ b/src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs @@ -1,4 +1,4 @@ -锘縩amespace IntegrationTests.TestsFixtures +锘縩amespace Renci.SshNet.IntegrationTests.TestsFixtures { public class SshUser { diff --git a/src/Renci.SshNet.IntegrationTests/Users.cs b/src/Renci.SshNet.IntegrationTests/Users.cs new file mode 100644 index 000000000..043ab63ec --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/Users.cs @@ -0,0 +1,8 @@ +锘縩amespace Renci.SshNet.IntegrationTests +{ + internal static class Users + { + public static readonly Credential Regular = new Credential("sshnet", "ssh4ever"); + public static readonly Credential Admin = new Credential("sshnetadm", "ssh4ever"); + } +} diff --git a/src/Renci.SshNet.IntegrationTests/Usings.cs b/src/Renci.SshNet.IntegrationTests/Usings.cs index e6180a739..8eba0e510 100644 --- a/src/Renci.SshNet.IntegrationTests/Usings.cs +++ b/src/Renci.SshNet.IntegrationTests/Usings.cs @@ -1,9 +1,5 @@ -#pragma warning disable IDE0005 - global using System.Text; global using Microsoft.VisualStudio.TestTools.UnitTesting; -global using IntegrationTests.TestsFixtures; - - +global using Renci.SshNet.IntegrationTests.TestsFixtures; diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/id_dsa b/src/Renci.SshNet.IntegrationTests/resources/client/id_dsa new file mode 100644 index 000000000..6c84e0c65 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/id_dsa @@ -0,0 +1,12 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQC1Zd32ntjuKsLACveUlEoV9CjFDT/spf7k95Rh/U/2abZx0pa0 +8Z01lwpdIPdShHgmhJww4S8ZuGgr9QIOAf8r3DOLt+KpJmjS8ti4gMYqnaG2XDRu +tT6sKneSA5Kd/CwbJ/LZm9dsbvTWpaVHzokhAdXMgq+MxWTK5tMLXciUFQIVAK76 +I2Sp/9g4BiNisdIIcWZYB8RhAoGADlSeN+FAEdx5+pQOZ1jXxTrlFR91u5yWj9BU +CYiD8exlG3cTvarQzU21pFi93PasefgezpXuMTO3L8lz6zUFGAxwhZUvlHtsdyHi +a5HX2ZB/Xjz9ucuQNCeP3PvF170Go+MwOZ38Nd6MuT7cne3dyqubRAzPColXSIcJ +F41ANz0CgYEAm8IGZQatS7M6AfNITNWG4TI7Z2aRQjLb9/MWJIID7c/VQ4zdTZdG +3kpk0Gj9n4xreopK5NmYAdj8rtFfPBgmXltsLqt+bBcXkpxW//7WC29WOXW3t90y +STh+cWuWfr9fV7mf4Ql/6u/ZIgpQNvnNYezazt3fK8EXjI1dAXEuQxECFBhGOzk+ +Aimeob964E8+HsQNlyde +-----END DSA PRIVATE KEY----- diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk b/src/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk new file mode 100644 index 000000000..b73384f82 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk @@ -0,0 +1,17 @@ +PuTTY-User-Key-File-2: ssh-dss +Encryption: none +Comment: imported-openssh-key +Public-Lines: 10 +AAAAB3NzaC1kc3MAAACBALVl3fae2O4qwsAK95SUShX0KMUNP+yl/uT3lGH9T/Zp +tnHSlrTxnTWXCl0g91KEeCaEnDDhLxm4aCv1Ag4B/yvcM4u34qkmaNLy2LiAxiqd +obZcNG61Pqwqd5IDkp38LBsn8tmb12xu9NalpUfOiSEB1cyCr4zFZMrm0wtdyJQV +AAAAFQCu+iNkqf/YOAYjYrHSCHFmWAfEYQAAAIAOVJ434UAR3Hn6lA5nWNfFOuUV +H3W7nJaP0FQJiIPx7GUbdxO9qtDNTbWkWL3c9qx5+B7Ole4xM7cvyXPrNQUYDHCF +lS+Ue2x3IeJrkdfZkH9ePP25y5A0J4/c+8XXvQaj4zA5nfw13oy5Ptyd7d3Kq5tE +DM8KiVdIhwkXjUA3PQAAAIEAm8IGZQatS7M6AfNITNWG4TI7Z2aRQjLb9/MWJIID +7c/VQ4zdTZdG3kpk0Gj9n4xreopK5NmYAdj8rtFfPBgmXltsLqt+bBcXkpxW//7W +C29WOXW3t90ySTh+cWuWfr9fV7mf4Ql/6u/ZIgpQNvnNYezazt3fK8EXjI1dAXEu +QxE= +Private-Lines: 1 +AAAAFBhGOzk+Aimeob964E8+HsQNlyde +Private-MAC: 1c254f3882a6661c98fb82dea1a55638a23633e5 diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa b/src/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa new file mode 100644 index 000000000..cf2cc9795 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa @@ -0,0 +1,27 @@ +锘-----BEGIN RSA PRIVATE KEY----- +MIIEoQIBAAKCAQEAuTtXn+BatX1oJuvhqfJZw5jc/pcIxJUPmuoFCH3+bXfKBJ/9 +4ixNETzZBasyvT/ozboAbCG3qcJOYxf2BEeTAIXe1jLAoTd1GKCwMvZOyjnsPN95 +/lChwfdnBbMzpZYTGfoUylXme/mzjjLu/J0qXgR5lyk9HFT+x5YEtRl8VSHiDkLK +TZ37dwhsqgcs+PkfvYMUK+C8evnfE0tgWgKZk0Eatl87nLWyVXB4LzhSDtGKLCPA +OgrX7fYfplDwJ2WK1N6nG0FnxW1HhDeSK7e2TbAa2vZQgvFXMWnO4O/NZKp4COpO +ReyliWhdtKAjr/+cD4yDfPjhjjKOYfxbvdRG4QIBIwKCAQAqVrTxV9o4HKoXhl93 +TVZYl/f/rX5Y0Z0quSW4zFdpendRg6e+qwpNFTjrWlS9ivNiOSSrAGR+ktAWpmQe +PD7bjFAw9ahfXSIUQfxja3+5Mc+Y4p+KlhZYOIyTlqy4Ik2CR8o84G8yR7QDPteK +Mo1XUXrguPgGedPV2SWlvK60XyAXqsewDhi7SeImZomKzbh33SXjVxakzHfa8BEU +eIIeR9oFlQMuYdo4GrHhFO2T+g/gqw/kVd1zkeEwt06fZVDErVwp+twewxxvwrk4 +CKUCzavfhDfi5sJ5YdzhDBRgkyBgJI+f15dKyqqOiAparV9+uzrD6vIuNnlVoqQA +iugLAoGBAPBliy32e83nshBknBn5HOK2rO3a1zHxvYr/NzITXtdZOjatNyfXtkwi +Ll/el5tZhJvKe9nItSI/4w7mvlvXZfW8h3MR0qb8at4jWa8ya2hwEerqaJonqjjb ++eBhg27ltZIQRk8Bv6ApXTAWkc+dFGhEIysokDQX7V72Bdrizup1AoGBAMVBLHK0 +5IFb8x7danlAmDX6bqCObId4Pce2OeONFIj1jIowvCXaE0t9zU4X5SdN5ujqu4Dq +XgzUdNeKcJxWpFO74MDRxT3CbMz36fikJnvxWl/+q0HalYuCY8gm14VYcThUBAro +3c941INueybGNLIA9jc7RMnsFtyVTvNYpaU9AoGAFJr9TRUgjf3qsPKuS15+0Zqh +G7OsC5hgtCSBEuu3rA72XHU/Pe3rDdcLSgvD2h2dpvQZPo2L3l0/WQx2t2o78H3f +uWftfAcB2Iav6nIJNNZn75BvXaug4E1ej5NUaJdYtL+Q/3UtrqR1s6opwVabWWTt +ElPvGmhzboodwk30en8CgYAyuPzNCfGdm00lMZ8JPH7pTwaBDq4xdrDM9FgHUCna +E0FlXP0uTgT2J6nSQKijtPI75JadfhgvL1E+vTLmX2wViBU45XvcrlZ92Vlr0nBL +wbgnUB1otIzauyD49AuIsFegxSWcZ8QCJmKIMlouir0X1FyR3Apfzv6Qfio+kyNH +vwKBgQCtwxojkzUSfV3zDt6bYSLBzgXgo/Zr9lS+gSggP72DzINmW2gbA0fkM2Zu +JltcfakKv4gVX/1zooz+7t+4bj6dqt+bl7hYz0VnTSDZGuo5LKDif/4gSGrdblC2 +QLTuX2HjWCZdsue7mRwL7cXR4zlIoE99+Ryhdxvc5wHSfYr/JA== +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/id_rsa b/src/Renci.SshNet.IntegrationTests/resources/client/id_rsa new file mode 100644 index 000000000..da8f397ea --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/id_rsa @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAuDdE+laKZ8D0mEFMNMGkDYQY89A2BUML5L+DsFmEn//3yRdz +Omx+Nk59ifiJUPuP3whZxN5vfbHleU9ZshI+37LqTbXmNrChRlxDSxrQA/++hTNI +gZl8e+sZUk8mUkpjQyEVOMVEdt3H3PmpfOBeZjtpRJPuWa90J+SVKbnAX4rOL7bt +LDA4GeMNXdLXLl5E/zBCZ9ol9nJ8W0suajQDx7u2/ixH1wb9jqzA6j68f1+kERII +t8OUcS+ZM+274rVrCMCL290k9gEQAKwcG/KRMqdgP8Oadtq5ELS/t4m2fH5JqYJ9 +9399QGT4LTPvoiTwZjyhYwK3FhCfXyFQf+gwIwIDAQABAoIBAGLChsFrKfJr2PXT +dAaIleoFGteDlaKGilbNcc1WgKrCsNXnM4hr59I3jEgurXd0FnKs6GuKEN2jRPIf +X2f/LiQBqGmXDl/dm+i7x/v42PJ75mlE0Cdi4QESTlX5RwMxDDxN/TGdWJIdXmwS +kRH4u8M1ML9qS4tba/uDKZDgG8lcF/z6K0RbXDMxL0azfbd5e+jca1e8Fs93X5s7 +mJotXaA+L33R7lCpBBOa1OY517Ug7bdI+uWh59o0bw8v2q8vr8ISOHU3N+JvKZ62 +2z5O6lLyB94sF6ltXRv9pmfcSBjfB8CJx5q1yejUZKM6VfN98MTSKo8WKMEtGmqk +BtZFTlECgYEA8WYG6vntqXPCHhFFfgCymh8OoXL/mPDSkqsswKfeD4O+Ml9hRUtg +xl6FDxFAMR7WJ4Vb8u9IMOc7Xx+nzlZNsdC5m7FAVRIEUPPjEucte+ZYKjSy+WOd +dAtQ07O3z9fi+JNplSjisKtBWaemfqc2TcYXOeIIgwJnkaCf2C7I2bsCgYEAw1vJ +9c5VLTisPj7ijMeGLWISG5E0aidOrb15E8xcnXuT9TEW1Dc1EgRK/D03tlnoxr1I +CISPx4EmdLTiEl2AVi33DOhCeFAt8TOd/y3chKsbewb+BYEMmBD93mhsKg+YmC5E +284SCV3fCcyFJfo9oy5Z2tIELerjT0cnpHgPCLkCgYEAij3OemRUeTUklol3jXgi +z+Y3P7gWreREAuBqSY4YujPNCRXcI43ORuu8MWvEohyxsYJKrO3hHrhdJNWBCMYd +ylXo5UN1vwIJXL6+bIXdY1X/aXQyhmVItzr/t6z0997/STFKRrRaVahNTWWYEHH7 +xEBL7scF7tjCrQAaafgo558CgYBkrrm3ZU+grsSWj/JSe8I7QX/zlTJeQ0PZZv0v +pvNUdowaoeISHSHM10mOFj7QTCYbxxGI0kkHmRgordCVhnrN74KTtGANgcUrul6D +VS+BcG4JSeFBFPFYreko5shYJRGP3MjAP8Qr76Uzd6RnnkCGCS1mCTb+M0BTa2iS +6w1UgQKBgQDQ2qV4s7xH3dixy4MWhDBFmrQlFpQkNNkrJ/ImHrxI2tFyNaq1fE+Q +PrXJi8mjwb/ETVN2C5iBTtIyVg1pZk3YAWAvIt9SPaRVYQWj8IJeOTTaNEZEvp5K +1LJBWO0ksgJK28f/z7FwejeGbBwg8ch9wVhtFwIV++rZ76smP7C+9Q== +-----END RSA PRIVATE KEY----- diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub b/src/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub new file mode 100644 index 000000000..24ba2f7dd --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4N0T6VopnwPSYQUw0waQNhBjz0DYFQwvkv4OwWYSf//fJF3M6bH42Tn2J+IlQ+4/fCFnE3m99seV5T1myEj7fsupNteY2sKFGXENLGtAD/76FM0iBmXx76xlSTyZSSmNDIRU4xUR23cfc+al84F5mO2lEk+5Zr3Qn5JUpucBfis4vtu0sMDgZ4w1d0tcuXkT/MEJn2iX2cnxbSy5qNAPHu7b+LEfXBv2OrMDqPrx/X6QREgi3w5RxL5kz7bvitWsIwIvb3ST2ARAArBwb8pEyp2A/w5p22rkQtL+3ibZ8fkmpgn33f31AZPgtM++iJPBmPKFjArcWEJ9fIVB/6DAj diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass b/src/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass new file mode 100644 index 000000000..841532d1f --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass @@ -0,0 +1,28 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABC9v0UCCP +T+1yNEu9m0w939AAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQC4N0T6Vopn +wPSYQUw0waQNhBjz0DYFQwvkv4OwWYSf//fJF3M6bH42Tn2J+IlQ+4/fCFnE3m99seV5T1 +myEj7fsupNteY2sKFGXENLGtAD/76FM0iBmXx76xlSTyZSSmNDIRU4xUR23cfc+al84F5m +O2lEk+5Zr3Qn5JUpucBfis4vtu0sMDgZ4w1d0tcuXkT/MEJn2iX2cnxbSy5qNAPHu7b+LE +fXBv2OrMDqPrx/X6QREgi3w5RxL5kz7bvitWsIwIvb3ST2ARAArBwb8pEyp2A/w5p22rkQ +tL+3ibZ8fkmpgn33f31AZPgtM++iJPBmPKFjArcWEJ9fIVB/6DAjAAADwPBAapXaoQvm3O +2i9sBnmO+d8kCdm2nhGbEXNzswb0toARYyx7/rPON15BHv470NLK4GjtxWb8SbkUBjWIXJ +dpJR1feYAgJQ27yaU6SBEJvnQBFI3EvH+h9ykaikDP/SzgZuGup5NZIoB09PzCPk4SbAwn +skFT3s1v3ufaULYTiAO2xtWzABkjxfw8HOo+PF3UqGIF4145kGLUT1pUN7iy5EQZA8evRb +Yt/9+ChcyBgKONgXdpjLNf02XIM/jQofZkROBg7ZAKCjtL3yGpvtOpwzCKy1hWDmgjtkeK +Xn84/qwXWEobBa2wrDQ4Mjj7AIimRsCciO05bVB5KtNjT+WzCalpTzfj2nazukteNRKTD3 +bQR0gLFfFX4/YodXmtu2n+0R2AKkdPW5ZhoEEpT1FjfYUImAuElSEy5FEeR3bwE5uGQkF4 +uIMJWD+89QxO9PWKTloVI2hrOF9/z+UzUi7p16FQFDlB82qCQAiaIOHgotgDn9+OwMw0ew +Gu/D3T8ZpKXcTAxK1JeoDFh2h+CE37JDvftNIxIhTp7lrhCdioj1DSBorwfke/q4+OvLUH +8SZ6ZgppHjJ4jg6lB9TWCpD5PECDW+NuQQwUb5V4NKoBqnJrPaNUSbI7SL5Pq3mOXXNRmv +q1Va06CfcHL3JupICFifux5xBDlQY0foAt7DFOgA6qANaCnRl2H2oFsEdRhBbL6EPP0bAQ +7PBvWJlt5Aqr1V7QzcCHNZcyGpjiHeXsQxSWXzb1xQprlrDSnlGZpusrBTcZTLWUtOAgqQ +dNbUNeUq1E74rZ/RBiVliaLHNBKwTCE9KyZTl/DcfgInB7DDEd7Vlmujzar7xAXRJot7k2 +a12gT69eVsqiO5si23493JFl0JB5vbQvQWARAvcdNPDPiILoJVpbgyL9oMzVzTjJyqYS1x +cHXKE+rL4ZHeQhcfySXplZlUY9ADVY5QywAj2kl+5gT3Fohu/95axF7w9dAHyMntxbVnA3 +r0zOmqbAKOYEYEXxZ+Vq09YdEyJh33V48PUmvCusWWyeKIfjO4R1nD2+7iyiF7joF7bOBm +o0LXuJdr81BCMueryPUaqSRpGhg/P/nUqzxj7p0mAh9uUOr/CtOpbc6wNY70RgdiMGFWhz +zhO54p7iEg2zZNUZ5zRM1hTBikTeYyInpw8IQiMv9GH7/9gWwqPsh0qRVjj5kjqjSu069d +FeuGjsMGCnLLG6WvOQ9DgH9JR4cfinBL3JwtpHFBIHwhsh2EIuSseVHvQlFlEc1U+7Yoxc +0dn1VVtg== +-----END OPENSSH PRIVATE KEY----- diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh b/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh new file mode 100644 index 000000000..29ecb9073 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh @@ -0,0 +1,9 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS +1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQT886z6SLRIzRu7VNA6SSeKZCNNRPXe +iutTik1T3RUEshgnTI/V3T/d5QurCQPvf2ob3+Rd4FhCsVCS9gilIhVsAAAAsH3KX4d9yl ++HAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPzzrPpItEjNG7tU +0DpJJ4pkI01E9d6K61OKTVPdFQSyGCdMj9XdP93lC6sJA+9/ahvf5F3gWEKxUJL2CKUiFW +wAAAAgYxeSyo7MVNup52COOCarcvARKlWhKIP2CKzj4qa5/6EAAAAYc3NobmV0QFVidW50 +dTE5MTBEZXNrdG9w +-----END OPENSSH PRIVATE KEY----- diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub b/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub new file mode 100644 index 000000000..33524cea6 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPzzrPpItEjNG7tU0DpJJ4pkI01E9d6K61OKTVPdFQSyGCdMj9XdP93lC6sJA+9/ahvf5F3gWEKxUJL2CKUiFWw= sshnet@Ubuntu1910Desktop diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh b/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh new file mode 100644 index 000000000..e720d2407 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh @@ -0,0 +1,10 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS +1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQS0rLvxzSomgC4UNulA7/jdABXTG9un +zFazinvOughrumo0n/R1DoSRXY4bHooQdq02pTD6/DK3FzS7n4ouJi/LuJfX1EFxYMJzP2 +aYlT0rOgvvIuLv2Q4OzcdjV8mzSIEAAADo1T5ZUtU+WVIAAAATZWNkc2Etc2hhMi1uaXN0 +cDM4NAAAAAhuaXN0cDM4NAAAAGEEtKy78c0qJoAuFDbpQO/43QAV0xvbp8xWs4p7zroIa7 +pqNJ/0dQ6EkV2OGx6KEHatNqUw+vwytxc0u5+KLiYvy7iX19RBcWDCcz9mmJU9KzoL7yLi +79kODs3HY1fJs0iBAAAAMQDgRb336Dk9e4VxOpSqnwBqHRsJ3QmSME9qMBvx5SXykHFAsK +wzVKEvIQizmg/+sWcAAAAYc3NobmV0QFVidW50dTE5MTBEZXNrdG9wAQIDBAUGBw== +-----END OPENSSH PRIVATE KEY----- diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub b/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub new file mode 100644 index 000000000..99878d2ca --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBLSsu/HNKiaALhQ26UDv+N0AFdMb26fMVrOKe866CGu6ajSf9HUOhJFdjhseihB2rTalMPr8MrcXNLufii4mL8u4l9fUQXFgwnM/ZpiVPSs6C+8i4u/ZDg7Nx2NXybNIgQ== sshnet@Ubuntu1910Desktop diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh b/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh new file mode 100644 index 000000000..47ee8ff8b --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh @@ -0,0 +1,12 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS +1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAgeFoEYBgUaOlJPnEYIPLSTwmxLRl +EUVpVAOzww3q10fj/Tuppty/fRLcbMoeVzWKl8mjDbR+XOdaKDGo6xcHGsgByITz2/F9wr +E8BHyFEPemg8h0DKLW0X55J+rnn3lE0a0jXKngJ3VLVcgKgXam7KtpoCWFx689jVCpTxWI +GrkIvlkAAAEYr0LrEa9C6xEAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ +AAAIUEAIHhaBGAYFGjpST5xGCDy0k8JsS0ZRFFaVQDs8MN6tdH4/07qabcv30S3GzKHlc1 +ipfJow20flznWigxqOsXBxrIAciE89vxfcKxPAR8hRD3poPIdAyi1tF+eSfq5595RNGtI1 +yp4Cd1S1XICoF2puyraaAlhcevPY1QqU8ViBq5CL5ZAAAAQQ50pmBidmKTIknaRpdO5WIu +nYEGMUkLqdZ0egk9Ggg63mOHiLykf+XWcGbHbHM95CISXhqlvMtCYeGwOpP6FoMGAAAAGH +NzaG5ldEBVYnVudHUxOTEwRGVza3RvcAECAw== +-----END OPENSSH PRIVATE KEY----- diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub b/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub new file mode 100644 index 000000000..085fa07bf --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACB4WgRgGBRo6Uk+cRgg8tJPCbEtGURRWlUA7PDDerXR+P9O6mm3L99Etxsyh5XNYqXyaMNtH5c51ooMajrFwcayAHIhPPb8X3CsTwEfIUQ96aDyHQMotbRfnkn6uefeUTRrSNcqeAndUtVyAqBdqbsq2mgJYXHrz2NUKlPFYgauQi+WQ== sshnet@Ubuntu1910Desktop diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh b/src/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh new file mode 100644 index 000000000..0bcb6e755 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh @@ -0,0 +1,7 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACAJDRj1Tk7s7ik4Bnx3L3tjEY+e8l4ZmYJFMovUaZia5QAAAKBKTcfHSk3H +xwAAAAtzc2gtZWQyNTUxOQAAACAJDRj1Tk7s7ik4Bnx3L3tjEY+e8l4ZmYJFMovUaZia5Q +AAAEBMMOaGa8RU8Vy0vLFlRT5iVSxl3ji9NBKaO/RS0aFL3QkNGPVOTuzuKTgGfHcve2MR +j57yXhmZgkUyi9RpmJrlAAAAGHNzaG5ldEBVYnVudHUxOTEwRGVza3RvcAECAwQF +-----END OPENSSH PRIVATE KEY----- diff --git a/src/Renci.SshNet.IntegrationTests/resources/issue #70.png b/src/Renci.SshNet.IntegrationTests/resources/issue #70.png new file mode 100644 index 0000000000000000000000000000000000000000..8c9723796f2280bc537b6e8097277bffc6d384e9 GIT binary patch literal 312036 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

866!RtPY&1#&$s>W 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

CTT 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 literal 0 HcmV?d00001 diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Cipher.cs b/src/Renci.SshNet.TestTools.OpenSSH/Cipher.cs new file mode 100644 index 000000000..f7d8d8842 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/Cipher.cs @@ -0,0 +1,54 @@ +锘縩amespace Renci.SshNet.TestTools.OpenSSH +{ + public class Cipher + { + public static readonly Cipher TripledesCbc = new Cipher("3des-cbc"); + public static readonly Cipher Aes128Cbc = new Cipher("aes128-cbc"); + public static readonly Cipher Aes192Cbc = new Cipher("aes192-cbc"); + public static readonly Cipher Aes256Cbc = new Cipher("aes256-cbc"); + public static readonly Cipher RijndaelCbc = new Cipher("rijndael-cbc@lysator.liu.se"); + public static readonly Cipher Aes128Ctr = new Cipher("aes128-ctr"); + public static readonly Cipher Aes192Ctr = new Cipher("aes192-ctr"); + public static readonly Cipher Aes256Ctr = new Cipher("aes256-ctr"); + public static readonly Cipher Aes128Gcm = new Cipher("aes128-gcm@openssh.com"); + public static readonly Cipher Aes256Gcm = new Cipher("aes256-gcm@openssh.com"); + public static readonly Cipher Arcfour = new Cipher("arcfour"); + public static readonly Cipher Arcfour128 = new Cipher("arcfour128"); + public static readonly Cipher Arcfour256 = new Cipher("arcfour256"); + public static readonly Cipher BlowfishCbc = new Cipher("blowfish-cbc"); + public static readonly Cipher Cast128Cbc = new Cipher("cast128-cbc"); + public static readonly Cipher Chacha20Poly1305 = new Cipher("chacha20-poly1305@openssh.com"); + + public Cipher(string name) + { + Name = name; + } + + public string Name { get; } + + public override bool Equals(object? obj) + { + if (obj == null) + { + return false; + } + + if (obj is Cipher otherCipher) + { + return otherCipher.Name == Name; + } + + return false; + } + + public override int GetHashCode() + { + return Name.GetHashCode(); + } + + public override string ToString() + { + return Name; + } + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs b/src/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs new file mode 100644 index 000000000..3eab2b199 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs @@ -0,0 +1,20 @@ +锘縩amespace Renci.SshNet.TestTools.OpenSSH.Formatters +{ + internal class BooleanFormatter + { + public string Format(bool value) + { + return value ? "yes" : "no"; + } + + public string Format(bool? value, bool defaultValue) + { + if (value.HasValue) + { + return Format(value.Value); + } + + return Format(defaultValue); + } + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs b/src/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs new file mode 100644 index 000000000..2b8231111 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs @@ -0,0 +1,12 @@ +锘縰sing System.Globalization; + +namespace Renci.SshNet.TestTools.OpenSSH.Formatters +{ + internal class Int32Formatter + { + public string Format(int value) + { + return value.ToString(NumberFormatInfo.InvariantInfo); + } + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs b/src/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs new file mode 100644 index 000000000..f9f4bbf6f --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs @@ -0,0 +1,10 @@ +锘縩amespace Renci.SshNet.TestTools.OpenSSH.Formatters +{ + internal class LogLevelFormatter + { + public string Format(LogLevel logLevel) + { + return logLevel.ToString("G").ToUpperInvariant(); + } + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs b/src/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs new file mode 100644 index 000000000..df2968be0 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs @@ -0,0 +1,54 @@ +锘縩amespace Renci.SshNet.TestTools.OpenSSH.Formatters +{ + internal class MatchFormatter + { + public string Format(Match match) + { + using (var writer = new StringWriter()) + { + Format(match, writer); + return writer.ToString(); + } + } + + public void Format(Match match, TextWriter writer) + { + writer.Write("Match "); + + if (match.Users.Length > 0) + { + writer.Write("User "); + for (var i = 0; i < match.Users.Length; i++) + { + if (i > 0) + { + writer.Write(','); + } + + writer.Write(match.Users[i]); + } + } + + if (match.Addresses.Length > 0) + { + writer.Write("Address "); + for (var i = 0; i < match.Addresses.Length; i++) + { + if (i > 0) + { + writer.Write(','); + } + + writer.Write(match.Addresses[i]); + } + } + + writer.WriteLine(); + + if (match.AuthenticationMethods != null) + { + writer.WriteLine(" AuthenticationMethods " + match.AuthenticationMethods); + } + } + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs b/src/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs new file mode 100644 index 000000000..fcb74e266 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs @@ -0,0 +1,10 @@ +锘縩amespace Renci.SshNet.TestTools.OpenSSH.Formatters +{ + internal class SubsystemFormatter + { + public string Format(Subsystem subsystem) + { + return subsystem.Name + " " + subsystem.Command; + } + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs b/src/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs new file mode 100644 index 000000000..0c79f7792 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs @@ -0,0 +1,53 @@ +锘縩amespace Renci.SshNet.TestTools.OpenSSH +{ + public class HostKeyAlgorithm + { + public static readonly HostKeyAlgorithm EcdsaSha2Nistp256CertV01OpenSSH = new HostKeyAlgorithm("ecdsa-sha2-nistp256-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm EcdsaSha2Nistp384CertV01OpenSSH = new HostKeyAlgorithm("ecdsa-sha2-nistp384-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm EcdsaSha2Nistp521CertV01OpenSSH = new HostKeyAlgorithm("ecdsa-sha2-nistp521-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm SshEd25519CertV01OpenSSH = new HostKeyAlgorithm("ssh-ed25519-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm RsaSha2256CertV01OpenSSH = new HostKeyAlgorithm("rsa-sha2-256-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm RsaSha2512CertV01OpenSSH = new HostKeyAlgorithm("rsa-sha2-512-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm SshRsaCertV01OpenSSH = new HostKeyAlgorithm("ssh-rsa-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm EcdsaSha2Nistp256 = new HostKeyAlgorithm("ecdsa-sha2-nistp256"); + public static readonly HostKeyAlgorithm EcdsaSha2Nistp384 = new HostKeyAlgorithm("ecdsa-sha2-nistp384"); + public static readonly HostKeyAlgorithm EcdsaSha2Nistp521 = new HostKeyAlgorithm("ecdsa-sha2-nistp521"); + public static readonly HostKeyAlgorithm SshEd25519 = new HostKeyAlgorithm("ssh-ed25519"); + public static readonly HostKeyAlgorithm RsaSha2512 = new HostKeyAlgorithm("rsa-sha2-512"); + public static readonly HostKeyAlgorithm RsaSha2256 = new HostKeyAlgorithm("rsa-sha2-256"); + public static readonly HostKeyAlgorithm SshRsa = new HostKeyAlgorithm("ssh-rsa"); + public static readonly HostKeyAlgorithm SshDsa = new HostKeyAlgorithm("ssh-dsa"); + + public HostKeyAlgorithm(string name) + { + Name = name; + } + + public string Name { get; } + + public override bool Equals(object? obj) + { + if (obj == null) + { + return false; + } + + if (obj is HostKeyAlgorithm otherHka) + { + return otherHka.Name == Name; + } + + return false; + } + + public override int GetHashCode() + { + return Name.GetHashCode(); + } + + public override string ToString() + { + return Name; + } + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs b/src/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs new file mode 100644 index 000000000..4701103f0 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs @@ -0,0 +1,52 @@ +锘縩amespace Renci.SshNet.TestTools.OpenSSH +{ + public class KeyExchangeAlgorithm + { + public static readonly KeyExchangeAlgorithm DiffieHellmanGroup1Sha1 = new KeyExchangeAlgorithm("diffie-hellman-group1-sha1"); + public static readonly KeyExchangeAlgorithm DiffieHellmanGroup14Sha1 = new KeyExchangeAlgorithm("diffie-hellman-group14-sha1"); + public static readonly KeyExchangeAlgorithm DiffieHellmanGroup14Sha256 = new KeyExchangeAlgorithm("diffie-hellman-group14-sha256"); + public static readonly KeyExchangeAlgorithm DiffieHellmanGroup16Sha512 = new KeyExchangeAlgorithm("diffie-hellman-group16-sha512"); + public static readonly KeyExchangeAlgorithm DiffieHellmanGroup18Sha512 = new KeyExchangeAlgorithm("diffie-hellman-group18-sha512"); + public static readonly KeyExchangeAlgorithm DiffieHellmanGroupExchangeSha1 = new KeyExchangeAlgorithm("diffie-hellman-group-exchange-sha1"); + public static readonly KeyExchangeAlgorithm DiffieHellmanGroupExchangeSha256 = new KeyExchangeAlgorithm("diffie-hellman-group-exchange-sha256"); + public static readonly KeyExchangeAlgorithm EcdhSha2Nistp256 = new KeyExchangeAlgorithm("ecdh-sha2-nistp256"); + public static readonly KeyExchangeAlgorithm EcdhSha2Nistp384 = new KeyExchangeAlgorithm("ecdh-sha2-nistp384"); + public static readonly KeyExchangeAlgorithm EcdhSha2Nistp521 = new KeyExchangeAlgorithm("ecdh-sha2-nistp521"); + public static readonly KeyExchangeAlgorithm Curve25519Sha256 = new KeyExchangeAlgorithm("curve25519-sha256"); + public static readonly KeyExchangeAlgorithm Curve25519Sha256Libssh = new KeyExchangeAlgorithm("curve25519-sha256@libssh.org"); + public static readonly KeyExchangeAlgorithm Sntrup4591761x25519Sha512 = new KeyExchangeAlgorithm("sntrup4591761x25519-sha512@tinyssh.org"); + + + public KeyExchangeAlgorithm(string name) + { + Name = name; + } + + public string Name { get; } + + public override bool Equals(object? obj) + { + if (obj == null) + { + return false; + } + + if (obj is KeyExchangeAlgorithm otherKex) + { + return otherKex.Name == Name; + } + + return false; + } + + public override int GetHashCode() + { + return Name.GetHashCode(); + } + + public override string ToString() + { + return Name; + } + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/LogLevel.cs b/src/Renci.SshNet.TestTools.OpenSSH/LogLevel.cs new file mode 100644 index 000000000..8724ae068 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/LogLevel.cs @@ -0,0 +1,15 @@ +锘縩amespace Renci.SshNet.TestTools.OpenSSH +{ + public enum LogLevel + { + Quiet = 1, + Fatal = 2, + Error = 3, + Info = 4, + Verbose = 5, + Debug = 6, + Debug1 = 7, + Debug2 = 8, + Debug3 = 9 + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Match.cs b/src/Renci.SshNet.TestTools.OpenSSH/Match.cs new file mode 100644 index 000000000..16cd5073d --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/Match.cs @@ -0,0 +1,57 @@ +锘縩amespace Renci.SshNet.TestTools.OpenSSH +{ + public class Match + { + public Match(string[] users, string[] addresses) + { + Users = users; + Addresses = addresses; + } + + public string[] Users { get; } + + public string[] Addresses { get; } + + public string? AuthenticationMethods { get; set; } + + public void WriteTo(TextWriter writer) + { + writer.Write("Match "); + + if (Users.Length > 0) + { + writer.Write("User "); + for (var i = 0; i < Users.Length; i++) + { + if (i > 0) + { + writer.Write(','); + } + + writer.Write(Users[i]); + } + } + + if (Addresses.Length > 0) + { + writer.Write("Address "); + for (var i = 0; i < Addresses.Length; i++) + { + if (i > 0) + { + writer.Write(','); + } + + writer.Write(Addresses[i]); + } + } + + writer.WriteLine(); + + if (AuthenticationMethods != null) + { + writer.WriteLine(" AuthenticationMethods " + AuthenticationMethods); + } + } + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs b/src/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs new file mode 100644 index 000000000..17bf0cf91 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs @@ -0,0 +1,56 @@ +锘縩amespace Renci.SshNet.TestTools.OpenSSH +{ + public class MessageAuthenticationCodeAlgorithm + { + public static readonly MessageAuthenticationCodeAlgorithm HmacMd5 = new MessageAuthenticationCodeAlgorithm("hmac-md5"); + public static readonly MessageAuthenticationCodeAlgorithm HmacMd5_96 = new MessageAuthenticationCodeAlgorithm("hmac-md5-96"); + public static readonly MessageAuthenticationCodeAlgorithm HmacRipemd160 = new MessageAuthenticationCodeAlgorithm("hmac-ripemd160"); + public static readonly MessageAuthenticationCodeAlgorithm HmacSha1 = new MessageAuthenticationCodeAlgorithm("hmac-sha1"); + public static readonly MessageAuthenticationCodeAlgorithm HmacSha1_96 = new MessageAuthenticationCodeAlgorithm("hmac-sha1-96"); + public static readonly MessageAuthenticationCodeAlgorithm HmacSha2_256 = new MessageAuthenticationCodeAlgorithm("hmac-sha2-256"); + public static readonly MessageAuthenticationCodeAlgorithm HmacSha2_512 = new MessageAuthenticationCodeAlgorithm("hmac-sha2-512"); + public static readonly MessageAuthenticationCodeAlgorithm Umac64 = new MessageAuthenticationCodeAlgorithm("umac-64@openssh.com"); + public static readonly MessageAuthenticationCodeAlgorithm Umac128 = new MessageAuthenticationCodeAlgorithm("umac-128@openssh.com"); + public static readonly MessageAuthenticationCodeAlgorithm HmacMd5Etm = new MessageAuthenticationCodeAlgorithm("hmac-md5-etm@openssh.com"); + public static readonly MessageAuthenticationCodeAlgorithm HmacMd5_96_Etm = new MessageAuthenticationCodeAlgorithm("hmac-md5-96-etm@openssh.com"); + public static readonly MessageAuthenticationCodeAlgorithm HmacRipemd160Etm = new MessageAuthenticationCodeAlgorithm("hmac-ripemd160-etm@openssh.com"); + public static readonly MessageAuthenticationCodeAlgorithm HmacSha1Etm = new MessageAuthenticationCodeAlgorithm("hmac-sha1-etm@openssh.com"); + public static readonly MessageAuthenticationCodeAlgorithm HmacSha1_96_Etm = new MessageAuthenticationCodeAlgorithm("hmac-sha1-96-etm@openssh.com"); + public static readonly MessageAuthenticationCodeAlgorithm HmacSha2_256_Etm = new MessageAuthenticationCodeAlgorithm("hmac-sha2-256-etm@openssh.com"); + public static readonly MessageAuthenticationCodeAlgorithm HmacSha2_512_Etm = new MessageAuthenticationCodeAlgorithm("hmac-sha2-512-etm@openssh.com"); + public static readonly MessageAuthenticationCodeAlgorithm Umac64_Etm = new MessageAuthenticationCodeAlgorithm("umac-64-etm@openssh.com"); + public static readonly MessageAuthenticationCodeAlgorithm Umac128_Etm = new MessageAuthenticationCodeAlgorithm("umac-128-etm@openssh.com"); + + public MessageAuthenticationCodeAlgorithm(string name) + { + Name = name; + } + + public string Name { get; } + + public override bool Equals(object? obj) + { + if (obj == null) + { + return false; + } + + if (obj is MessageAuthenticationCodeAlgorithm otherMac) + { + return otherMac.Name == Name; + } + + return false; + } + + public override int GetHashCode() + { + return Name.GetHashCode(); + } + + public override string ToString() + { + return Name; + } + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs b/src/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs new file mode 100644 index 000000000..292ace7f9 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs @@ -0,0 +1,59 @@ +锘縩amespace Renci.SshNet.TestTools.OpenSSH +{ + public class PublicKeyAlgorithm + { + public static readonly PublicKeyAlgorithm SshEd25519 = new PublicKeyAlgorithm("ssh-ed25519"); + public static readonly PublicKeyAlgorithm SshEd25519CertV01OpenSSH = new PublicKeyAlgorithm("ssh-ed25519-cert-v01@openssh.com"); + public static readonly PublicKeyAlgorithm SkSshEd25519OpenSSH = new PublicKeyAlgorithm("sk-ssh-ed25519@openssh.com"); + public static readonly PublicKeyAlgorithm SkSshEd25519CertV01OpenSSH = new PublicKeyAlgorithm("sk-ssh-ed25519-cert-v01@openssh.com"); + public static readonly PublicKeyAlgorithm SshRsa = new PublicKeyAlgorithm("ssh-rsa"); + public static readonly PublicKeyAlgorithm RsaSha2256 = new PublicKeyAlgorithm("rsa-sha2-256"); + public static readonly PublicKeyAlgorithm RsaSha2512 = new PublicKeyAlgorithm("rsa-sha2-512"); + public static readonly PublicKeyAlgorithm SshDss = new PublicKeyAlgorithm("ssh-dss"); + public static readonly PublicKeyAlgorithm EcdsaSha2Nistp256 = new PublicKeyAlgorithm("ecdsa-sha2-nistp256"); + public static readonly PublicKeyAlgorithm EcdsaSha2Nistp384 = new PublicKeyAlgorithm("ecdsa-sha2-nistp384"); + public static readonly PublicKeyAlgorithm EcdsaSha2Nistp521 = new PublicKeyAlgorithm("ecdsa-sha2-nistp521"); + public static readonly PublicKeyAlgorithm SkEcdsaSha2Nistp256OpenSSH = new PublicKeyAlgorithm("sk-ecdsa-sha2-nistp256@openssh.com"); + public static readonly PublicKeyAlgorithm WebAuthnSkEcdsaSha2Nistp256OpenSSH = new PublicKeyAlgorithm("webauthn-sk-ecdsa-sha2-nistp256@openssh.com"); + public static readonly PublicKeyAlgorithm SshRsaCertV01OpenSSH = new PublicKeyAlgorithm("ssh-rsa-cert-v01@openssh.com"); + public static readonly PublicKeyAlgorithm RsaSha2256CertV01OpenSSH = new PublicKeyAlgorithm("rsa-sha2-256-cert-v01@openssh.com"); + public static readonly PublicKeyAlgorithm RsaSha2512CertV01OpenSSH = new PublicKeyAlgorithm("rsa-sha2-512-cert-v01@openssh.com"); + public static readonly PublicKeyAlgorithm SshDssCertV01OpenSSH = new PublicKeyAlgorithm("ssh-dss-cert-v01@openssh.com"); + public static readonly PublicKeyAlgorithm EcdsaSha2Nistp256CertV01OpenSSH = new PublicKeyAlgorithm("ecdsa-sha2-nistp256-cert-v01@openssh.com"); + public static readonly PublicKeyAlgorithm EcdsaSha2Nistp384CertV01OpenSSH = new PublicKeyAlgorithm("ecdsa-sha2-nistp384-cert-v01@openssh.com"); + public static readonly PublicKeyAlgorithm EcdsaSha2Nistp521CertV01OpenSSH = new PublicKeyAlgorithm("ecdsa-sha2-nistp521-cert-v01@openssh.com"); + public static readonly PublicKeyAlgorithm SkEcdsaSha2Nistp256CertV01OpenSSH = new PublicKeyAlgorithm("sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"); + + public PublicKeyAlgorithm(string name) + { + Name = name; + } + + public string Name { get; } + + public override bool Equals(object? obj) + { + if (obj == null) + { + return false; + } + + if (obj is HostKeyAlgorithm otherHka) + { + return otherHka.Name == Name; + } + + return false; + } + + public override int GetHashCode() + { + return Name.GetHashCode(); + } + + public override string ToString() + { + return Name; + } + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj b/src/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj new file mode 100644 index 000000000..bd59aa4e5 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj @@ -0,0 +1,21 @@ +锘 + + net7.0 + enable + enable + + + $(NoWarn);CS1591;SYSLIB0021;SYSLIB1045 + + + + + \ No newline at end of file diff --git a/src/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs b/src/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs new file mode 100644 index 000000000..b80967113 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs @@ -0,0 +1,501 @@ +锘縰sing System.Globalization; +using System.Text; +using System.Text.RegularExpressions; + +using Renci.SshNet.TestTools.OpenSSH.Formatters; + +namespace Renci.SshNet.TestTools.OpenSSH +{ + public class SshdConfig + { + private static readonly Regex MatchRegex = new Regex($@"\s*Match\s+(User\s+(?[\S]+))?\s*(Address\s+(?[\S]+))?\s*", RegexOptions.Compiled); + + private readonly SubsystemFormatter _subsystemFormatter; + private readonly Int32Formatter _int32Formatter; + private readonly BooleanFormatter _booleanFormatter; + private readonly MatchFormatter _matchFormatter; + + private SshdConfig() + { + AcceptedEnvironmentVariables = new List(); + Ciphers = new List(); + HostKeyFiles = new List(); + HostKeyAlgorithms = new List(); + KeyExchangeAlgorithms = new List(); + PublicKeyAcceptedAlgorithms = new List(); + MessageAuthenticationCodeAlgorithms = new List(); + Subsystems = new List(); + Matches = new List(); + LogLevel = LogLevel.Info; + Port = 22; + Protocol = "2,1"; + + _booleanFormatter = new BooleanFormatter(); + _int32Formatter = new Int32Formatter(); + _matchFormatter = new MatchFormatter(); + _subsystemFormatter = new SubsystemFormatter(); + } + + /// + /// Gets or sets the port number that sshd listens on. + /// + /// + /// The port number that sshd listens on. The default is 22. + /// + public int Port { get; set; } + + /// + /// Gets or sets the list of private host key files used by sshd. + /// + /// + /// A list of private host key files used by sshd. + /// + public List HostKeyFiles { get; set; } + + /// + /// Gets or sets a value specifying whether challenge-response authentication is allowed. + /// + /// + /// A value specifying whether challenge-response authentication is allowed, or + /// if this option is not configured. + /// + public bool? ChallengeResponseAuthentication { get; set; } + + /// + /// Gets or sets a value indicating whether to allow keyboard-interactive authentication. + /// + /// + /// to allow and to disallow keyboard-interactive + /// authentication, or if this option is not configured. + /// + public bool? KeyboardInteractiveAuthentication { get; set; } + + /// + /// Gets or sets the verbosity when logging messages from sshd. + /// + /// + /// The verbosity when logging messages from sshd. The default is . + /// + public LogLevel LogLevel { get; set; } + + /// + /// Gets a sets a value indicating whether the Pluggable Authentication Module interface is enabled. + /// + /// + /// A value indicating whether the Pluggable Authentication Module interface is enabled. + /// + public bool? UsePAM { get; set; } + + public List Subsystems { get; } + + /// + /// Gets a list of conditional blocks. + /// + public List Matches { get; } + + public bool X11Forwarding { get; private set; } + public List AcceptedEnvironmentVariables { get; private set; } + public List Ciphers { get; private set; } + + /// + /// Gets the host key signature algorithms that the server offers. + /// + public List HostKeyAlgorithms { get; private set; } + + /// + /// Gets the available KEX (Key Exchange) algorithms. + /// + public List KeyExchangeAlgorithms { get; private set; } + + /// + /// Gets the signature algorithms that will be accepted for public key authentication. + /// + public List PublicKeyAcceptedAlgorithms { get; private set; } + + /// + /// Gets the available MAC (message authentication code) algorithms. + /// + public List MessageAuthenticationCodeAlgorithms { get; private set; } + + /// + /// Gets a value indicating whether sshd should print /etc/motd when a user logs in interactively. + /// + /// + /// if sshd should print /etc/motd when a user logs in interactively + /// and if it should not; if this option is not configured. + /// + public bool? PrintMotd { get; set; } + + /// + /// Gets or sets the protocol versions sshd supported. + /// + /// + /// The protocol versions sshd supported. The default is 2,1. + /// + public string Protocol { get; set; } + + /// + /// Gets or sets a value indicating whether TCP forwarding is allowed. + /// + /// + /// to allow and to disallow TCP forwarding, + /// or if this option is not configured. + /// + public bool? AllowTcpForwarding { get; set; } + + public void SaveTo(TextWriter writer) + { + writer.WriteLine("Protocol " + Protocol); + writer.WriteLine("Port " + _int32Formatter.Format(Port)); + if (HostKeyFiles.Count > 0) + { + writer.WriteLine("HostKey " + string.Join(",", HostKeyFiles.ToArray())); + } + + if (ChallengeResponseAuthentication is not null) + { + writer.WriteLine("ChallengeResponseAuthentication " + _booleanFormatter.Format(ChallengeResponseAuthentication.Value)); + } + + if (KeyboardInteractiveAuthentication is not null) + { + writer.WriteLine("KbdInteractiveAuthentication " + _booleanFormatter.Format(KeyboardInteractiveAuthentication.Value)); + } + + if (AllowTcpForwarding is not null) + { + writer.WriteLine("AllowTcpForwarding " + _booleanFormatter.Format(AllowTcpForwarding.Value)); + } + + if (PrintMotd is not null) + { + writer.WriteLine("PrintMotd " + _booleanFormatter.Format(PrintMotd.Value)); + } + + writer.WriteLine("LogLevel " + new LogLevelFormatter().Format(LogLevel)); + + foreach (var subsystem in Subsystems) + { + writer.WriteLine("Subsystem " + _subsystemFormatter.Format(subsystem)); + } + + if (UsePAM is not null) + { + writer.WriteLine("UsePAM " + _booleanFormatter.Format(UsePAM.Value)); + } + + writer.WriteLine("X11Forwarding " + _booleanFormatter.Format(X11Forwarding)); + + foreach (var acceptedEnvVar in AcceptedEnvironmentVariables) + { + writer.WriteLine("AcceptEnv " + acceptedEnvVar); + } + + if (Ciphers.Count > 0) + { + writer.WriteLine("Ciphers " + string.Join(",", Ciphers.Select(c => c.Name).ToArray())); + } + + if (HostKeyAlgorithms.Count > 0) + { + writer.WriteLine("HostKeyAlgorithms " + string.Join(",", HostKeyAlgorithms.Select(c => c.Name).ToArray())); + } + + if (KeyExchangeAlgorithms.Count > 0) + { + writer.WriteLine("KexAlgorithms " + string.Join(",", KeyExchangeAlgorithms.Select(c => c.Name).ToArray())); + } + + if (MessageAuthenticationCodeAlgorithms.Count > 0) + { + writer.WriteLine("MACs " + string.Join(",", MessageAuthenticationCodeAlgorithms.Select(c => c.Name).ToArray())); + } + + writer.WriteLine("PubkeyAcceptedAlgorithms " + string.Join(",", PublicKeyAcceptedAlgorithms.Select(c => c.Name).ToArray())); + + foreach (var match in Matches) + { + _matchFormatter.Format(match, writer); + } + } + + public static SshdConfig LoadFrom(Stream stream, Encoding encoding) + { + using (var sr = new StreamReader(stream, encoding)) + { + var sshdConfig = new SshdConfig(); + + Match? currentMatchConfiguration = null; + + string? line; + while ((line = sr.ReadLine()) != null) + { + // Skip empty lines + if (line.Length == 0) + { + continue; + } + + // Skip comments + if (line[0] == '#') + { + continue; + } + + var match = MatchRegex.Match(line); + if (match.Success) + { + var usersGroup = match.Groups["users"]; + var addressesGroup = match.Groups["addresses"]; + var users = usersGroup.Success ? usersGroup.Value.Split(',') : Array.Empty(); + var addresses = addressesGroup.Success ? addressesGroup.Value.Split(',') : Array.Empty(); + + currentMatchConfiguration = new Match(users, addresses); + sshdConfig.Matches.Add(currentMatchConfiguration); + continue; + } + + if (currentMatchConfiguration != null) + { + ProcessMatchOption(currentMatchConfiguration, line); + } + else + { + ProcessGlobalOption(sshdConfig, line); + } + } + + if (sshdConfig.Ciphers == null) + { + // Obtain supported ciphers using ssh -Q cipher + } + + if (sshdConfig.KeyExchangeAlgorithms == null) + { + // Obtain supports key exchange algorithms using ssh -Q kex + } + + if (sshdConfig.HostKeyAlgorithms == null) + { + // Obtain supports host key algorithms using ssh -Q key + } + + if (sshdConfig.MessageAuthenticationCodeAlgorithms == null) + { + // Obtain supported MACs using ssh -Q mac + } + + + return sshdConfig; + } + } + + private static void ProcessGlobalOption(SshdConfig sshdConfig, string line) + { + var matchOptionRegex = new Regex(@"^\s*(?[\S]+)\s+(?.+?){1}\s*$"); + + var optionsMatch = matchOptionRegex.Match(line); + if (!optionsMatch.Success) + { + return; + } + + var nameGroup = optionsMatch.Groups["name"]; + var valueGroup = optionsMatch.Groups["value"]; + + var name = nameGroup.Value; + var value = valueGroup.Value; + + switch (name) + { + case "Port": + sshdConfig.Port = ToInt(value); + break; + case "HostKey": + sshdConfig.HostKeyFiles = ParseCommaSeparatedValue(value); + break; + case "ChallengeResponseAuthentication": + sshdConfig.ChallengeResponseAuthentication = ToBool(value); + break; + case "KbdInteractiveAuthentication": + sshdConfig.KeyboardInteractiveAuthentication = ToBool(value); + break; + case "LogLevel": + sshdConfig.LogLevel = (LogLevel) Enum.Parse(typeof(LogLevel), value, true); + break; + case "Subsystem": + sshdConfig.Subsystems.Add(Subsystem.FromConfig(value)); + break; + case "UsePAM": + sshdConfig.UsePAM = ToBool(value); + break; + case "X11Forwarding": + sshdConfig.X11Forwarding = ToBool(value); + break; + case "Ciphers": + sshdConfig.Ciphers = ParseCiphers(value); + break; + case "KexAlgorithms": + sshdConfig.KeyExchangeAlgorithms = ParseKeyExchangeAlgorithms(value); + break; + case "PubkeyAcceptedAlgorithms": + sshdConfig.PublicKeyAcceptedAlgorithms = ParsePublicKeyAcceptedAlgorithms(value); + break; + case "HostKeyAlgorithms": + sshdConfig.HostKeyAlgorithms = ParseHostKeyAlgorithms(value); + break; + case "MACs": + sshdConfig.MessageAuthenticationCodeAlgorithms = ParseMacs(value); + break; + case "PrintMotd": + sshdConfig.PrintMotd = ToBool(value); + break; + case "AcceptEnv": + ParseAcceptedEnvironmentVariable(sshdConfig, value); + break; + case "Protocol": + sshdConfig.Protocol = value; + break; + case "AllowTcpForwarding": + sshdConfig.AllowTcpForwarding = ToBool(value); + break; + case "KeyRegenerationInterval": + case "HostbasedAuthentication": + case "ServerKeyBits": + case "SyslogFacility": + case "LoginGraceTime": + case "PermitRootLogin": + case "StrictModes": + case "RSAAuthentication": + case "PubkeyAuthentication": + case "IgnoreRhosts": + case "RhostsRSAAuthentication": + case "PermitEmptyPasswords": + case "X11DisplayOffset": + case "PrintLastLog": + case "TCPKeepAlive": + case "AuthorizedKeysFile": + case "PasswordAuthentication": + case "GatewayPorts": + break; + default: + throw new Exception($"Global option '{name}' is not implemented."); + } + } + + private static void ParseAcceptedEnvironmentVariable(SshdConfig sshdConfig, string value) + { + var acceptedEnvironmentVariables = value.Split(' '); + foreach (var acceptedEnvironmentVariable in acceptedEnvironmentVariables) + { + sshdConfig.AcceptedEnvironmentVariables.Add(acceptedEnvironmentVariable); + } + } + + private static List ParseCiphers(string value) + { + var cipherNames = value.Split(','); + var ciphers = new List(cipherNames.Length); + foreach (var cipherName in cipherNames) + { + ciphers.Add(new Cipher(cipherName.Trim())); + } + return ciphers; + } + + private static List ParseKeyExchangeAlgorithms(string value) + { + var kexNames = value.Split(','); + var keyExchangeAlgorithms = new List(kexNames.Length); + foreach (var kexName in kexNames) + { + keyExchangeAlgorithms.Add(new KeyExchangeAlgorithm(kexName.Trim())); + } + return keyExchangeAlgorithms; + } + + public static List ParsePublicKeyAcceptedAlgorithms(string value) + { + var publicKeyAlgorithmNames = value.Split(','); + var publicKeyAlgorithms = new List(publicKeyAlgorithmNames.Length); + foreach (var publicKeyAlgorithmName in publicKeyAlgorithmNames) + { + publicKeyAlgorithms.Add(new PublicKeyAlgorithm(publicKeyAlgorithmName.Trim())); + } + return publicKeyAlgorithms; + } + + private static List ParseHostKeyAlgorithms(string value) + { + var algorithmNames = value.Split(','); + var hostKeyAlgorithms = new List(algorithmNames.Length); + foreach (var algorithmName in algorithmNames) + { + hostKeyAlgorithms.Add(new HostKeyAlgorithm(algorithmName.Trim())); + } + return hostKeyAlgorithms; + } + + private static List ParseMacs(string value) + { + var macNames = value.Split(','); + var macAlgorithms = new List(macNames.Length); + foreach (var algorithmName in macNames) + { + macAlgorithms.Add(new MessageAuthenticationCodeAlgorithm(algorithmName.Trim())); + } + return macAlgorithms; + } + + private static void ProcessMatchOption(Match matchConfiguration, string line) + { + var matchOptionRegex = new Regex(@"^\s+(?[\S]+)\s+(?.+?){1}\s*$"); + + var optionsMatch = matchOptionRegex.Match(line); + if (!optionsMatch.Success) + { + return; + } + + var nameGroup = optionsMatch.Groups["name"]; + var valueGroup = optionsMatch.Groups["value"]; + + var name = nameGroup.Value; + var value = valueGroup.Value; + + switch (name) + { + case "AuthenticationMethods": + matchConfiguration.AuthenticationMethods = value; + break; + default: + throw new Exception($"Match option '{name}' is not implemented."); + } + } + + + private static List ParseCommaSeparatedValue(string value) + { + var values = value.Split(','); + return new List(values); + } + + private static bool ToBool(string value) + { + switch (value) + { + case "yes": + return true; + case "no": + return false; + default: + throw new Exception($"Value '{value}' cannot be mapped to a boolean."); + } + } + + private static int ToInt(string value) + { + return int.Parse(value, NumberFormatInfo.InvariantInfo); + } + } +} diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs b/src/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs new file mode 100644 index 000000000..4d1155105 --- /dev/null +++ b/src/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs @@ -0,0 +1,41 @@ +锘縰sing System.Text.RegularExpressions; + +namespace Renci.SshNet.TestTools.OpenSSH +{ + public class Subsystem + { + public Subsystem(string name, string command) + { + Name = name; + Command = command; + } + + public string Name { get; } + + public string Command { get; set; } + + public void WriteTo(TextWriter writer) + { + writer.WriteLine(Name + "=" + Command); + } + + public static Subsystem FromConfig(string value) + { + var subSystemValueRegex = new Regex(@"^\s*(?[\S]+)\s+(?.+?){1}\s*$"); + + var match = subSystemValueRegex.Match(value); + if (match.Success) + { + var nameGroup = match.Groups["name"]; + var commandGroup = match.Groups["command"]; + + var name = nameGroup.Value; + var command = commandGroup.Value; + + return new Subsystem(name, command); + } + + throw new Exception($"'{value}' not recognized as value for Subsystem."); + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs index 068169248..7cd0f6ec6 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs @@ -36,7 +36,7 @@ public void ConnectShouldHaveThrownSocketException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(SocketError.HostNotFound, _actualException.SocketErrorCode); + Assert.IsTrue(_actualException.SocketErrorCode is SocketError.HostNotFound or SocketError.TryAgain); } } } diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs index 59524ffd7..7a87e9d6f 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs @@ -43,7 +43,7 @@ public void ConnectShouldHaveThrownSocketException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(SocketError.HostNotFound, _actualException.SocketErrorCode); + Assert.IsTrue(_actualException.SocketErrorCode is SocketError.HostNotFound or SocketError.TryAgain); } } } diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs index 5db6b2353..98ffde6aa 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs @@ -12,7 +12,6 @@ using Moq; using Renci.SshNet.Common; -using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Connection diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs index 10aa8bd91..bec205f1a 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs @@ -10,7 +10,6 @@ using Moq; using Renci.SshNet.Common; -using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Connection diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs index 56ad91011..4108c7c09 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs @@ -1,5 +1,5 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; + using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; using System; diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs index 03c1832df..f3ce9ccf8 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs @@ -1,5 +1,5 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; + using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; using System; diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs index 7aa26b309..2c35bce53 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs @@ -8,7 +8,6 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs index b482b753c..5aabb8164 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs @@ -10,7 +10,6 @@ using Moq; using Renci.SshNet.Common; -using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Connection diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs index d8121e894..d87969ced 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs @@ -10,7 +10,6 @@ using Moq; using Renci.SshNet.Common; -using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Connection diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs index 1aaa36e4a..8f6ee9019 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs @@ -10,7 +10,6 @@ using Moq; using Renci.SshNet.Common; -using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Connection diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs index 37b7f8389..4ca6e0c58 100644 --- a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs +++ b/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs @@ -1,7 +1,6 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Renci.SshNet.Common; -using Renci.SshNet.Connection; using Renci.SshNet.Tests.Common; using System; using System.Diagnostics; diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs index 82459d00a..766dd23a6 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs @@ -1,16 +1,7 @@ 锘縰sing System; -using System.Diagnostics; -#if NET6_0_OR_GREATER -using System.Net.Http; -#else -using System.Net; -#endif // NET6_0_OR_GREATER -using System.Threading; -using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; @@ -22,92 +13,6 @@ namespace Renci.SshNet.Tests.Classes [TestClass] public partial class ForwardedPortLocalTest : TestBase { - [TestMethod] - [WorkItem(713)] - [Owner("Kenneth_aa")] - [TestCategory("PortForwarding")] - [TestCategory("integration")] - [Description("Test if calling Stop on ForwardedPortLocal instance causes wait.")] - public void Test_PortForwarding_Local_Stop_Hangs_On_Wait() - { - using (var client = new SshClient(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - - var port1 = new ForwardedPortLocal("localhost", 8084, "www.google.com", 80); - client.AddForwardedPort(port1); - port1.Exception += delegate(object sender, ExceptionEventArgs e) - { - Assert.Fail(e.Exception.ToString()); - }; - - port1.Start(); - - var hasTestedTunnel = false; - - _ = ThreadPool.QueueUserWorkItem(delegate(object state) - { - try - { - var url = "http://www.google.com/"; - Debug.WriteLine("Starting web request to \"" + url + "\""); - -#if NET6_0_OR_GREATER - var httpClient = new HttpClient(); - var response = httpClient.GetAsync(url) - .ConfigureAwait(false) - .GetAwaiter() - .GetResult(); -#else - var request = (HttpWebRequest) WebRequest.Create(url); - var response = (HttpWebResponse) request.GetResponse(); -#endif // NET6_0_OR_GREATER - - Assert.IsNotNull(response); - - Debug.WriteLine("Http Response status code: " + response.StatusCode.ToString()); - - response.Dispose(); - - hasTestedTunnel = true; - } - catch (Exception ex) - { - Assert.Fail(ex.ToString()); - } - }); - - // Wait for the web request to complete. - while (!hasTestedTunnel) - { - Thread.Sleep(1000); - } - - try - { - // Try stop the port forwarding, wait 3 seconds and fail if it is still started. - _ = ThreadPool.QueueUserWorkItem(delegate(object state) - { - Debug.WriteLine("Trying to stop port forward."); - port1.Stop(); - Debug.WriteLine("Port forwarding stopped."); - }); - - Thread.Sleep(3000); - if (port1.IsStarted) - { - Assert.Fail("Port forwarding not stopped."); - } - } - catch (Exception ex) - { - Assert.Fail(ex.ToString()); - } - client.Disconnect(); - Debug.WriteLine("Success."); - } - } - [TestMethod] public void ConstructorShouldThrowArgumentNullExceptionWhenBoundHostIsNull() { @@ -177,132 +82,5 @@ public void ConstructorShouldNotThrowExceptionWhenHostIsInvalidDnsName() Assert.AreSame(host, forwardedPort.Host); } - - /// - ///A test for ForwardedPortRemote Constructor - /// - [TestMethod] - [TestCategory("integration")] - public void Test_ForwardedPortRemote() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - #region Example SshClient AddForwardedPort Start Stop ForwardedPortLocal - client.Connect(); - var port = new ForwardedPortLocal(8082, "www.cnn.com", 80); - client.AddForwardedPort(port); - port.Exception += delegate(object sender, ExceptionEventArgs e) - { - Console.WriteLine(e.Exception.ToString()); - }; - port.Start(); - - Thread.Sleep(1000 * 60 * 20); // Wait 20 minutes for port to be forwarded - - port.Stop(); - #endregion - } - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - [TestMethod] - [TestCategory("integration")] - [ExpectedException(typeof(SshConnectionException))] - public void Test_PortForwarding_Local_Without_Connecting() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - var port1 = new ForwardedPortLocal("localhost", 8084, "www.renci.org", 80); - client.AddForwardedPort(port1); - port1.Exception += delegate (object sender, ExceptionEventArgs e) - { - Assert.Fail(e.Exception.ToString()); - }; - port1.Start(); - - _ = Parallel.For(0, - 100, - counter => - { - var start = DateTime.Now; - -#if NET6_0_OR_GREATER - var httpClient = new HttpClient(); - using (var response = httpClient.GetAsync("http://localhost:8084").GetAwaiter().GetResult()) - { - var data = ReadStream(response.Content.ReadAsStream()); -#else - var request = (HttpWebRequest) WebRequest.Create("http://localhost:8084"); - using (var response = (HttpWebResponse) request.GetResponse()) - { - var data = ReadStream(response.GetResponseStream()); -#endif // NET6_0_OR_GREATER - var end = DateTime.Now; - - Debug.WriteLine(string.Format("Request# {2}: Lenght: {0} Time: {1}", data.Length, end - start, counter)); - } - }); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_PortForwarding_Local() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var port1 = new ForwardedPortLocal("localhost", 8084, "www.renci.org", 80); - client.AddForwardedPort(port1); - port1.Exception += delegate (object sender, ExceptionEventArgs e) - { - Assert.Fail(e.Exception.ToString()); - }; - port1.Start(); - - _ = Parallel.For(0, - 100, - counter => - { - var start = DateTime.Now; - -#if NET6_0_OR_GREATER - var httpClient = new HttpClient(); - using (var response = httpClient.GetAsync("http://localhost:8084").GetAwaiter().GetResult()) - { - var data = ReadStream(response.Content.ReadAsStream()); -#else - var request = (HttpWebRequest) WebRequest.Create("http://localhost:8084"); - using (var response = (HttpWebResponse) request.GetResponse()) - { - var data = ReadStream(response.GetResponseStream()); -#endif // NET6_0_OR_GREATER - var end = DateTime.Now; - - Debug.WriteLine(string.Format("Request# {2}: Length: {0} Time: {1}", data.Length, end - start, counter)); - } - }); - } - } - - private static byte[] ReadStream(System.IO.Stream stream) - { - var buffer = new byte[1024]; - using (var ms = new System.IO.MemoryStream()) - { - while (true) - { - var read = stream.Read(buffer, 0, buffer.Length); - if (read > 0) - { - ms.Write(buffer, 0, read); - } - else - { - return ms.ToArray(); - } - } - } - } } } diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs index 5f0777190..be6adef7b 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs @@ -1,12 +1,8 @@ 锘縰sing System; -using System.Net; -using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; namespace Renci.SshNet.Tests.Classes { @@ -16,64 +12,6 @@ namespace Renci.SshNet.Tests.Classes [TestClass] public partial class ForwardedPortRemoteTest : TestBase { - [TestMethod] - [Description("Test passing null to AddForwardedPort hosts (remote).")] - [ExpectedException(typeof(ArgumentNullException))] - [TestCategory("integration")] - public void Test_AddForwardedPort_Remote_Hosts_Are_Null() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var port1 = new ForwardedPortRemote(boundHost: null, 8080, host: null, 80); - client.AddForwardedPort(port1); - client.Disconnect(); - } - } - - [TestMethod] - [Description("Test passing invalid port numbers to AddForwardedPort.")] - [ExpectedException(typeof(ArgumentOutOfRangeException))] - [TestCategory("integration")] - public void Test_AddForwardedPort_Invalid_PortNumber() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var port1 = new ForwardedPortRemote("localhost", IPEndPoint.MaxPort + 1, "www.renci.org", IPEndPoint.MaxPort + 1); - client.AddForwardedPort(port1); - client.Disconnect(); - } - } - - /// - ///A test for ForwardedPortRemote Constructor - /// - [TestMethod] - [TestCategory("integration")] - public void Test_ForwardedPortRemote() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - #region Example SshClient AddForwardedPort Start Stop ForwardedPortRemote - client.Connect(); - var port = new ForwardedPortRemote(8082, "www.cnn.com", 80); - client.AddForwardedPort(port); - port.Exception += delegate(object sender, ExceptionEventArgs e) - { - Console.WriteLine(e.Exception.ToString()); - }; - port.Start(); - - Thread.Sleep(1000 * 60 * 20); // Wait 20 minutes for port to be forwarded - - port.Stop(); - #endregion - } - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// ///A test for Stop /// @@ -152,46 +90,5 @@ public void ForwardedPortRemoteConstructorTest1() var target = new ForwardedPortRemote(boundPort, host, port); Assert.Inconclusive("TODO: Implement code to verify target"); } - -#if FEATURE_TPL - [TestMethod] - [TestCategory("integration")] - public void Test_PortForwarding_Remote() - { - // ****************************************************************** - // ************* Tests are still in not finished ******************** - // ****************************************************************** - - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var port1 = new ForwardedPortRemote(8082, "www.renci.org", 80); - client.AddForwardedPort(port1); - port1.Exception += delegate (object sender, ExceptionEventArgs e) - { - Assert.Fail(e.Exception.ToString()); - }; - port1.Start(); - var boundport = port1.BoundPort; - - System.Threading.Tasks.Parallel.For(0, 5, - - //new ParallelOptions - //{ - // MaxDegreeOfParallelism = 1, - //}, - (counter) => - { - var cmd = client.CreateCommand(string.Format("wget -O- http://localhost:{0}", boundport)); - var result = cmd.Execute(); - var end = DateTime.Now; - System.Diagnostics.Debug.WriteLine(string.Format("Length: {0}", result.Length)); - } - ); - Thread.Sleep(1000 * 100); - port1.Stop(); - } - } -#endif // FEATURE_TPL } } diff --git a/src/Renci.SshNet.Tests/Classes/KeyboardInteractiveConnectionInfoTest.cs b/src/Renci.SshNet.Tests/Classes/KeyboardInteractiveConnectionInfoTest.cs index 0fc12c462..f50aaf9b7 100644 --- a/src/Renci.SshNet.Tests/Classes/KeyboardInteractiveConnectionInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/KeyboardInteractiveConnectionInfoTest.cs @@ -1,8 +1,6 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; + using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; -using System; namespace Renci.SshNet.Tests.Classes { @@ -12,40 +10,6 @@ namespace Renci.SshNet.Tests.Classes [TestClass] public class KeyboardInteractiveConnectionInfoTest : TestBase { - [TestMethod] - [TestCategory("KeyboardInteractiveConnectionInfo")] - [TestCategory("integration")] - public void Test_KeyboardInteractiveConnectionInfo() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - - #region Example KeyboardInteractiveConnectionInfo AuthenticationPrompt - var connectionInfo = new KeyboardInteractiveConnectionInfo(host, username); - connectionInfo.AuthenticationPrompt += delegate(object sender, AuthenticationPromptEventArgs e) - { - System.Console.WriteLine(e.Instruction); - - foreach (var prompt in e.Prompts) - { - Console.WriteLine(prompt.Request); - prompt.Response = Console.ReadLine(); - } - }; - - using (var client = new SftpClient(connectionInfo)) - { - client.Connect(); - // Do something here - client.Disconnect(); - } - #endregion - - Assert.AreEqual(connectionInfo.Host, Resources.HOST); - Assert.AreEqual(connectionInfo.Username, Resources.USERNAME); - } - /// ///A test for Dispose /// @@ -192,4 +156,4 @@ public void KeyboardInteractiveConnectionInfoConstructorTest7() Assert.Inconclusive("TODO: Implement code to verify target"); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs b/src/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs index ec0d3fef8..951314d1c 100644 --- a/src/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs @@ -1,6 +1,5 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; using System; namespace Renci.SshNet.Tests.Classes @@ -59,32 +58,6 @@ public void Password_Test_Pass_Valid() new PasswordAuthenticationMethod("valid", string.Empty); } - [TestMethod] - [WorkItem(1140)] - [TestCategory("BaseClient")] - [TestCategory("integration")] - [Description("Test whether IsConnected is false after disconnect.")] - [Owner("Kenneth_aa")] - public void Test_BaseClient_IsConnected_True_After_Disconnect() - { - // 2012-04-29 - Kenneth_aa - // The problem with this test, is that after SSH Net calls .Disconnect(), the library doesn't wait - // for the server to confirm disconnect before IsConnected is checked. And now I'm not mentioning - // anything about Socket's either. - - var connectionInfo = new PasswordAuthenticationMethod(Resources.USERNAME, Resources.PASSWORD); - - using (SftpClient client = new SftpClient(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - Assert.AreEqual(true, client.IsConnected, "IsConnected is not true after Connect() was called."); - - client.Disconnect(); - - Assert.AreEqual(false, client.IsConnected, "IsConnected is true after Disconnect() was called."); - } - } - /// ///A test for Name /// @@ -158,4 +131,4 @@ public void PasswordAuthenticationMethodConstructorTest1() Assert.Inconclusive("TODO: Implement code to verify target"); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs b/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs index 824f649f1..56a510140 100644 --- a/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs @@ -1,5 +1,4 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; using System; @@ -13,84 +12,6 @@ namespace Renci.SshNet.Tests.Classes [TestClass] public class PasswordConnectionInfoTest : TestBase { - [TestMethod] - [TestCategory("PasswordConnectionInfo")] - [TestCategory("integration")] - public void Test_PasswordConnectionInfo() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - - #region Example PasswordConnectionInfo - var connectionInfo = new PasswordConnectionInfo(host, username, password); - using (var client = new SftpClient(connectionInfo)) - { - client.Connect(); - // Do something here - client.Disconnect(); - } - #endregion - - Assert.AreEqual(connectionInfo.Host, Resources.HOST); - Assert.AreEqual(connectionInfo.Username, Resources.USERNAME); - } - - [TestMethod] - [TestCategory("PasswordConnectionInfo")] - [TestCategory("integration")] - public void Test_PasswordConnectionInfo_PasswordExpired() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - - #region Example PasswordConnectionInfo PasswordExpired - var connectionInfo = new PasswordConnectionInfo("host", "username", "password"); - var encoding = SshData.Ascii; - connectionInfo.PasswordExpired += delegate(object sender, AuthenticationPasswordChangeEventArgs e) - { - e.NewPassword = encoding.GetBytes("123456"); - }; - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - - client.Disconnect(); - } - #endregion - - Assert.Inconclusive(); - } - [TestMethod] - [TestCategory("PasswordConnectionInfo")] - [TestCategory("integration")] - public void Test_PasswordConnectionInfo_AuthenticationBanner() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - - #region Example PasswordConnectionInfo AuthenticationBanner - var connectionInfo = new PasswordConnectionInfo(host, username, password); - connectionInfo.AuthenticationBanner += delegate(object sender, AuthenticationBannerEventArgs e) - { - Console.WriteLine(e.BannerMessage); - }; - using (var client = new SftpClient(connectionInfo)) - { - client.Connect(); - // Do something here - client.Disconnect(); - } - #endregion - - Assert.AreEqual(connectionInfo.Host, Resources.HOST); - Assert.AreEqual(connectionInfo.Username, Resources.USERNAME); - } - - [WorkItem(703), TestMethod] [TestCategory("PasswordConnectionInfo")] public void Test_ConnectionInfo_Host_Is_Null() @@ -148,60 +69,7 @@ public void Test_ConnectionInfo_BigPortNumber() { _ = new PasswordConnectionInfo(Resources.HOST, IPEndPoint.MaxPort + 1, Resources.USERNAME, Resources.PASSWORD); } - - [TestMethod] - [Owner("Kenneth_aa")] - [Description("Test connect to remote server via a SOCKS4 proxy server.")] - [TestCategory("Proxy")] - [TestCategory("integration")] - public void Test_Ssh_Connect_Via_Socks4() - { - var connInfo = new PasswordConnectionInfo(Resources.HOST, Resources.USERNAME, Resources.PASSWORD, ProxyTypes.Socks4, Resources.PROXY_HOST, int.Parse(Resources.PROXY_PORT)); - using (var client = new SshClient(connInfo)) - { - client.Connect(); - - var ret = client.RunCommand("ls -la"); - - client.Disconnect(); - } - } - - [TestMethod] - [Owner("Kenneth_aa")] - [Description("Test connect to remote server via a TCP SOCKS5 proxy server.")] - [TestCategory("Proxy")] - [TestCategory("integration")] - public void Test_Ssh_Connect_Via_TcpSocks5() - { - var connInfo = new PasswordConnectionInfo(Resources.HOST, Resources.USERNAME, Resources.PASSWORD, ProxyTypes.Socks5, Resources.PROXY_HOST, int.Parse(Resources.PROXY_PORT)); - using (var client = new SshClient(connInfo)) - { - client.Connect(); - - var ret = client.RunCommand("ls -la"); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("Kenneth_aa")] - [Description("Test connect to remote server via a HTTP proxy server.")] - [TestCategory("Proxy")] - [TestCategory("integration")] - public void Test_Ssh_Connect_Via_HttpProxy() - { - var connInfo = new PasswordConnectionInfo(Resources.HOST, Resources.USERNAME, Resources.PASSWORD, ProxyTypes.Http, Resources.PROXY_HOST, int.Parse(Resources.PROXY_PORT)); - using (var client = new SshClient(connInfo)) - { - client.Connect(); - - var ret = client.RunCommand("ls -la"); - - client.Disconnect(); - } - } - + /// ///A test for Dispose /// diff --git a/src/Renci.SshNet.Tests/Classes/PrivateKeyConnectionInfoTest.cs b/src/Renci.SshNet.Tests/Classes/PrivateKeyConnectionInfoTest.cs index f8c863ba0..40a781174 100644 --- a/src/Renci.SshNet.Tests/Classes/PrivateKeyConnectionInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PrivateKeyConnectionInfoTest.cs @@ -1,8 +1,5 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; -using System.IO; -using System.Text; namespace Renci.SshNet.Tests.Classes { @@ -12,53 +9,6 @@ namespace Renci.SshNet.Tests.Classes [TestClass] public class PrivateKeyConnectionInfoTest : TestBase { - [TestMethod] - [TestCategory("PrivateKeyConnectionInfo")] - [TestCategory("integration")] - public void Test_PrivateKeyConnectionInfo() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - MemoryStream keyFileStream = new MemoryStream(Encoding.ASCII.GetBytes(Resources.RSA_KEY_WITHOUT_PASS)); - - #region Example PrivateKeyConnectionInfo PrivateKeyFile - var connectionInfo = new PrivateKeyConnectionInfo(host, username, new PrivateKeyFile(keyFileStream)); - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - #endregion - - Assert.AreEqual(connectionInfo.Host, Resources.HOST); - Assert.AreEqual(connectionInfo.Username, Resources.USERNAME); - } - - [TestMethod] - [TestCategory("PrivateKeyConnectionInfo")] - [TestCategory("integration")] - public void Test_PrivateKeyConnectionInfo_MultiplePrivateKey() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - MemoryStream keyFileStream1 = new MemoryStream(Encoding.ASCII.GetBytes(Resources.RSA_KEY_WITHOUT_PASS)); - MemoryStream keyFileStream2 = new MemoryStream(Encoding.ASCII.GetBytes(Resources.RSA_KEY_WITHOUT_PASS)); - - #region Example PrivateKeyConnectionInfo PrivateKeyFile Multiple - var connectionInfo = new PrivateKeyConnectionInfo(host, username, - new PrivateKeyFile(keyFileStream1), - new PrivateKeyFile(keyFileStream2)); - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - #endregion - - Assert.AreEqual(connectionInfo.Host, Resources.HOST); - Assert.AreEqual(connectionInfo.Username, Resources.USERNAME); - } - /// ///A test for Dispose /// @@ -214,4 +164,4 @@ public void PrivateKeyConnectionInfoConstructorTest7() Assert.Inconclusive("TODO: Implement code to verify target"); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs index a9af0c3dd..bcdf93966 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs @@ -1,15 +1,11 @@ 锘縰sing System; using System.IO; -using System.Linq; -using System.Security.Cryptography; using System.Text; -using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; namespace Renci.SshNet.Tests.Classes { @@ -219,203 +215,6 @@ public void RemotePathTransformation_Value_Null() Assert.AreSame(RemotePathTransformation.ShellQuote, client.RemotePathTransformation); } - [TestMethod] - [TestCategory("Scp")] - [TestCategory("integration")] - public void Test_Scp_File_Upload_Download() - { - RemoveAllFiles(); - - using (var scp = new ScpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - scp.Connect(); - - var uploadedFileName = Path.GetTempFileName(); - var downloadedFileName = Path.GetTempFileName(); - - CreateTestFile(uploadedFileName, 1); - - scp.Upload(new FileInfo(uploadedFileName), Path.GetFileName(uploadedFileName)); - - scp.Download(Path.GetFileName(uploadedFileName), new FileInfo(downloadedFileName)); - - // Calculate MD5 value - var uploadedHash = CalculateMD5(uploadedFileName); - var downloadedHash = CalculateMD5(downloadedFileName); - - File.Delete(uploadedFileName); - File.Delete(downloadedFileName); - - scp.Disconnect(); - - Assert.AreEqual(uploadedHash, downloadedHash); - } - } - - [TestMethod] - [TestCategory("Scp")] - [TestCategory("integration")] - public void Test_Scp_Stream_Upload_Download() - { - RemoveAllFiles(); - - using (var scp = new ScpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - scp.Connect(); - - var uploadedFileName = Path.GetTempFileName(); - var downloadedFileName = Path.GetTempFileName(); - - CreateTestFile(uploadedFileName, 1); - - // Calculate has value - using (var stream = File.OpenRead(uploadedFileName)) - { - scp.Upload(stream, Path.GetFileName(uploadedFileName)); - } - - using (var stream = File.OpenWrite(downloadedFileName)) - { - scp.Download(Path.GetFileName(uploadedFileName), stream); - } - - // Calculate MD5 value - var uploadedHash = CalculateMD5(uploadedFileName); - var downloadedHash = CalculateMD5(downloadedFileName); - - File.Delete(uploadedFileName); - File.Delete(downloadedFileName); - - scp.Disconnect(); - - Assert.AreEqual(uploadedHash, downloadedHash); - } - } - - [TestMethod] - [TestCategory("Scp")] - [TestCategory("integration")] - public void Test_Scp_10MB_File_Upload_Download() - { - RemoveAllFiles(); - - using (var scp = new ScpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - scp.Connect(); - - var uploadedFileName = Path.GetTempFileName(); - var downloadedFileName = Path.GetTempFileName(); - - CreateTestFile(uploadedFileName, 10); - - scp.Upload(new FileInfo(uploadedFileName), Path.GetFileName(uploadedFileName)); - - scp.Download(Path.GetFileName(uploadedFileName), new FileInfo(downloadedFileName)); - - // Calculate MD5 value - var uploadedHash = CalculateMD5(uploadedFileName); - var downloadedHash = CalculateMD5(downloadedFileName); - - File.Delete(uploadedFileName); - File.Delete(downloadedFileName); - - scp.Disconnect(); - - Assert.AreEqual(uploadedHash, downloadedHash); - } - } - - [TestMethod] - [TestCategory("Scp")] - [TestCategory("integration")] - public void Test_Scp_10MB_Stream_Upload_Download() - { - RemoveAllFiles(); - - using (var scp = new ScpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - scp.Connect(); - - var uploadedFileName = Path.GetTempFileName(); - var downloadedFileName = Path.GetTempFileName(); - - CreateTestFile(uploadedFileName, 10); - - // Calculate has value - using (var stream = File.OpenRead(uploadedFileName)) - { - scp.Upload(stream, Path.GetFileName(uploadedFileName)); - } - - using (var stream = File.OpenWrite(downloadedFileName)) - { - scp.Download(Path.GetFileName(uploadedFileName), stream); - } - - // Calculate MD5 value - var uploadedHash = CalculateMD5(uploadedFileName); - var downloadedHash = CalculateMD5(downloadedFileName); - - File.Delete(uploadedFileName); - File.Delete(downloadedFileName); - - scp.Disconnect(); - - Assert.AreEqual(uploadedHash, downloadedHash); - } - } - - [TestMethod] - [TestCategory("Scp")] - [TestCategory("integration")] - public void Test_Scp_Directory_Upload_Download() - { - RemoveAllFiles(); - - using (var scp = new ScpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - scp.Connect(); - - var uploadDirectory = - Directory.CreateDirectory(string.Format("{0}\\{1}", Path.GetTempPath(), Path.GetRandomFileName())); - for (var i = 0; i < 3; i++) - { - var subfolder = Directory.CreateDirectory(string.Format(@"{0}\folder_{1}", uploadDirectory.FullName, i)); - - for (var j = 0; j < 5; j++) - { - CreateTestFile(string.Format(@"{0}\file_{1}", subfolder.FullName, j), 1); - } - - CreateTestFile(string.Format(@"{0}\file_{1}", uploadDirectory.FullName, i), 1); - } - - scp.Upload(uploadDirectory, "uploaded_dir"); - - var downloadDirectory = - Directory.CreateDirectory(string.Format("{0}\\{1}", Path.GetTempPath(), Path.GetRandomFileName())); - - scp.Download("uploaded_dir", downloadDirectory); - - var uploadedFiles = uploadDirectory.GetFiles("*.*", SearchOption.AllDirectories); - var downloadFiles = downloadDirectory.GetFiles("*.*", SearchOption.AllDirectories); - - var result = from f1 in uploadedFiles - from f2 in downloadFiles - where - f1.FullName.Substring(uploadDirectory.FullName.Length) == - f2.FullName.Substring(downloadDirectory.FullName.Length) - && CalculateMD5(f1.FullName) == CalculateMD5(f2.FullName) - select f1; - - var counter = result.Count(); - - scp.Disconnect(); - - Assert.IsTrue(counter == uploadedFiles.Length && uploadedFiles.Length == downloadFiles.Length); - } - } - /// ///A test for OperationTimeout /// @@ -539,133 +338,6 @@ public void DownloadTest2() Assert.Inconclusive("A method that does not return a value cannot be verified."); } - [TestMethod] - [TestCategory("Scp")] - [TestCategory("integration")] - public void Test_Scp_File_20_Parallel_Upload_Download() - { - using (var scp = new ScpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - scp.Connect(); - - var uploadFilenames = new string[20]; - for (var i = 0; i < uploadFilenames.Length; i++) - { - uploadFilenames[i] = Path.GetTempFileName(); - CreateTestFile(uploadFilenames[i], 1); - } - - _ = Parallel.ForEach(uploadFilenames, - filename => - { - scp.Upload(new FileInfo(filename), Path.GetFileName(filename)); - }); - _ = Parallel.ForEach(uploadFilenames, - filename => - { - scp.Download(Path.GetFileName(filename), new FileInfo(string.Format("{0}.down", filename))); - }); - - var result = from file in uploadFilenames - where CalculateMD5(file) == CalculateMD5(string.Format("{0}.down", file)) - select file; - - scp.Disconnect(); - - Assert.IsTrue(result.Count() == uploadFilenames.Length); - } - } - - [TestMethod] - [TestCategory("Scp")] - [TestCategory("integration")] - public void Test_Scp_File_Upload_Download_Events() - { - using (var scp = new ScpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - scp.Connect(); - - var uploadFilenames = new string[10]; - - for (var i = 0; i < uploadFilenames.Length; i++) - { - uploadFilenames[i] = Path.GetTempFileName(); - CreateTestFile(uploadFilenames[i], 1); - } - - var uploadedFiles = uploadFilenames.ToDictionary(Path.GetFileName, (filename) => 0L); - var downloadedFiles = uploadFilenames.ToDictionary((filename) => string.Format("{0}.down", Path.GetFileName(filename)), (filename) => 0L); - - scp.Uploading += delegate (object sender, ScpUploadEventArgs e) - { - uploadedFiles[e.Filename] = e.Uploaded; - }; - - scp.Downloading += delegate (object sender, ScpDownloadEventArgs e) - { - downloadedFiles[string.Format("{0}.down", e.Filename)] = e.Downloaded; - }; - - _ = Parallel.ForEach(uploadFilenames, - filename => - { - scp.Upload(new FileInfo(filename), Path.GetFileName(filename)); - }); - _ = Parallel.ForEach(uploadFilenames, - filename => - { - scp.Download(Path.GetFileName(filename), new FileInfo(string.Format("{0}.down", filename))); - }); - - var result = from uf in uploadedFiles - from df in downloadedFiles - where string.Format("{0}.down", uf.Key) == df.Key && uf.Value == df.Value - select uf; - - scp.Disconnect(); - - Assert.IsTrue(result.Count() == uploadFilenames.Length && uploadFilenames.Length == uploadedFiles.Count && uploadedFiles.Count == downloadedFiles.Count); - } - } - - protected static string CalculateMD5(string fileName) - { - using (var file = new FileStream(fileName, FileMode.Open)) - { -#if NET7_0_OR_GREATER - var hash = MD5.HashData(file); -#else -#if NET6_0 - var md5 = MD5.Create(); -#else - MD5 md5 = new MD5CryptoServiceProvider(); -#endif // NET6_0 - var hash = md5.ComputeHash(file); -#endif // NET7_0_OR_GREATER - - file.Close(); - - var sb = new StringBuilder(); - - for (var i = 0; i < hash.Length; i++) - { - _ = sb.Append(i.ToString("x2")); - } - - return sb.ToString(); - } - } - - private static void RemoveAllFiles() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - _ = client.RunCommand("rm -rf *"); - client.Disconnect(); - } - } - private PrivateKeyFile GetRsaKey() { using (var stream = GetData("Key.RSA.txt")) diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs index ef6b69197..03a2e34e9 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs @@ -3,7 +3,6 @@ using Renci.SshNet.Security.Cryptography.Ciphers; using Renci.SshNet.Security.Cryptography.Ciphers.Modes; using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers { @@ -84,125 +83,6 @@ public void Decrypt_InputAndOffsetAndLength_128_CTR() Assert.IsTrue(expected.IsEqualTo(actual)); } - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - [TestCategory("integration")] - public void Test_Cipher_AEes128CBC_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes128-cbc", new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - [TestCategory("integration")] - public void Test_Cipher_Aes192CBC_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes192-cbc", new CipherInfo(192, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - [TestCategory("integration")] - public void Test_Cipher_Aes256CBC_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes256-cbc", new CipherInfo(256, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - [TestCategory("integration")] - public void Test_Cipher_Aes128CTR_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes128-ctr", new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CtrCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - [TestCategory("integration")] - public void Test_Cipher_Aes192CTR_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes192-ctr", new CipherInfo(192, (key, iv) => { return new AesCipher(key, new CtrCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - [TestCategory("integration")] - public void Test_Cipher_Aes256CTR_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes256-ctr", new CipherInfo(256, (key, iv) => { return new AesCipher(key, new CtrCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - [TestCategory("integration")] - public void Test_Cipher_Arcfour_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("arcfour", new CipherInfo(128, (key, iv) => { return new Arc4Cipher(key, false); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - /// ///A test for DecryptBlock /// @@ -263,4 +143,4 @@ public void EncryptBlockTest() Assert.Inconclusive("Verify the correctness of this test method."); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs index f83aa7aa5..5b972021b 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs @@ -3,7 +3,6 @@ using Renci.SshNet.Common; using Renci.SshNet.Security.Cryptography.Ciphers; using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers { @@ -156,40 +155,5 @@ public void EncryptBlockTest() Assert.AreEqual(expected, actual); Assert.Inconclusive("Verify the correctness of this test method."); } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - [TestCategory("integration")] - public void Test_Cipher_Arcfour128_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("arcfour128", new CipherInfo(128, (key, iv) => { return new Arc4Cipher(key, true); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - [TestCategory("integration")] - public void Test_Cipher_Arcfour256_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("arcfour256", new CipherInfo(256, (key, iv) => { return new Arc4Cipher(key, true); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs index 1c2d0aec8..168b1eaf8 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs @@ -2,7 +2,7 @@ using Renci.SshNet.Security.Cryptography.Ciphers; using Renci.SshNet.Security.Cryptography.Ciphers.Modes; using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; + using System.Linq; namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers @@ -29,23 +29,6 @@ public void Test_Cipher_Blowfish_128_CBC() } } - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - [TestCategory("integration")] - public void Test_Cipher_BlowfishCBC_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("blowfish-cbc", new CipherInfo(128, (key, iv) => { return new BlowfishCipher(key, new CbcCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - /// ///A test for BlowfishCipher Constructor /// diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs index c077a3098..a04c5f2db 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs @@ -2,7 +2,7 @@ using Renci.SshNet.Security.Cryptography.Ciphers; using Renci.SshNet.Security.Cryptography.Ciphers.Modes; using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; + using System.Linq; namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers @@ -39,22 +39,6 @@ public void Decrypt_128_CBC() Assert.IsTrue(r.SequenceEqual(input)); } - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - [TestCategory("integration")] - public void Test_Cipher_Cast128CBC_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("cast128-cbc", new CipherInfo(128, (key, iv) => { return new CastCipher(key, new CbcCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } /// ///A test for CastCipher Constructor /// @@ -115,4 +99,4 @@ public void EncryptBlockTest() Assert.Inconclusive("Verify the correctness of this test method."); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs index 5b4f97bac..9dc6a2b65 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs @@ -5,8 +5,6 @@ using Renci.SshNet.Security.Cryptography.Ciphers; using Renci.SshNet.Security.Cryptography.Ciphers.Modes; using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; - namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers { @@ -32,22 +30,6 @@ public void Test_Cipher_3DES_CBC() } } - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - [TestCategory("integration")] - public void Test_Cipher_TripleDESCBC_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("3des-cbc", new CipherInfo(192, (key, iv) => { return new TripleDesCipher(key, new CbcCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } /// ///A test for TripleDesCipher Constructor /// diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/HMacTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/HMacTest.cs deleted file mode 100644 index 94e558b2a..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/HMacTest.cs +++ /dev/null @@ -1,134 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; -using Renci.SshNet.Abstractions; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography -{ - /// - /// Provides HMAC algorithm implementation. - /// - [TestClass] - public class HMacTest : TestBase - { - [TestMethod] - [TestCategory("integration")] - public void Test_HMac_MD5_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-md5", new HashInfo(16 * 8, CryptoAbstraction.CreateHMACMD5)); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_HMac_Sha1_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-sha1", new HashInfo(20 * 8, CryptoAbstraction.CreateHMACSHA1)); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_HMac_MD5_96_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-md5", new HashInfo(16 * 8, key => CryptoAbstraction.CreateHMACMD5(key, 96))); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_HMac_Sha1_96_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-sha1", new HashInfo(20 * 8, key => CryptoAbstraction.CreateHMACSHA1(key, 96))); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_HMac_Sha256_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-sha2-256", new HashInfo(32 * 8, CryptoAbstraction.CreateHMACSHA256)); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_HMac_Sha256_96_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-sha2-256-96", new HashInfo(32 * 8, (key) => CryptoAbstraction.CreateHMACSHA256(key, 96))); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_HMac_RIPEMD160_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-ripemd160", new HashInfo(160, CryptoAbstraction.CreateHMACRIPEMD160)); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_HMac_RIPEMD160_OPENSSH_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-ripemd160@openssh.com", new HashInfo(160, CryptoAbstraction.CreateHMACRIPEMD160)); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyHostAlgorithmTest.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyHostAlgorithmTest.cs deleted file mode 100644 index 9bd5d10c3..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/KeyHostAlgorithmTest.cs +++ /dev/null @@ -1,123 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; - -namespace Renci.SshNet.Tests.Classes.Security -{ - /// - /// Implements key support for host algorithm. - /// - [TestClass] - public class KeyHostAlgorithmTest : TestBase - { - [TestMethod] - [TestCategory("integration")] - public void Test_HostKey_SshRsa_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.HostKeyAlgorithms.Clear(); - connectionInfo.HostKeyAlgorithms.Add("ssh-rsa", (data) => { return new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data); }); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_HostKey_SshDss_Connection() - { - var connectionInfo = new PasswordConnectionInfo(Resources.HOST, int.Parse(Resources.PORT), Resources.USERNAME, Resources.PASSWORD); - connectionInfo.HostKeyAlgorithms.Clear(); - connectionInfo.HostKeyAlgorithms.Add("ssh-dss", (data) => { return new KeyHostAlgorithm("ssh-dss", new DsaKey(), data); }); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - /// - ///A test for KeyHostAlgorithm Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyHostAlgorithmConstructorTest() - { - string name = string.Empty; // TODO: Initialize to an appropriate value - Key key = null; // TODO: Initialize to an appropriate value - KeyHostAlgorithm target = new KeyHostAlgorithm(name, key); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for KeyHostAlgorithm Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyHostAlgorithmConstructorTest1() - { - string name = string.Empty; // TODO: Initialize to an appropriate value - Key key = null; // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - KeyHostAlgorithm target = new KeyHostAlgorithm(name, key, data); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for Sign - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SignTest() - { - string name = string.Empty; // TODO: Initialize to an appropriate value - Key key = null; // TODO: Initialize to an appropriate value - KeyHostAlgorithm target = new KeyHostAlgorithm(name, key); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Sign(data); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for VerifySignature - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void VerifySignatureTest() - { - string name = string.Empty; // TODO: Initialize to an appropriate value - Key key = null; // TODO: Initialize to an appropriate value - KeyHostAlgorithm target = new KeyHostAlgorithm(name, key); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - byte[] signature = null; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - actual = target.VerifySignature(data, signature); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Data - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DataTest() - { - string name = string.Empty; // TODO: Initialize to an appropriate value - Key key = null; // TODO: Initialize to an appropriate value - KeyHostAlgorithm target = new KeyHostAlgorithm(name, key); // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Data; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileTest.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileTest.cs index d1716a957..285d4aa51 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileTest.cs @@ -1,10 +1,9 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; + using Renci.SshNet.Sftp; using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; + using System; -using System.IO; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -14,121 +13,6 @@ namespace Renci.SshNet.Tests.Classes.Sftp [TestClass] public class SftpFileTest : TestBase { - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - public void Test_Get_Root_Directory() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - var directory = sftp.Get("/"); - - Assert.AreEqual("/", directory.FullName); - Assert.IsTrue(directory.IsDirectory); - Assert.IsFalse(directory.IsRegularFile); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [ExpectedException(typeof(SftpPathNotFoundException))] - public void Test_Get_Invalid_Directory() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - sftp.Get("/xyz"); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - public void Test_Get_File() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - sftp.UploadFile(new MemoryStream(), "abc.txt"); - - var file = sftp.Get("abc.txt"); - - Assert.AreEqual("/home/tester/abc.txt", file.FullName); - Assert.IsTrue(file.IsRegularFile); - Assert.IsFalse(file.IsDirectory); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [Description("Test passing null to Get.")] - [ExpectedException(typeof(ArgumentNullException))] - public void Test_Get_File_Null() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - var file = sftp.Get(null); - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - public void Test_Get_International_File() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - sftp.UploadFile(new MemoryStream(), "test-眉枚盲-"); - - var file = sftp.Get("test-眉枚盲-"); - - Assert.AreEqual("/home/tester/test-眉枚盲-", file.FullName); - Assert.IsTrue(file.IsRegularFile); - Assert.IsFalse(file.IsDirectory); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - public void Test_Sftp_SftpFile_MoveTo() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - string uploadedFileName = Path.GetTempFileName(); - string remoteFileName = Path.GetRandomFileName(); - string newFileName = Path.GetRandomFileName(); - - this.CreateTestFile(uploadedFileName, 1); - - using (var file = File.OpenRead(uploadedFileName)) - { - sftp.UploadFile(file, remoteFileName); - } - - var sftpFile = sftp.Get(remoteFileName); - - sftpFile.MoveTo(newFileName); - - Assert.AreEqual(newFileName, sftpFile.Name); - - sftp.Disconnect(); - } - } - /// ///A test for Delete /// @@ -623,4 +507,4 @@ public void UserIdTest() } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs index 9ae69f6ec..c2798104a 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs @@ -20,7 +20,7 @@ public void Connect_HostNameInvalid_ShouldThrowSocketExceptionWithErrorCodeHostN } catch (SocketException ex) { - Assert.AreEqual(ex.ErrorCode, (int) SocketError.HostNotFound); + Assert.IsTrue(ex.ErrorCode is (int) SocketError.HostNotFound or (int) SocketError.TryAgain); } } @@ -38,7 +38,7 @@ public void Connect_ProxyHostNameInvalid_ShouldThrowSocketExceptionWithErrorCode } catch (SocketException ex) { - Assert.AreEqual(ex.ErrorCode, (int)SocketError.HostNotFound); + Assert.IsTrue(ex.ErrorCode is (int) SocketError.HostNotFound or (int) SocketError.TryAgain); } } } diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.CreateDirectory.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.CreateDirectory.cs deleted file mode 100644 index 73e5f3c83..000000000 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.CreateDirectory.cs +++ /dev/null @@ -1,106 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Properties; -using System; - -namespace Renci.SshNet.Tests.Classes -{ - /// - /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. - /// - public partial class SftpClientTest - { - [TestMethod] - [TestCategory("Sftp")] - [ExpectedException(typeof(SshConnectionException))] - public void Test_Sftp_CreateDirectory_Without_Connecting() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.CreateDirectory("test"); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - public void Test_Sftp_CreateDirectory_In_Current_Location() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - sftp.CreateDirectory("test"); - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [ExpectedException(typeof(SftpPermissionDeniedException))] - public void Test_Sftp_CreateDirectory_In_Forbidden_Directory() - { - if (Resources.USERNAME == "root") - { - Assert.Fail("Must not run this test as root!"); - } - - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - sftp.CreateDirectory("/sbin/test"); - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [ExpectedException(typeof(SftpPathNotFoundException))] - public void Test_Sftp_CreateDirectory_Invalid_Path() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - sftp.CreateDirectory("/abcdefg/abcefg"); - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [ExpectedException(typeof(SshException))] - public void Test_Sftp_CreateDirectory_Already_Exists() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - sftp.CreateDirectory("test"); - - sftp.CreateDirectory("test"); - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [Description("Test passing null to CreateDirectory.")] - [ExpectedException(typeof(ArgumentException))] - public void Test_Sftp_CreateDirectory_Null() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.CreateDirectory(null); - } - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs index 0964d4690..d25fb37fd 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs @@ -1,7 +1,6 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; using Renci.SshNet.Tests.Properties; -using System; namespace Renci.SshNet.Tests.Classes { @@ -20,75 +19,5 @@ public void Test_Sftp_DeleteDirectory_Without_Connecting() sftp.DeleteDirectory("test"); } } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [ExpectedException(typeof(SftpPathNotFoundException))] - public void Test_Sftp_DeleteDirectory_Which_Doesnt_Exists() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - sftp.DeleteDirectory("abcdef"); - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [ExpectedException(typeof(SftpPermissionDeniedException))] - public void Test_Sftp_DeleteDirectory_Which_No_Permissions() - { - if (Resources.USERNAME == "root") - { - Assert.Fail("Must not run this test as root!"); - } - - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - sftp.DeleteDirectory("/usr"); - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - public void Test_Sftp_DeleteDirectory() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - sftp.CreateDirectory("abcdef"); - sftp.DeleteDirectory("abcdef"); - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [Description("Test passing null to DeleteDirectory.")] - [ExpectedException(typeof(ArgumentException))] - public void Test_Sftp_DeleteDirectory_Null() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - sftp.DeleteDirectory(null); - - sftp.Disconnect(); - } - } } } diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs index 6a19ce5a3..ceafd4c50 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs @@ -1,13 +1,8 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; using Renci.SshNet.Tests.Properties; -using System; + using System.Diagnostics; -using System.Linq; -#if NET6_0_OR_GREATER -using System.Threading; -using System.Threading.Tasks; -#endif namespace Renci.SshNet.Tests.Classes { @@ -30,267 +25,5 @@ public void Test_Sftp_ListDirectory_Without_Connecting() } } } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [ExpectedException(typeof(SftpPermissionDeniedException))] - public void Test_Sftp_ListDirectory_Permission_Denied() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - var files = sftp.ListDirectory("/root"); - foreach (var file in files) - { - Debug.WriteLine(file.FullName); - } - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [ExpectedException(typeof(SftpPathNotFoundException))] - public void Test_Sftp_ListDirectory_Not_Exists() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - var files = sftp.ListDirectory("/asdfgh"); - foreach (var file in files) - { - Debug.WriteLine(file.FullName); - } - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - public void Test_Sftp_ListDirectory_Current() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - var files = sftp.ListDirectory("."); - - Assert.IsTrue(files.Count() > 0); - - foreach (var file in files) - { - Debug.WriteLine(file.FullName); - } - - sftp.Disconnect(); - } - } - -#if NET6_0_OR_GREATER - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - public async Task Test_Sftp_ListDirectoryAsync_Current() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - var cts = new CancellationTokenSource(); - cts.CancelAfter(TimeSpan.FromMinutes(1)); - var count = 0; - await foreach(var file in sftp.ListDirectoryAsync(".", cts.Token)) - { - count++; - Debug.WriteLine(file.FullName); - } - - Assert.IsTrue(count > 0); - - sftp.Disconnect(); - } - } -#endif - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - public void Test_Sftp_ListDirectory_Empty() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - var files = sftp.ListDirectory(string.Empty); - - Assert.IsTrue(files.Count() > 0); - - foreach (var file in files) - { - Debug.WriteLine(file.FullName); - } - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [Description("Test passing null to ListDirectory.")] - [ExpectedException(typeof(ArgumentNullException))] - public void Test_Sftp_ListDirectory_Null() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - var files = sftp.ListDirectory(null); - - Assert.IsTrue(files.Count() > 0); - - foreach (var file in files) - { - Debug.WriteLine(file.FullName); - } - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - public void Test_Sftp_ListDirectory_HugeDirectory() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - // Create 10000 directory items - for (int i = 0; i < 10000; i++) - { - sftp.CreateDirectory(string.Format("test_{0}", i)); - Debug.WriteLine("Created " + i); - } - - var files = sftp.ListDirectory("."); - - // Ensure that directory has at least 10000 items - Assert.IsTrue(files.Count() > 10000); - - sftp.Disconnect(); - } - - RemoveAllFiles(); - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - public void Test_Sftp_Change_Directory() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - Assert.AreEqual(sftp.WorkingDirectory, "/home/tester"); - - sftp.CreateDirectory("test1"); - - sftp.ChangeDirectory("test1"); - - Assert.AreEqual(sftp.WorkingDirectory, "/home/tester/test1"); - - sftp.CreateDirectory("test1_1"); - sftp.CreateDirectory("test1_2"); - sftp.CreateDirectory("test1_3"); - - var files = sftp.ListDirectory("."); - - Assert.IsTrue(files.First().FullName.StartsWith(string.Format("{0}", sftp.WorkingDirectory))); - - sftp.ChangeDirectory("test1_1"); - - Assert.AreEqual(sftp.WorkingDirectory, "/home/tester/test1/test1_1"); - - sftp.ChangeDirectory("../test1_2"); - - Assert.AreEqual(sftp.WorkingDirectory, "/home/tester/test1/test1_2"); - - sftp.ChangeDirectory(".."); - - Assert.AreEqual(sftp.WorkingDirectory, "/home/tester/test1"); - - sftp.ChangeDirectory(".."); - - Assert.AreEqual(sftp.WorkingDirectory, "/home/tester"); - - files = sftp.ListDirectory("test1/test1_1"); - - Assert.IsTrue(files.First().FullName.StartsWith(string.Format("{0}/test1/test1_1", sftp.WorkingDirectory))); - - sftp.ChangeDirectory("test1/test1_1"); - - Assert.AreEqual(sftp.WorkingDirectory, "/home/tester/test1/test1_1"); - - sftp.ChangeDirectory("/home/tester/test1/test1_1"); - - Assert.AreEqual(sftp.WorkingDirectory, "/home/tester/test1/test1_1"); - - sftp.ChangeDirectory("/home/tester/test1/test1_1/../test1_2"); - - Assert.AreEqual(sftp.WorkingDirectory, "/home/tester/test1/test1_2"); - - sftp.ChangeDirectory("../../"); - - sftp.DeleteDirectory("test1/test1_1"); - sftp.DeleteDirectory("test1/test1_2"); - sftp.DeleteDirectory("test1/test1_3"); - sftp.DeleteDirectory("test1"); - - sftp.Disconnect(); - } - - RemoveAllFiles(); - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [Description("Test passing null to ChangeDirectory.")] - [ExpectedException(typeof(ArgumentNullException))] - public void Test_Sftp_ChangeDirectory_Null() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - - sftp.ChangeDirectory(null); - - sftp.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Sftp")] - [TestCategory("integration")] - [Description("Test calling EndListDirectory method more then once.")] - [ExpectedException(typeof(ArgumentException))] - public void Test_Sftp_Call_EndListDirectory_Twice() - { - using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - sftp.Connect(); - var ar = sftp.BeginListDirectory("/", null, null); - var result = sftp.EndListDirectory(ar); - var result1 = sftp.EndListDirectory(ar); - } - } } } diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs index 200abae89..9e1c1f3c7 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs @@ -1,11 +1,9 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Sftp; using Renci.SshNet.Tests.Common; -using Renci.SshNet.Tests.Properties; using System; using System.Collections.Generic; using System.IO; -using System.Security.Cryptography; using System.Text; namespace Renci.SshNet.Tests.Classes @@ -1355,69 +1353,5 @@ public void WorkingDirectoryTest() actual = target.WorkingDirectory; Assert.Inconclusive("Verify the correctness of this test method."); } - - protected static string CalculateMD5(string fileName) - { - using (FileStream file = new FileStream(fileName, FileMode.Open)) - { -#if NET7_0_OR_GREATER - var hash = MD5.HashData(file); -#else -#if NET6_0 - var md5 = MD5.Create(); -#else - MD5 md5 = new MD5CryptoServiceProvider(); -#endif // NET6_0 - var hash = md5.ComputeHash(file); -#endif // NET7_0_OR_GREATER - - file.Close(); - - StringBuilder sb = new StringBuilder(); - for (var i = 0; i < hash.Length; i++) - { - sb.Append(hash[i].ToString("x2")); - } - return sb.ToString(); - } - } - - private static void RemoveAllFiles() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - client.RunCommand("rm -rf *"); - client.Disconnect(); - } - } - - /// - /// Helper class to help with upload and download testing - /// - private class TestInfo - { - public string RemoteFileName { get; set; } - - public string UploadedFileName { get; set; } - - public string DownloadedFileName { get; set; } - - //public ulong UploadedBytes { get; set; } - - //public ulong DownloadedBytes { get; set; } - - public FileStream UploadedFile { get; set; } - - public FileStream DownloadedFile { get; set; } - - public string UploadedHash { get; set; } - - public string DownloadedHash { get; set; } - - public SftpUploadAsyncResult UploadResult { get; set; } - - public SftpDownloadAsyncResult DownloadResult { get; set; } - } } } diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest.cs b/src/Renci.SshNet.Tests/Classes/SshClientTest.cs index 1eabcae20..8ee74c2ca 100644 --- a/src/Renci.SshNet.Tests/Classes/SshClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SshClientTest.cs @@ -2,11 +2,10 @@ using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; -using System; + using System.Collections.Generic; using System.IO; using System.Text; -using System.Linq; namespace Renci.SshNet.Tests.Classes { @@ -16,249 +15,6 @@ namespace Renci.SshNet.Tests.Classes [TestClass] public class SshClientTest : TestBase { - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - public void Test_Connect_Using_Correct_Password() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - - #region Example SshClient(host, username) Connect - using (var client = new SshClient(host, username, password)) - { - client.Connect(); - // Do something here - client.Disconnect(); - } - #endregion - } - - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - public void Test_Connect_Handle_HostKeyReceived() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - var hostKeyValidated = false; - - #region Example SshClient Connect HostKeyReceived - using (var client = new SshClient(host, username, password)) - { - client.HostKeyReceived += delegate(object sender, HostKeyEventArgs e) - { - hostKeyValidated = true; - - if (e.FingerPrint.SequenceEqual(new byte[] { 0x00, 0x01, 0x02, 0x03 })) - { - e.CanTrust = true; - } - else - { - e.CanTrust = false; - } - }; - client.Connect(); - // Do something here - client.Disconnect(); - } - #endregion - - Assert.IsTrue(hostKeyValidated); - } - - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - public void Test_Connect_Timeout() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - - #region Example SshClient Connect Timeout - - var connectionInfo = new PasswordConnectionInfo(host, username, password) - { - Timeout = TimeSpan.FromSeconds(30) - }; - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - // Do something here - client.Disconnect(); - } - #endregion - Assert.Inconclusive(); - } - - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - public void Test_Connect_Handle_ErrorOccurred() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - var exceptionOccured = false; - - #region Example SshClient Connect ErrorOccurred - using (var client = new SshClient(host, username, password)) - { - client.ErrorOccurred += delegate(object sender, ExceptionEventArgs e) - { - Console.WriteLine("Error occured: " + e.Exception); - exceptionOccured = true; - }; - - client.Connect(); - // Do something here - client.Disconnect(); - } - #endregion - Assert.IsTrue(exceptionOccured); - } - - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - [ExpectedException(typeof(SshAuthenticationException))] - public void Test_Connect_Using_Invalid_Password() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, "invalid password")) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - public void Test_Connect_Using_Rsa_Key_Without_PassPhrase() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - MemoryStream keyFileStream = new MemoryStream(Encoding.ASCII.GetBytes(Resources.RSA_KEY_WITHOUT_PASS)); - - #region Example SshClient(host, username) Connect PrivateKeyFile - using (var client = new SshClient(host, username, new PrivateKeyFile(keyFileStream))) - { - client.Connect(); - client.Disconnect(); - } - #endregion - } - - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - public void Test_Connect_Using_RsaKey_With_PassPhrase() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var passphrase = Resources.PASSWORD; - MemoryStream keyFileStream = new MemoryStream(Encoding.ASCII.GetBytes(Resources.RSA_KEY_WITH_PASS)); - - #region Example SshClient(host, username) Connect PrivateKeyFile PassPhrase - using (var client = new SshClient(host, username, new PrivateKeyFile(keyFileStream, passphrase))) - { - client.Connect(); - client.Disconnect(); - } - #endregion - } - - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - [ExpectedException(typeof(SshPassPhraseNullOrEmptyException))] - public void Test_Connect_Using_Key_With_Empty_PassPhrase() - { - MemoryStream keyFileStream = new MemoryStream(Encoding.ASCII.GetBytes(Resources.RSA_KEY_WITH_PASS)); - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, new PrivateKeyFile(keyFileStream, null))) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - public void Test_Connect_Using_DsaKey_Without_PassPhrase() - { - MemoryStream keyFileStream = new MemoryStream(Encoding.ASCII.GetBytes(Resources.DSA_KEY_WITHOUT_PASS)); - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, new PrivateKeyFile(keyFileStream))) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - public void Test_Connect_Using_DsaKey_With_PassPhrase() - { - MemoryStream keyFileStream = new MemoryStream(Encoding.ASCII.GetBytes(Resources.DSA_KEY_WITH_PASS)); - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, new PrivateKeyFile(keyFileStream, Resources.PASSWORD))) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - [ExpectedException(typeof(SshAuthenticationException))] - public void Test_Connect_Using_Invalid_PrivateKey() - { - MemoryStream keyFileStream = new MemoryStream(Encoding.ASCII.GetBytes(Resources.INVALID_KEY)); - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, new PrivateKeyFile(keyFileStream))) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - public void Test_Connect_Using_Multiple_PrivateKeys() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, - new PrivateKeyFile(new MemoryStream(Encoding.ASCII.GetBytes(Resources.INVALID_KEY))), - new PrivateKeyFile(new MemoryStream(Encoding.ASCII.GetBytes(Resources.DSA_KEY_WITH_PASS)), Resources.PASSWORD), - new PrivateKeyFile(new MemoryStream(Encoding.ASCII.GetBytes(Resources.RSA_KEY_WITH_PASS)), Resources.PASSWORD), - new PrivateKeyFile(new MemoryStream(Encoding.ASCII.GetBytes(Resources.RSA_KEY_WITHOUT_PASS))), - new PrivateKeyFile(new MemoryStream(Encoding.ASCII.GetBytes(Resources.DSA_KEY_WITHOUT_PASS))) - )) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("Authentication")] - [TestCategory("integration")] - public void Test_Connect_Then_Reconnect() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - client.Disconnect(); - client.Connect(); - client.Disconnect(); - } - } - [TestMethod] public void CreateShellStream1_NeverConnected() { diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs b/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs index d43a11e5e..3f5450952 100644 --- a/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs @@ -3,13 +3,7 @@ using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; using System; -using System.IO; using System.Text; -using System.Threading; -#if FEATURE_TPL -using System.Diagnostics; -using System.Threading.Tasks; -#endif // FEATURE_TPL namespace Renci.SshNet.Tests.Classes { @@ -31,480 +25,6 @@ public void Test_Execute_SingleCommand_Without_Connecting() } } - [TestMethod] - [TestCategory("integration")] - public void Test_Run_SingleCommand() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - - using (var client = new SshClient(host, username, password)) - { - #region Example SshCommand RunCommand Result - client.Connect(); - - var testValue = Guid.NewGuid().ToString(); - var command = client.RunCommand(string.Format("echo {0}", testValue)); - var result = command.Result; - result = result.Substring(0, result.Length - 1); // Remove \n character returned by command - - client.Disconnect(); - #endregion - - Assert.IsTrue(result.Equals(testValue)); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_SingleCommand() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - - using (var client = new SshClient(host, username, password)) - { - #region Example SshCommand CreateCommand Execute - client.Connect(); - - var testValue = Guid.NewGuid().ToString(); - var command = string.Format("echo {0}", testValue); - var cmd = client.CreateCommand(command); - var result = cmd.Execute(); - result = result.Substring(0, result.Length - 1); // Remove \n character returned by command - - client.Disconnect(); - #endregion - - Assert.IsTrue(result.Equals(testValue)); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_OutputStream() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - - using (var client = new SshClient(host, username, password)) - { - #region Example SshCommand CreateCommand Execute OutputStream - client.Connect(); - - var cmd = client.CreateCommand("ls -l"); // very long list - var asynch = cmd.BeginExecute(); - - var reader = new StreamReader(cmd.OutputStream); - - while (!asynch.IsCompleted) - { - var result = reader.ReadToEnd(); - if (string.IsNullOrEmpty(result)) - { - continue; - } - - Console.Write(result); - } - - _ = cmd.EndExecute(asynch); - - client.Disconnect(); - #endregion - - Assert.Inconclusive(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_ExtendedOutputStream() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - - using (var client = new SshClient(host, username, password)) - { - #region Example SshCommand CreateCommand Execute ExtendedOutputStream - - client.Connect(); - var cmd = client.CreateCommand("echo 12345; echo 654321 >&2"); - var result = cmd.Execute(); - - Console.Write(result); - - var reader = new StreamReader(cmd.ExtendedOutputStream); - Console.WriteLine("DEBUG:"); - Console.Write(reader.ReadToEnd()); - - client.Disconnect(); - - #endregion - - Assert.Inconclusive(); - } - } - - [TestMethod] - [TestCategory("integration")] - [ExpectedException(typeof(SshOperationTimeoutException))] - public void Test_Execute_Timeout() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - #region Example SshCommand CreateCommand Execute CommandTimeout - client.Connect(); - var cmd = client.CreateCommand("sleep 10s"); - cmd.CommandTimeout = TimeSpan.FromSeconds(5); - cmd.Execute(); - client.Disconnect(); - #endregion - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_Infinite_Timeout() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var cmd = client.CreateCommand("sleep 10s"); - cmd.Execute(); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_InvalidCommand() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - - var cmd = client.CreateCommand(";"); - cmd.Execute(); - if (string.IsNullOrEmpty(cmd.Error)) - { - Assert.Fail("Operation should fail"); - } - Assert.IsTrue(cmd.ExitStatus > 0); - - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_InvalidCommand_Then_Execute_ValidCommand() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var cmd = client.CreateCommand(";"); - cmd.Execute(); - if (string.IsNullOrEmpty(cmd.Error)) - { - Assert.Fail("Operation should fail"); - } - Assert.IsTrue(cmd.ExitStatus > 0); - - var result = ExecuteTestCommand(client); - - client.Disconnect(); - - Assert.IsTrue(result); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_Command_with_ExtendedOutput() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var cmd = client.CreateCommand("echo 12345; echo 654321 >&2"); - cmd.Execute(); - - //var extendedData = Encoding.ASCII.GetString(cmd.ExtendedOutputStream.ToArray()); - var extendedData = new StreamReader(cmd.ExtendedOutputStream, Encoding.ASCII).ReadToEnd(); - client.Disconnect(); - - Assert.AreEqual("12345\n", cmd.Result); - Assert.AreEqual("654321\n", extendedData); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_Command_Reconnect_Execute_Command() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var result = ExecuteTestCommand(client); - Assert.IsTrue(result); - - client.Disconnect(); - client.Connect(); - result = ExecuteTestCommand(client); - Assert.IsTrue(result); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_Command_ExitStatus() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - #region Example SshCommand RunCommand ExitStatus - client.Connect(); - - var cmd = client.RunCommand("exit 128"); - - Console.WriteLine(cmd.ExitStatus); - - client.Disconnect(); - #endregion - - Assert.IsTrue(cmd.ExitStatus == 128); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_Command_Asynchronously() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - - var cmd = client.CreateCommand("sleep 5s; echo 'test'"); - var asyncResult = cmd.BeginExecute(null, null); - while (!asyncResult.IsCompleted) - { - Thread.Sleep(100); - } - - cmd.EndExecute(asyncResult); - - Assert.IsTrue(cmd.Result == "test\n"); - - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_Command_Asynchronously_With_Error() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - - var cmd = client.CreateCommand("sleep 5s; ;"); - var asyncResult = cmd.BeginExecute(null, null); - while (!asyncResult.IsCompleted) - { - Thread.Sleep(100); - } - - cmd.EndExecute(asyncResult); - - Assert.IsFalse(string.IsNullOrEmpty(cmd.Error)); - - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_Command_Asynchronously_With_Callback() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - - var callbackCalled = false; - - var cmd = client.CreateCommand("sleep 5s; echo 'test'"); - var asyncResult = cmd.BeginExecute(new AsyncCallback((s) => - { - callbackCalled = true; - }), null); - while (!asyncResult.IsCompleted) - { - Thread.Sleep(100); - } - - cmd.EndExecute(asyncResult); - - Assert.IsTrue(callbackCalled); - - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_Command_Asynchronously_With_Callback_On_Different_Thread() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - - var currentThreadId = Thread.CurrentThread.ManagedThreadId; - int callbackThreadId = 0; - - var cmd = client.CreateCommand("sleep 5s; echo 'test'"); - var asyncResult = cmd.BeginExecute(new AsyncCallback((s) => - { - callbackThreadId = Thread.CurrentThread.ManagedThreadId; - }), null); - while (!asyncResult.IsCompleted) - { - Thread.Sleep(100); - } - - cmd.EndExecute(asyncResult); - - Assert.AreNotEqual(currentThreadId, callbackThreadId); - - client.Disconnect(); - } - } - - /// - /// Tests for Issue 563. - /// - [WorkItem(563), TestMethod] - [TestCategory("integration")] - public void Test_Execute_Command_Same_Object_Different_Commands() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var cmd = client.CreateCommand("echo 12345"); - cmd.Execute(); - Assert.AreEqual("12345\n", cmd.Result); - cmd.Execute("echo 23456"); - Assert.AreEqual("23456\n", cmd.Result); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Get_Result_Without_Execution() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var cmd = client.CreateCommand("ls -l"); - - Assert.IsTrue(string.IsNullOrEmpty(cmd.Result)); - client.Disconnect(); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Get_Error_Without_Execution() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var cmd = client.CreateCommand("ls -l"); - - Assert.IsTrue(string.IsNullOrEmpty(cmd.Error)); - client.Disconnect(); - } - } - - [WorkItem(703), TestMethod] - [ExpectedException(typeof(ArgumentException))] - [TestCategory("integration")] - public void Test_EndExecute_Before_BeginExecute() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - var cmd = client.CreateCommand("ls -l"); - cmd.EndExecute(null); - client.Disconnect(); - } - } - - /// - ///A test for BeginExecute - /// - [TestMethod()] - [TestCategory("integration")] - public void BeginExecuteTest() - { - string expected = "123\n"; - string result; - - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - #region Example SshCommand CreateCommand BeginExecute IsCompleted EndExecute - - client.Connect(); - - var cmd = client.CreateCommand("sleep 15s;echo 123"); // Perform long running task - - var asynch = cmd.BeginExecute(); - - while (!asynch.IsCompleted) - { - // Waiting for command to complete... - Thread.Sleep(2000); - } - result = cmd.EndExecute(asynch); - client.Disconnect(); - - #endregion - - Assert.IsNotNull(asynch); - Assert.AreEqual(expected, result); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_Execute_Invalid_Command() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - #region Example SshCommand CreateCommand Error - - client.Connect(); - - var cmd = client.CreateCommand(";"); - cmd.Execute(); - if (!string.IsNullOrEmpty(cmd.Error)) - { - Console.WriteLine(cmd.Error); - } - - client.Disconnect(); - - #endregion - - Assert.Inconclusive(); - } - } - - /// ///A test for BeginExecute /// @@ -630,100 +150,6 @@ public void ResultTest() Assert.Inconclusive("Verify the correctness of this test method."); } -#if FEATURE_TPL - [TestMethod] - [TestCategory("integration")] - public void Test_MultipleThread_Example_MultipleConnections() - { - var host = Resources.HOST; - var username = Resources.USERNAME; - var password = Resources.PASSWORD; - - try - { -#region Example SshCommand RunCommand Parallel - System.Threading.Tasks.Parallel.For(0, 10000, - () => - { - var client = new SshClient(host, username, password); - client.Connect(); - return client; - }, - (int counter, ParallelLoopState pls, SshClient client) => - { - var result = client.RunCommand("echo 123"); - Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); - return client; - }, - (SshClient client) => - { - client.Disconnect(); - client.Dispose(); - } - ); -#endregion - - } - catch (Exception exp) - { - Assert.Fail(exp.ToString()); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_MultipleThread_10000_MultipleConnections() - { - try - { - System.Threading.Tasks.Parallel.For(0, 10000, - () => - { - var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD); - client.Connect(); - return client; - }, - (int counter, ParallelLoopState pls, SshClient client) => - { - var result = ExecuteTestCommand(client); - Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); - Assert.IsTrue(result); - return client; - }, - (SshClient client) => - { - client.Disconnect(); - client.Dispose(); - } - ); - } - catch (Exception exp) - { - Assert.Fail(exp.ToString()); - } - } - - [TestMethod] - [TestCategory("integration")] - public void Test_MultipleThread_10000_MultipleSessions() - { - using (var client = new SshClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) - { - client.Connect(); - System.Threading.Tasks.Parallel.For(0, 10000, - (counter) => - { - var result = ExecuteTestCommand(client); - Debug.WriteLine(string.Format("TestMultipleThreadMultipleConnections #{0}", counter)); - Assert.IsTrue(result); - } - ); - - client.Disconnect(); - } - } -#endif // FEATURE_TPL - private static bool ExecuteTestCommand(SshClient s) { var testValue = Guid.NewGuid().ToString(); diff --git a/src/Renci.SshNet.sln b/src/Renci.SshNet.sln index be2686bee..34cc0f483 100644 --- a/src/Renci.SshNet.sln +++ b/src/Renci.SshNet.sln @@ -42,7 +42,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D21A4D03-0 ..\test\Directory.Build.props = ..\test\Directory.Build.props EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntegrationTests", "Renci.SshNet.IntegrationTests\IntegrationTests.csproj", "{EEF98046-729C-419E-932D-4E569073C8CC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.IntegrationTests", "Renci.SshNet.IntegrationTests\Renci.SshNet.IntegrationTests.csproj", "{EEF98046-729C-419E-932D-4E569073C8CC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.TestTools.OpenSSH", "Renci.SshNet.TestTools.OpenSSH\Renci.SshNet.TestTools.OpenSSH.csproj", "{78239046-2019-494E-B6EC-240AF787E4D0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -106,6 +108,26 @@ Global {EEF98046-729C-419E-932D-4E569073C8CC}.Release|x64.Build.0 = Release|Any CPU {EEF98046-729C-419E-932D-4E569073C8CC}.Release|x86.ActiveCfg = Release|Any CPU {EEF98046-729C-419E-932D-4E569073C8CC}.Release|x86.Build.0 = Release|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|ARM.ActiveCfg = Debug|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|ARM.Build.0 = Debug|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|x64.ActiveCfg = Debug|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|x64.Build.0 = Debug|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|x86.ActiveCfg = Debug|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|x86.Build.0 = Debug|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Release|Any CPU.Build.0 = Release|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Release|ARM.ActiveCfg = Release|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Release|ARM.Build.0 = Release|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Release|x64.ActiveCfg = Release|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Release|x64.Build.0 = Release|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Release|x86.ActiveCfg = Release|Any CPU + {78239046-2019-494E-B6EC-240AF787E4D0}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Renci.SshNet/Properties/AssemblyInfo.cs b/src/Renci.SshNet/Properties/AssemblyInfo.cs index cde7dcdeb..07f66e5fe 100644 --- a/src/Renci.SshNet/Properties/AssemblyInfo.cs +++ b/src/Renci.SshNet/Properties/AssemblyInfo.cs @@ -5,4 +5,5 @@ [assembly: AssemblyTitle("SSH.NET")] [assembly: Guid("ad816c5e-6f13-4589-9f3e-59523f8b77a4")] [assembly: InternalsVisibleTo("Renci.SshNet.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f9194e1eb66b7e2575aaee115ee1d27bc100920e7150e43992d6f668f9737de8b9c7ae892b62b8a36dd1d57929ff1541665d101dc476d6e02390846efae7e5186eec409710fdb596e3f83740afef0d4443055937649bc5a773175b61c57615dac0f0fd10f52b52fedf76c17474cc567b3f7a79de95dde842509fb39aaf69c6c2")] +[assembly: InternalsVisibleTo("Renci.SshNet.IntegrationTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f9194e1eb66b7e2575aaee115ee1d27bc100920e7150e43992d6f668f9737de8b9c7ae892b62b8a36dd1d57929ff1541665d101dc476d6e02390846efae7e5186eec409710fdb596e3f83740afef0d4443055937649bc5a773175b61c57615dac0f0fd10f52b52fedf76c17474cc567b3f7a79de95dde842509fb39aaf69c6c2")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] From 60de8a41a4d67713f172158dd49ed2538a6fb50b Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Fri, 15 Sep 2023 05:32:13 +0200 Subject: [PATCH 34/96] Add a benchmarks project (#1151) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add a benchmarks project * Small improvements --------- Co-authored-by: Wojciech Nag贸rski --- .gitignore | 3 ++ .../Data/Key.ECDSA.Encrypted.txt | 0 .../Data/Key.ECDSA.txt | 0 .../Data/Key.ECDSA384.Encrypted.txt | 0 .../Data/Key.ECDSA384.txt | 0 .../Data/Key.ECDSA521.Encrypted.txt | 0 .../Data/Key.ECDSA521.txt | 0 .../Data/Key.OPENSSH.ECDSA.Encrypted.txt | 0 .../Data/Key.OPENSSH.ECDSA.txt | 0 .../Data/Key.OPENSSH.ECDSA384.Encrypted.txt | 0 .../Data/Key.OPENSSH.ECDSA384.txt | 0 .../Data/Key.OPENSSH.ECDSA521.Encrypted.txt | 0 .../Data/Key.OPENSSH.ECDSA521.txt | 0 .../Data/Key.OPENSSH.ED25519.Encrypted.txt | 0 .../Data/Key.OPENSSH.ED25519.txt | 0 .../Data/Key.OPENSSH.RSA.Encrypted.txt | 0 .../Data/Key.OPENSSH.RSA.txt | 0 .../Key.RSA.Encrypted.Aes.128.CBC.12345.txt | 0 .../Key.RSA.Encrypted.Aes.192.CBC.12345.txt | 0 .../Key.RSA.Encrypted.Aes.256.CBC.12345.txt | 0 .../Data/Key.RSA.Encrypted.Des.CBC.12345.txt | 0 .../Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt | 0 ....RSA.Encrypted.Des.Ede3.CFB.1234567890.txt | 0 src/{Renci.SshNet.Tests => }/Data/Key.RSA.txt | 0 .../Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt | 0 .../Data/Key.SSH2.DSA.txt | 0 .../Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt | 0 .../Data/Key.SSH2.RSA.txt | 0 src/Renci.SshNet.Benchmarks/Program.cs | 27 +++++++++++ .../Renci.SshNet.Benchmarks.csproj | 31 ++++++++++++ .../Ciphers/AesCipherBenchmarks.cs | 38 +++++++++++++++ .../Ciphers/RsaCipherBenchmarks.cs | 48 +++++++++++++++++++ .../ED25519DigitalSignatureBenchmarks.cs | 41 ++++++++++++++++ .../Renci.SshNet.Tests.csproj | 28 +---------- src/Renci.SshNet.sln | 22 +++++++++ 35 files changed, 211 insertions(+), 27 deletions(-) rename src/{Renci.SshNet.Tests => }/Data/Key.ECDSA.Encrypted.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.ECDSA.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.ECDSA384.Encrypted.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.ECDSA384.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.ECDSA521.Encrypted.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.ECDSA521.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.OPENSSH.ECDSA.Encrypted.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.OPENSSH.ECDSA.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.OPENSSH.ECDSA384.Encrypted.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.OPENSSH.ECDSA384.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.OPENSSH.ECDSA521.Encrypted.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.OPENSSH.ECDSA521.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.OPENSSH.ED25519.Encrypted.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.OPENSSH.ED25519.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.OPENSSH.RSA.Encrypted.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.OPENSSH.RSA.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.RSA.Encrypted.Des.CBC.12345.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.RSA.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.SSH2.DSA.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt (100%) rename src/{Renci.SshNet.Tests => }/Data/Key.SSH2.RSA.txt (100%) create mode 100644 src/Renci.SshNet.Benchmarks/Program.cs create mode 100644 src/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj create mode 100644 src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs create mode 100644 src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs create mode 100644 src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs diff --git a/.gitignore b/.gitignore index 7d6bdbf60..37793444d 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,6 @@ project.lock.json # Build outputs build/target/ + +# Benchmark results +BenchmarkDotNet.Artifacts/ diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA.Encrypted.txt b/src/Data/Key.ECDSA.Encrypted.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.ECDSA.Encrypted.txt rename to src/Data/Key.ECDSA.Encrypted.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA.txt b/src/Data/Key.ECDSA.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.ECDSA.txt rename to src/Data/Key.ECDSA.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA384.Encrypted.txt b/src/Data/Key.ECDSA384.Encrypted.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.ECDSA384.Encrypted.txt rename to src/Data/Key.ECDSA384.Encrypted.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA384.txt b/src/Data/Key.ECDSA384.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.ECDSA384.txt rename to src/Data/Key.ECDSA384.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA521.Encrypted.txt b/src/Data/Key.ECDSA521.Encrypted.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.ECDSA521.Encrypted.txt rename to src/Data/Key.ECDSA521.Encrypted.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.ECDSA521.txt b/src/Data/Key.ECDSA521.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.ECDSA521.txt rename to src/Data/Key.ECDSA521.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.Encrypted.txt b/src/Data/Key.OPENSSH.ECDSA.Encrypted.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.Encrypted.txt rename to src/Data/Key.OPENSSH.ECDSA.Encrypted.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.txt b/src/Data/Key.OPENSSH.ECDSA.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA.txt rename to src/Data/Key.OPENSSH.ECDSA.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.Encrypted.txt b/src/Data/Key.OPENSSH.ECDSA384.Encrypted.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.Encrypted.txt rename to src/Data/Key.OPENSSH.ECDSA384.Encrypted.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.txt b/src/Data/Key.OPENSSH.ECDSA384.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA384.txt rename to src/Data/Key.OPENSSH.ECDSA384.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.Encrypted.txt b/src/Data/Key.OPENSSH.ECDSA521.Encrypted.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.Encrypted.txt rename to src/Data/Key.OPENSSH.ECDSA521.Encrypted.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.txt b/src/Data/Key.OPENSSH.ECDSA521.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.OPENSSH.ECDSA521.txt rename to src/Data/Key.OPENSSH.ECDSA521.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ED25519.Encrypted.txt b/src/Data/Key.OPENSSH.ED25519.Encrypted.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.OPENSSH.ED25519.Encrypted.txt rename to src/Data/Key.OPENSSH.ED25519.Encrypted.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.ED25519.txt b/src/Data/Key.OPENSSH.ED25519.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.OPENSSH.ED25519.txt rename to src/Data/Key.OPENSSH.ED25519.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.Encrypted.txt b/src/Data/Key.OPENSSH.RSA.Encrypted.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.Encrypted.txt rename to src/Data/Key.OPENSSH.RSA.Encrypted.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.txt b/src/Data/Key.OPENSSH.RSA.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.OPENSSH.RSA.txt rename to src/Data/Key.OPENSSH.RSA.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt b/src/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt rename to src/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt b/src/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt rename to src/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt b/src/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt rename to src/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Des.CBC.12345.txt b/src/Data/Key.RSA.Encrypted.Des.CBC.12345.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Des.CBC.12345.txt rename to src/Data/Key.RSA.Encrypted.Des.CBC.12345.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt b/src/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt rename to src/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt b/src/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt rename to src/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.RSA.txt b/src/Data/Key.RSA.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.RSA.txt rename to src/Data/Key.RSA.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt b/src/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt rename to src/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.SSH2.DSA.txt b/src/Data/Key.SSH2.DSA.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.SSH2.DSA.txt rename to src/Data/Key.SSH2.DSA.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt b/src/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt rename to src/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt diff --git a/src/Renci.SshNet.Tests/Data/Key.SSH2.RSA.txt b/src/Data/Key.SSH2.RSA.txt similarity index 100% rename from src/Renci.SshNet.Tests/Data/Key.SSH2.RSA.txt rename to src/Data/Key.SSH2.RSA.txt diff --git a/src/Renci.SshNet.Benchmarks/Program.cs b/src/Renci.SshNet.Benchmarks/Program.cs new file mode 100644 index 000000000..3249baa99 --- /dev/null +++ b/src/Renci.SshNet.Benchmarks/Program.cs @@ -0,0 +1,27 @@ +锘縰sing BenchmarkDotNet.Running; + +namespace Renci.SshNet.Benchmarks +{ + class Program + { + static void Main(string[] args) + { + // Usage examples: + // 1. Run all benchmarks: + // dotnet run -c Release -- --filter * + // 2. List all benchmarks: + // dotnet run -c Release -- --list flat + // 3. Run a subset of benchmarks based on a filter (of a benchmark method's fully-qualified name, + // e.g. "Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers.AesCipherBenchmarks.Encrypt_CBC"): + // dotnet run -c Release -- --filter *Ciphers* + // 4. Run benchmarks and include memory usage statistics in the output: + // dotnet run -c Release -- filter *Rsa* --memory + // 3. Print help: + // dotnet run -c Release -- --help + + // See also https://benchmarkdotnet.org/articles/guides/console-args.html + + _ = BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); + } + } +} diff --git a/src/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj b/src/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj new file mode 100644 index 000000000..daf3f5095 --- /dev/null +++ b/src/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj @@ -0,0 +1,31 @@ + + + + Exe + net7.0 + enable + enable + + $(NoWarn);CS1591 + + + + + + + + + + + + + + + diff --git a/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs b/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs new file mode 100644 index 000000000..ff414cc4a --- /dev/null +++ b/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs @@ -0,0 +1,38 @@ +锘縰sing BenchmarkDotNet.Attributes; +using Renci.SshNet.Security.Cryptography.Ciphers; +using Renci.SshNet.Security.Cryptography.Ciphers.Modes; + +namespace Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers +{ + [MemoryDiagnoser] + public class AesCipherBenchmarks + { + private readonly byte[] _key; + private readonly byte[] _iv; + private readonly byte[] _data; + + public AesCipherBenchmarks() + { + _key = new byte[32]; + _iv = new byte[16]; + _data = new byte[256]; + + Random random = new(Seed: 12345); + random.NextBytes(_key); + random.NextBytes(_iv); + random.NextBytes(_data); + } + + [Benchmark] + public byte[] Encrypt_CBC() + { + return new AesCipher(_key, new CbcCipherMode(_iv), null).Encrypt(_data); + } + + [Benchmark] + public byte[] Decrypt_CBC() + { + return new AesCipher(_key, new CbcCipherMode(_iv), null).Decrypt(_data); + } + } +} diff --git a/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs b/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs new file mode 100644 index 000000000..f25e6db71 --- /dev/null +++ b/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs @@ -0,0 +1,48 @@ +锘縰sing BenchmarkDotNet.Attributes; + +using Renci.SshNet.Security; +using Renci.SshNet.Security.Cryptography.Ciphers; + +namespace Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers +{ + [MemoryDiagnoser] + public class RsaCipherBenchmarks + { + private readonly RsaKey _privateKey; + private readonly RsaKey _publicKey; + private readonly byte[] _data; + + public RsaCipherBenchmarks() + { + _data = new byte[128]; + + Random random = new(Seed: 12345); + random.NextBytes(_data); + + using (var s = typeof(RsaCipherBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.RSA.txt")) + { + _privateKey = (RsaKey)((KeyHostAlgorithm) new PrivateKeyFile(s).HostKey).Key; + + // The implementations of RsaCipher.Encrypt/Decrypt differ based on whether the supplied RsaKey has private key information + // or only public. So we extract out the public key information to a separate variable. + _publicKey = new RsaKey() + { + Public = _privateKey.Public + }; + } + } + + [Benchmark] + public byte[] Encrypt() + { + return new RsaCipher(_publicKey).Encrypt(_data); + } + + // RSA Decrypt does not work + // [Benchmark] + // public byte[] Decrypt() + // { + // return new RsaCipher(_privateKey).Decrypt(_data); + // } + } +} diff --git a/src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs b/src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs new file mode 100644 index 000000000..2f07a2d3a --- /dev/null +++ b/src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs @@ -0,0 +1,41 @@ +锘縰sing BenchmarkDotNet.Attributes; + +using Renci.SshNet.Security; +using Renci.SshNet.Security.Cryptography; + +namespace Renci.SshNet.Benchmarks.Security.Cryptography +{ + [MemoryDiagnoser] + public class ED25519DigitalSignatureBenchmarks + { + private readonly ED25519Key _key; + private readonly byte[] _data; + private readonly byte[] _signature; + + public ED25519DigitalSignatureBenchmarks() + { + _data = new byte[128]; + + Random random = new(Seed: 12345); + random.NextBytes(_data); + + using (var s = typeof(ED25519DigitalSignatureBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.OPENSSH.ED25519.txt")) + { + _key = (ED25519Key) ((KeyHostAlgorithm) new PrivateKeyFile(s).HostKey).Key; + } + _signature = new ED25519DigitalSignature(_key).Sign(_data); + } + + [Benchmark] + public byte[] Sign() + { + return new ED25519DigitalSignature(_key).Sign(_data); + } + + [Benchmark] + public bool Verify() + { + return new ED25519DigitalSignature(_key).Verify(_data, _signature); + } + } +} diff --git a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index 94a4e8015..aa9d79a2a 100644 --- a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -14,33 +14,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/Renci.SshNet.sln b/src/Renci.SshNet.sln index 34cc0f483..459d129c4 100644 --- a/src/Renci.SshNet.sln +++ b/src/Renci.SshNet.sln @@ -42,6 +42,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D21A4D03-0 ..\test\Directory.Build.props = ..\test\Directory.Build.props EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.Benchmarks", "Renci.SshNet.Benchmarks\Renci.SshNet.Benchmarks.csproj", "{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.IntegrationTests", "Renci.SshNet.IntegrationTests\Renci.SshNet.IntegrationTests.csproj", "{EEF98046-729C-419E-932D-4E569073C8CC}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.TestTools.OpenSSH", "Renci.SshNet.TestTools.OpenSSH\Renci.SshNet.TestTools.OpenSSH.csproj", "{78239046-2019-494E-B6EC-240AF787E4D0}" @@ -88,6 +90,26 @@ Global {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Mixed Platforms.Build.0 = Release|Any CPU {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x64.ActiveCfg = Release|Any CPU {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x86.ActiveCfg = Release|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|ARM.ActiveCfg = Debug|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|ARM.Build.0 = Debug|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|x64.ActiveCfg = Debug|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|x64.Build.0 = Debug|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|x86.ActiveCfg = Debug|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|x86.Build.0 = Debug|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|Any CPU.Build.0 = Release|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|ARM.ActiveCfg = Release|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|ARM.Build.0 = Release|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|x64.ActiveCfg = Release|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|x64.Build.0 = Release|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|x86.ActiveCfg = Release|Any CPU + {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|x86.Build.0 = Release|Any CPU {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|Any CPU.Build.0 = Debug|Any CPU {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|ARM.ActiveCfg = Debug|Any CPU From dcc596a774182d0e5f605e90f4f8e9fe6e7f78db Mon Sep 17 00:00:00 2001 From: Igor Milavec Date: Fri, 15 Sep 2023 09:45:17 +0200 Subject: [PATCH 35/96] Use ExceptionDispatchInfo to retain call stack in Session.WaitOnHandle() (#936) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use ExceptionDispatchInfo to retain call stack in Session.WaitOnHandle() * merge * Update src/Renci.SshNet/Session.cs Co-authored-by: Rob Hague --------- Co-authored-by: Wojciech Nag贸rski Co-authored-by: Rob Hague --- src/Renci.SshNet/Session.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index 9fec6bd7e..257cf8c2c 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -992,7 +992,8 @@ internal void WaitOnHandle(WaitHandle waitHandle, TimeSpan timeout) switch (signaledElement) { case 0: - throw _exception; + System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(_exception).Throw(); + break; case 1: throw new SshConnectionException("Client not connected."); case 2: From 43329eef281fcd364e226dbd6b8c614d97368827 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C4=81vis=20Mo=C5=A1enkovs?= Date: Sun, 17 Sep 2023 23:44:26 +0300 Subject: [PATCH 36/96] Support SHA256 fingerprints for host key validation (#1098) * Add tests for HostKeyEventArgs * Add SHA256 fingerprint support --- README.md | 21 +----- .../Classes/Common/HostKeyEventArgsTest.cs | 70 ++++++++++++++++--- src/Renci.SshNet/Common/HostKeyEventArgs.cs | 18 ++++- 3 files changed, 81 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 2c0dc015c..86d0e309b 100644 --- a/README.md +++ b/README.md @@ -143,30 +143,13 @@ using (var client = new SftpClient(connectionInfo)) 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 -byte[] expectedFingerPrint = new byte[] { - 0x66, 0x31, 0xaf, 0x00, 0x54, 0xb9, 0x87, 0x31, - 0xff, 0x58, 0x1c, 0x31, 0xb1, 0xa2, 0x4c, 0x6b - }; +string expectedFingerPrint = "LKOy5LvmtEe17S4lyxVXqvs7uPMy+yF79MQpHeCs/Qo"; using (var client = new SshClient("sftp.foo.com", "guest", "pwd")) { client.HostKeyReceived += (sender, e) => { - if (expectedFingerPrint.Length == e.FingerPrint.Length) - { - for (var i = 0; i < expectedFingerPrint.Length; i++) - { - if (expectedFingerPrint[i] != e.FingerPrint[i]) - { - e.CanTrust = false; - break; - } - } - } - else - { - e.CanTrust = false; - } + e.CanTrust = expectedFingerPrint.Equals(e.FingerPrintSHA256); }; client.Connect(); } diff --git a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs index 93055c6e0..516e3623f 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs @@ -2,6 +2,8 @@ using Renci.SshNet.Common; using Renci.SshNet.Security; using Renci.SshNet.Tests.Common; +using System.Linq; +using System.Reflection; namespace Renci.SshNet.Tests.Classes.Common { @@ -10,7 +12,6 @@ namespace Renci.SshNet.Tests.Classes.Common ///to contain all HostKeyEventArgsTest Unit Tests ///
[TestClass] - [Ignore] // placeholder for actual test public class HostKeyEventArgsTest : TestBase { /// @@ -19,9 +20,52 @@ public class HostKeyEventArgsTest : TestBase [TestMethod] public void HostKeyEventArgsConstructorTest() { - KeyHostAlgorithm host = null; // TODO: Initialize to an appropriate value - HostKeyEventArgs target = new HostKeyEventArgs(host); - Assert.Inconclusive("TODO: Implement code to verify target"); + HostKeyEventArgs target = new HostKeyEventArgs(GetKeyHostAlgorithm()); + Assert.IsTrue(target.CanTrust); + Assert.IsTrue(new byte[] { + 0x00, 0x00, 0x00, 0x07, 0x73, 0x73, 0x68, 0x2d, 0x72, 0x73, 0x61, 0x00, 0x00, 0x00, 0x01, 0x23, + 0x00, 0x00, 0x01, 0x01, 0x00, 0xb9, 0x3b, 0x57, 0x9f, 0xe0, 0x5a, 0xb5, 0x7d, 0x68, 0x26, 0xeb, + 0xe1, 0xa9, 0xf2, 0x59, 0xc3, 0x98, 0xdc, 0xfe, 0x97, 0x08, 0xc4, 0x95, 0x0f, 0x9a, 0xea, 0x05, + 0x08, 0x7d, 0xfe, 0x6d, 0x77, 0xca, 0x04, 0x9f, 0xfd, 0xe2, 0x2c, 0x4d, 0x11, 0x3c, 0xd9, 0x05, + 0xab, 0x32, 0xbd, 0x3f, 0xe8, 0xcd, 0xba, 0x00, 0x6c, 0x21, 0xb7, 0xa9, 0xc2, 0x4e, 0x63, 0x17, + 0xf6, 0x04, 0x47, 0x93, 0x00, 0x85, 0xde, 0xd6, 0x32, 0xc0, 0xa1, 0x37, 0x75, 0x18, 0xa0, 0xb0, + 0x32, 0xf6, 0x4e, 0xca, 0x39, 0xec, 0x3c, 0xdf, 0x79, 0xfe, 0x50, 0xa1, 0xc1, 0xf7, 0x67, 0x05, + 0xb3, 0x33, 0xa5, 0x96, 0x13, 0x19, 0xfa, 0x14, 0xca, 0x55, 0xe6, 0x7b, 0xf9, 0xb3, 0x8e, 0x32, + 0xee, 0xfc, 0x9d, 0x2a, 0x5e, 0x04, 0x79, 0x97, 0x29, 0x3d, 0x1c, 0x54, 0xfe, 0xc7, 0x96, 0x04, + 0xb5, 0x19, 0x7c, 0x55, 0x21, 0xe2, 0x0e, 0x42, 0xca, 0x4d, 0x9d, 0xfb, 0x77, 0x08, 0x6c, 0xaa, + 0x07, 0x2c, 0xf8, 0xf9, 0x1f, 0xbd, 0x83, 0x14, 0x2b, 0xe0, 0xbc, 0x7a, 0xf9, 0xdf, 0x13, 0x4b, + 0x60, 0x5a, 0x02, 0x99, 0x93, 0x41, 0x1a, 0xb6, 0x5f, 0x3b, 0x9c, 0xb5, 0xb2, 0x55, 0x70, 0x78, + 0x2f, 0x38, 0x52, 0x0e, 0xd1, 0x8a, 0x2c, 0x23, 0xc0, 0x3a, 0x0a, 0xd7, 0xed, 0xf6, 0x1f, 0xa6, + 0x50, 0xf0, 0x27, 0x65, 0x8a, 0xd4, 0xde, 0xa7, 0x1b, 0x41, 0x67, 0xc5, 0x6d, 0x47, 0x84, 0x37, + 0x92, 0x2b, 0xb7, 0xb6, 0x4d, 0xb0, 0x1a, 0xda, 0xf6, 0x50, 0x82, 0xf1, 0x57, 0x31, 0x69, 0xce, + 0xe0, 0xef, 0xcd, 0x64, 0xaa, 0x78, 0x08, 0xea, 0x4e, 0x45, 0xec, 0xa5, 0x89, 0x68, 0x5d, 0xb4, + 0xa0, 0x23, 0xaf, 0xff, 0x9c, 0x0f, 0x8c, 0x83, 0x7c, 0xf8, 0xe1, 0x8e, 0x32, 0x8e, 0x61, 0xfc, + 0x5b, 0xbd, 0xd4, 0x46, 0xe1 + }.SequenceEqual(target.HostKey)); + Assert.AreEqual("ssh-rsa", target.HostKeyName); + Assert.AreEqual(2048, target.KeyLength); + } + + /// + ///A test for MD5 calculation in HostKeyEventArgs Constructor + /// + [TestMethod] + public void HostKeyEventArgsConstructorTest_VerifyMD5() + { + HostKeyEventArgs target = new HostKeyEventArgs(GetKeyHostAlgorithm()); + Assert.IsTrue(new byte[] { + 0x92, 0xea, 0x54, 0xa1, 0x01, 0xf9, 0x95, 0x9c, 0x71, 0xd9, 0xbb, 0x51, 0xb2, 0x55, 0xf8, 0xd9 + }.SequenceEqual(target.FingerPrint)); + } + + /// + ///A test for SHA256 calculation in HostKeyEventArgs Constructor + /// + [TestMethod] + public void HostKeyEventArgsConstructorTest_VerifySHA256() + { + HostKeyEventArgs target = new HostKeyEventArgs(GetKeyHostAlgorithm()); + Assert.AreEqual("93LkmoWksp9ytNVZIPXi9KJU1uvlC9clZ/CkUHf6uEE", target.FingerPrintSHA256); } /// @@ -30,14 +74,24 @@ public void HostKeyEventArgsConstructorTest() [TestMethod] public void CanTrustTest() { - KeyHostAlgorithm host = null; // TODO: Initialize to an appropriate value - HostKeyEventArgs target = new HostKeyEventArgs(host); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value + HostKeyEventArgs target = new HostKeyEventArgs(GetKeyHostAlgorithm()); + bool expected = false; bool actual; target.CanTrust = expected; actual = target.CanTrust; Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); } + + private static KeyHostAlgorithm GetKeyHostAlgorithm() + { + var executingAssembly = Assembly.GetExecutingAssembly(); + + using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) + { + var privateKey = new PrivateKeyFile(s); + return (KeyHostAlgorithm)privateKey.HostKey; + } + } + } } diff --git a/src/Renci.SshNet/Common/HostKeyEventArgs.cs b/src/Renci.SshNet/Common/HostKeyEventArgs.cs index 017b1e513..ddf49d0ac 100644 --- a/src/Renci.SshNet/Common/HostKeyEventArgs.cs +++ b/src/Renci.SshNet/Common/HostKeyEventArgs.cs @@ -28,10 +28,21 @@ public class HostKeyEventArgs : EventArgs public string HostKeyName{ get; private set; } /// - /// Gets the finger print. + /// Gets the MD5 fingerprint. /// + /// + /// MD5 fingerprint as byte array. + /// public byte[] FingerPrint { get; private set; } + /// + /// Gets the SHA256 fingerprint. + /// + /// + /// Base64 encoded SHA256 fingerprint with padding (equals sign) removed. + /// + public string FingerPrintSHA256 { get; private set; } + /// /// Gets the length of the key in bits. /// @@ -55,6 +66,11 @@ public HostKeyEventArgs(KeyHostAlgorithm host) { FingerPrint = md5.ComputeHash(host.Data); } + + using (var sha256 = CryptoAbstraction.CreateSHA256()) + { + FingerPrintSHA256 = Convert.ToBase64String(sha256.ComputeHash(host.Data)).Replace("=", ""); + } } } } From 8732d3d7efe3c1ff9120bb61bda54cd1ea88a8af Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Sat, 23 Sep 2023 07:09:41 +0200 Subject: [PATCH 37/96] Add support for RSA SHA-2 public key algorithms (#1177) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Abstract out the hash algorithm from RsaDigitalSignature * Add integration tests * Add DigitalSignature property to KeyHostAlgorithm * Add IHostAlgorithmsProvider interface * Verify the host signature * Fix HostKeyEventArgsTest after merge * Remove PubkeyAcceptedAlgorithms ssh-rsa * Add test coverage for RSA keys in PrivateKeyFile * Obsolete IPrivateKeySource --------- Co-authored-by: Wojciech Nag贸rski --- .../Common/RemoteSshdConfigExtensions.cs | 2 - src/Renci.SshNet.IntegrationTests/Dockerfile | 1 - .../HostKeyAlgorithmTests.cs | 72 ++---- .../PrivateKeyAuthenticationTests.cs | 65 ++++-- .../Renci.SshNet.IntegrationTests.csproj | 1 + .../user/sshnet/authorized_keys | 3 +- .../SshdConfig.cs | 7 +- .../Classes/Common/HostKeyEventArgsTest.cs | 2 +- .../Classes/PrivateKeyFileTest.cs | 36 ++- .../Cryptography/RsaDigitalSignatureTest.cs | 164 ++++++++++++- .../Classes/Security/KeyAlgorithmTest.cs | 215 ++++++++++++++++++ src/Renci.SshNet.Tests/Common/TestBase.cs | 4 +- src/Renci.SshNet/Common/ObjectIdentifier.cs | 16 ++ src/Renci.SshNet/ConnectionInfo.cs | 4 + src/Renci.SshNet/IHostAlgorithmsProvider.cs | 21 ++ src/Renci.SshNet/IPrivateKeySource.cs | 17 +- src/Renci.SshNet/NetConfClient.cs | 4 +- .../PrivateKeyAuthenticationMethod.cs | 27 ++- src/Renci.SshNet/PrivateKeyConnectionInfo.cs | 18 +- src/Renci.SshNet/PrivateKeyFile.cs | 66 +++++- src/Renci.SshNet/ScpClient.cs | 4 +- .../Cryptography/Ciphers/RsaCipher.cs | 7 +- .../Security/Cryptography/DsaKey.cs | 2 +- .../Security/Cryptography/ED25519Key.cs | 2 +- .../Security/Cryptography/EcdsaKey.cs | 2 +- src/Renci.SshNet/Security/Cryptography/Key.cs | 4 +- .../Cryptography/RsaDigitalSignature.cs | 17 +- .../Security/Cryptography/RsaKey.cs | 8 +- src/Renci.SshNet/Security/KeyExchange.cs | 22 ++ .../Security/KeyExchangeDiffieHellman.cs | 16 +- src/Renci.SshNet/Security/KeyExchangeEC.cs | 20 +- src/Renci.SshNet/Security/KeyHostAlgorithm.cs | 120 ++++++++-- src/Renci.SshNet/SftpClient.cs | 4 +- src/Renci.SshNet/SshClient.cs | 4 +- 34 files changed, 767 insertions(+), 210 deletions(-) create mode 100644 src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs create mode 100644 src/Renci.SshNet/IHostAlgorithmsProvider.cs diff --git a/src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs b/src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs index 64676a0d2..af64ff62a 100644 --- a/src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs +++ b/src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs @@ -20,9 +20,7 @@ public static void Reset(this RemoteSshdConfig remoteSshdConfig) .ClearCiphers() .ClearKeyExchangeAlgorithms() .ClearHostKeyAlgorithms() - .AddHostKeyAlgorithm(HostKeyAlgorithm.SshRsa) .ClearPublicKeyAcceptedAlgorithms() - .AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.SshRsa) .WithUsePAM(true) .Update() .Restart(); diff --git a/src/Renci.SshNet.IntegrationTests/Dockerfile b/src/Renci.SshNet.IntegrationTests/Dockerfile index 811d51543..160ea6f29 100644 --- a/src/Renci.SshNet.IntegrationTests/Dockerfile +++ b/src/Renci.SshNet.IntegrationTests/Dockerfile @@ -14,7 +14,6 @@ RUN apk update && apk upgrade --no-cache && \ chmod 400 /etc/ssh/ssh*key && \ sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config && \ sed -i 's/#LogLevel\s*INFO/LogLevel DEBUG3/' /etc/ssh/sshd_config && \ - echo 'PubkeyAcceptedAlgorithms ssh-rsa' >> /etc/ssh/sshd_config && \ chmod 646 /etc/ssh/sshd_config && \ # install and configure sudo apk add --no-cache sudo && \ diff --git a/src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs b/src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs index 3732f1e22..7f177a6f4 100644 --- a/src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs +++ b/src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs @@ -22,63 +22,46 @@ public void TearDown() { _remoteSshdConfig?.Reset(); } - + [TestMethod] [Ignore] // No longer supported in recent versions of OpenSSH + // TODO: We should be able to enable some legacy settings to make it work + // https://www.openssh.com/legacy.html e.g. PubkeyAcceptedKeyTypes / HostbasedAcceptedKeyTypes ? public void SshDsa() { - _remoteSshdConfig.ClearHostKeyAlgorithms() - .AddHostKeyAlgorithm(HostKeyAlgorithm.SshDsa) - .ClearHostKeyFiles() - .AddHostKeyFile(HostKeyFile.Dsa.FilePath) - .Update() - .Restart(); - - HostKeyEventArgs hostKeyEventsArgs = null; - - using (var client = new SshClient(_connectionInfoFactory.Create())) - { - client.HostKeyReceived += (sender, e) => hostKeyEventsArgs = e; - client.Connect(); - client.Disconnect(); - } - - Assert.IsNotNull(hostKeyEventsArgs); - Assert.AreEqual(HostKeyFile.Dsa.KeyName, hostKeyEventsArgs.HostKeyName); - Assert.AreEqual(1024, hostKeyEventsArgs.KeyLength); - Assert.IsTrue(hostKeyEventsArgs.FingerPrint.SequenceEqual(HostKeyFile.Dsa.FingerPrint)); + DoTest(HostKeyAlgorithm.SshDsa, HostKeyFile.Dsa, 1024); } [TestMethod] public void SshRsa() { - _remoteSshdConfig.ClearHostKeyAlgorithms() - .AddHostKeyAlgorithm(HostKeyAlgorithm.SshRsa) - .Update() - .Restart(); - - HostKeyEventArgs hostKeyEventsArgs = null; + DoTest(HostKeyAlgorithm.SshRsa, HostKeyFile.Rsa, 3072); + } - using (var client = new SshClient(_connectionInfoFactory.Create())) - { - client.HostKeyReceived += (sender, e) => hostKeyEventsArgs = e; - client.Connect(); - client.Disconnect(); - } + [TestMethod] + public void SshRsaSha256() + { + DoTest(HostKeyAlgorithm.RsaSha2256, HostKeyFile.Rsa, 3072); + } - Assert.IsNotNull(hostKeyEventsArgs); - Assert.AreEqual(HostKeyFile.Rsa.KeyName, hostKeyEventsArgs.HostKeyName); - Assert.AreEqual(3072, hostKeyEventsArgs.KeyLength); - Assert.IsTrue(hostKeyEventsArgs.FingerPrint.SequenceEqual(HostKeyFile.Rsa.FingerPrint)); + [TestMethod] + public void SshRsaSha512() + { + DoTest(HostKeyAlgorithm.RsaSha2512, HostKeyFile.Rsa, 3072); } [TestMethod] public void SshEd25519() + { + DoTest(HostKeyAlgorithm.SshEd25519, HostKeyFile.Ed25519, 256); + } + + private void DoTest(HostKeyAlgorithm hostKeyAlgorithm, HostKeyFile hostKeyFile, int keyLength) { _remoteSshdConfig.ClearHostKeyAlgorithms() - .AddHostKeyAlgorithm(HostKeyAlgorithm.SshEd25519) + .AddHostKeyAlgorithm(hostKeyAlgorithm) .ClearHostKeyFiles() - .AddHostKeyFile(HostKeyFile.Ed25519.FilePath) + .AddHostKeyFile(hostKeyFile.FilePath) .Update() .Restart(); @@ -92,14 +75,9 @@ public void SshEd25519() } Assert.IsNotNull(hostKeyEventsArgs); - Assert.AreEqual(HostKeyFile.Ed25519.KeyName, hostKeyEventsArgs.HostKeyName); - Assert.AreEqual(256, hostKeyEventsArgs.KeyLength); - Assert.IsTrue(hostKeyEventsArgs.FingerPrint.SequenceEqual(HostKeyFile.Ed25519.FingerPrint)); - } - - private void Client_HostKeyReceived(object sender, HostKeyEventArgs e) - { - throw new NotImplementedException(); + Assert.AreEqual(hostKeyAlgorithm.Name, hostKeyEventsArgs.HostKeyName); + Assert.AreEqual(keyLength, hostKeyEventsArgs.KeyLength); + CollectionAssert.AreEqual(hostKeyFile.FingerPrint, hostKeyEventsArgs.FingerPrint); } } } diff --git a/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs b/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs index 83313f4a8..308f2ab3f 100644 --- a/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs +++ b/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.IntegrationTests { [TestClass] public class PrivateKeyAuthenticationTests : TestBase - { + { private IConnectionInfoFactory _connectionInfoFactory; private RemoteSshdConfig _remoteSshdConfig; @@ -23,43 +23,64 @@ public void TearDown() } [TestMethod] - public void Ecdsa256() + [Ignore] // No longer supported in recent versions of OpenSSH + // TODO: We should be able to enable some legacy settings to make it work + // https://www.openssh.com/legacy.html e.g. PubkeyAcceptedKeyTypes / HostbasedAcceptedKeyTypes ? + public void SshDsa() { - _remoteSshdConfig.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.EcdsaSha2Nistp256) - .Update() - .Restart(); + DoTest(PublicKeyAlgorithm.SshDss, "id_dsa"); + } - var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod("key_ecdsa_256_openssh")); + [TestMethod] + public void SshRsa() + { + DoTest(PublicKeyAlgorithm.SshRsa, "id_rsa"); + } - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - } + [TestMethod] + public void SshRsaSha256() + { + DoTest(PublicKeyAlgorithm.RsaSha2256, "id_rsa"); } [TestMethod] - public void Ecdsa384() + public void SshRsaSha512() { - _remoteSshdConfig.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.EcdsaSha2Nistp384) - .Update() - .Restart(); + DoTest(PublicKeyAlgorithm.RsaSha2512, "id_rsa"); + } - var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod("key_ecdsa_384_openssh")); + [TestMethod] + public void Ecdsa256() + { + DoTest(PublicKeyAlgorithm.EcdsaSha2Nistp256, "key_ecdsa_256_openssh"); + } - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - } + [TestMethod] + public void Ecdsa384() + { + DoTest(PublicKeyAlgorithm.EcdsaSha2Nistp384, "key_ecdsa_384_openssh"); } [TestMethod] - public void EcdsaA521() + public void Ecdsa521() + { + DoTest(PublicKeyAlgorithm.EcdsaSha2Nistp521, "key_ecdsa_521_openssh"); + } + + [TestMethod] + public void Ed25519() + { + DoTest(PublicKeyAlgorithm.SshEd25519, "key_ed25519_openssh"); + } + + private void DoTest(PublicKeyAlgorithm publicKeyAlgorithm, string keyResource) { - _remoteSshdConfig.AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm.EcdsaSha2Nistp521) + _remoteSshdConfig.ClearPublicKeyAcceptedAlgorithms() + .AddPublicKeyAcceptedAlgorithms(publicKeyAlgorithm) .Update() .Restart(); - var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod("key_ecdsa_521_openssh")); + var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod(keyResource)); using (var client = new SshClient(connectionInfo)) { diff --git a/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj b/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj index ae3505f10..db411f361 100644 --- a/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj +++ b/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj @@ -60,6 +60,7 @@ + diff --git a/src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys b/src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys index 484a0bdcc..8f0372d84 100644 --- a/src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys +++ b/src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys @@ -1,4 +1,5 @@ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4N0T6VopnwPSYQUw0waQNhBjz0DYFQwvkv4OwWYSf//fJF3M6bH42Tn2J+IlQ+4/fCFnE3m99seV5T1myEj7fsupNteY2sKFGXENLGtAD/76FM0iBmXx76xlSTyZSSmNDIRU4xUR23cfc+al84F5mO2lEk+5Zr3Qn5JUpucBfis4vtu0sMDgZ4w1d0tcuXkT/MEJn2iX2cnxbSy5qNAPHu7b+LEfXBv2OrMDqPrx/X6QREgi3w5RxL5kz7bvitWsIwIvb3ST2ARAArBwb8pEyp2A/w5p22rkQtL+3ibZ8fkmpgn33f31AZPgtM++iJPBmPKFjArcWEJ9fIVB/6DAj ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPzzrPpItEjNG7tU0DpJJ4pkI01E9d6K61OKTVPdFQSyGCdMj9XdP93lC6sJA+9/ahvf5F3gWEKxUJL2CKUiFWw= ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBLSsu/HNKiaALhQ26UDv+N0AFdMb26fMVrOKe866CGu6ajSf9HUOhJFdjhseihB2rTalMPr8MrcXNLufii4mL8u4l9fUQXFgwnM/ZpiVPSs6C+8i4u/ZDg7Nx2NXybNIgQ== -ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACB4WgRgGBRo6Uk+cRgg8tJPCbEtGURRWlUA7PDDerXR+P9O6mm3L99Etxsyh5XNYqXyaMNtH5c51ooMajrFwcayAHIhPPb8X3CsTwEfIUQ96aDyHQMotbRfnkn6uefeUTRrSNcqeAndUtVyAqBdqbsq2mgJYXHrz2NUKlPFYgauQi+WQ== \ No newline at end of file +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACB4WgRgGBRo6Uk+cRgg8tJPCbEtGURRWlUA7PDDerXR+P9O6mm3L99Etxsyh5XNYqXyaMNtH5c51ooMajrFwcayAHIhPPb8X3CsTwEfIUQ96aDyHQMotbRfnkn6uefeUTRrSNcqeAndUtVyAqBdqbsq2mgJYXHrz2NUKlPFYgauQi+WQ== +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAkNGPVOTuzuKTgGfHcve2MRj57yXhmZgkUyi9RpmJrl diff --git a/src/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs b/src/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs index b80967113..7dc9f309c 100644 --- a/src/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs +++ b/src/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs @@ -211,8 +211,11 @@ public void SaveTo(TextWriter writer) writer.WriteLine("MACs " + string.Join(",", MessageAuthenticationCodeAlgorithms.Select(c => c.Name).ToArray())); } - writer.WriteLine("PubkeyAcceptedAlgorithms " + string.Join(",", PublicKeyAcceptedAlgorithms.Select(c => c.Name).ToArray())); - + if (PublicKeyAcceptedAlgorithms.Count > 0) + { + writer.WriteLine("PubkeyAcceptedAlgorithms " + string.Join(",", PublicKeyAcceptedAlgorithms.Select(c => c.Name).ToArray())); + } + foreach (var match in Matches) { _matchFormatter.Format(match, writer); diff --git a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs index 516e3623f..e7ee53b90 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs @@ -42,7 +42,7 @@ public void HostKeyEventArgsConstructorTest() 0xa0, 0x23, 0xaf, 0xff, 0x9c, 0x0f, 0x8c, 0x83, 0x7c, 0xf8, 0xe1, 0x8e, 0x32, 0x8e, 0x61, 0xfc, 0x5b, 0xbd, 0xd4, 0x46, 0xe1 }.SequenceEqual(target.HostKey)); - Assert.AreEqual("ssh-rsa", target.HostKeyName); + Assert.AreEqual("rsa-sha2-512", target.HostKeyName); Assert.AreEqual(2048, target.KeyLength); } diff --git a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index 4ca6e9544..c684f0be7 100644 --- a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs @@ -1,8 +1,11 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; +using Renci.SshNet.Security; using Renci.SshNet.Tests.Common; using System; +using System.Collections.Generic; using System.IO; +using System.Linq; namespace Renci.SshNet.Tests.Classes { @@ -144,7 +147,7 @@ public void Test_PrivateKey_RSA() { using (var stream = GetData("Key.RSA.txt")) { - _ = new PrivateKeyFile(stream); + TestRsaKeyFile(new PrivateKeyFile(stream)); } } @@ -166,7 +169,7 @@ public void Test_PrivateKey_SSH2_RSA() { using (var stream = GetData("Key.SSH2.RSA.txt")) { - _ = new PrivateKeyFile(stream); + TestRsaKeyFile(new PrivateKeyFile(stream)); } } @@ -188,7 +191,7 @@ public void Test_PrivateKey_SSH2_Encrypted_RSA_DES_CBC() { using (var stream = GetData("Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt")) { - _ = new PrivateKeyFile(stream, "12345"); + TestRsaKeyFile(new PrivateKeyFile(stream, "12345")); } } @@ -262,7 +265,7 @@ public void Test_PrivateKey_RSA_DES_CBC() { using (var stream = GetData("Key.RSA.Encrypted.Des.CBC.12345.txt")) { - _ = new PrivateKeyFile(stream, "12345"); + TestRsaKeyFile(new PrivateKeyFile(stream, "12345")); } } @@ -284,7 +287,7 @@ public void Test_PrivateKey_RSA_AES_128_CBC() { using (var stream = GetData("Key.RSA.Encrypted.Aes.128.CBC.12345.txt")) { - _ = new PrivateKeyFile(stream, "12345"); + TestRsaKeyFile(new PrivateKeyFile(stream, "12345")); } } @@ -295,7 +298,7 @@ public void Test_PrivateKey_RSA_AES_192_CBC() { using (var stream = GetData("Key.RSA.Encrypted.Aes.192.CBC.12345.txt")) { - _ = new PrivateKeyFile(stream, "12345"); + TestRsaKeyFile(new PrivateKeyFile(stream, "12345")); } } @@ -306,7 +309,7 @@ public void Test_PrivateKey_RSA_AES_256_CBC() { using (var stream = GetData("Key.RSA.Encrypted.Aes.256.CBC.12345.txt")) { - _ = new PrivateKeyFile(stream, "12345"); + TestRsaKeyFile(new PrivateKeyFile(stream, "12345")); } } @@ -317,7 +320,7 @@ public void Test_PrivateKey_RSA_DES_EDE3_CFB() { using (var stream = GetData("Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt")) { - _ = new PrivateKeyFile(stream, "1234567890"); + TestRsaKeyFile(new PrivateKeyFile(stream, "1234567890")); } } @@ -576,7 +579,7 @@ public void Test_PrivateKey_OPENSSH_RSA() { using (var stream = GetData("Key.OPENSSH.RSA.txt")) { - _ = new PrivateKeyFile(stream); + TestRsaKeyFile(new PrivateKeyFile(stream)); } } @@ -587,7 +590,7 @@ public void Test_PrivateKey_OPENSSH_RSA_ENCRYPTED() { using (var stream = GetData("Key.OPENSSH.RSA.Encrypted.txt")) { - _ = new PrivateKeyFile(stream, "12345"); + TestRsaKeyFile(new PrivateKeyFile(stream, "12345")); } } @@ -678,5 +681,18 @@ private string GetTempFileName() File.Delete(tempFile); return tempFile; } + + private static void TestRsaKeyFile(PrivateKeyFile rsaPrivateKeyFile) + { + Assert.AreEqual(3, rsaPrivateKeyFile.HostAlgorithms.Count); + + List algorithms = rsaPrivateKeyFile.HostAlgorithms.Cast().ToList(); + + Assert.AreEqual("rsa-sha2-512", algorithms[0].Name); + Assert.AreEqual("rsa-sha2-256", algorithms[1].Name); + Assert.AreEqual("ssh-rsa", algorithms[2].Name); + + Assert.AreSame(algorithms[0], rsaPrivateKeyFile.HostKey); + } } } diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs index 93a76bbee..0c5c7eb02 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs @@ -1,4 +1,9 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System; +using System.Security.Cryptography; +using System.Text; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Security; using Renci.SshNet.Security.Cryptography; using Renci.SshNet.Tests.Common; @@ -11,17 +16,156 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography [TestClass] public class RsaDigitalSignatureTest : TestBase { + [TestMethod] + public void Sha1_SignAndVerify() + { + byte[] data = Encoding.UTF8.GetBytes("hello world"); + + RsaKey rsaKey = GetRsaKey(); + + var digitalSignature = new RsaDigitalSignature(rsaKey); // Verify SHA-1 is the default + + byte[] signedBytes = digitalSignature.Sign(data); + + byte[] expectedSignedBytes = new byte[] + { + // echo -n 'hello world' | openssl dgst -sha1 -sign Key.RSA.txt -out test.signed + 0x41, 0x50, 0x12, 0x14, 0xd3, 0x7c, 0xe0, 0x40, 0x50, 0x65, 0xfb, 0x33, 0xd9, 0x17, 0x89, 0xbf, + 0xb2, 0x4b, 0x85, 0x15, 0xbf, 0x9e, 0x57, 0x3b, 0x01, 0x15, 0x2b, 0x99, 0xfa, 0x62, 0x9b, 0x2a, + 0x05, 0xa0, 0x73, 0xc7, 0xb7, 0x5b, 0xd9, 0x01, 0xaa, 0x56, 0x73, 0x95, 0x13, 0x41, 0x33, 0x0d, + 0x7f, 0x83, 0x8a, 0x60, 0x4d, 0x19, 0xdc, 0x9b, 0xba, 0x8e, 0x61, 0xed, 0xd0, 0x8a, 0x3e, 0x38, + 0x71, 0xee, 0x34, 0xc3, 0x55, 0x0f, 0x55, 0x65, 0x89, 0xbb, 0x3e, 0x41, 0xee, 0xdf, 0xf5, 0x2f, + 0xab, 0x9e, 0x89, 0x37, 0x68, 0x1f, 0x9f, 0x38, 0x00, 0x81, 0x29, 0x93, 0xeb, 0x61, 0x37, 0xad, + 0x8d, 0x35, 0xf1, 0x3d, 0x4b, 0x9b, 0x99, 0x74, 0x7b, 0xeb, 0xf4, 0xfb, 0x76, 0xb4, 0xb6, 0xb4, + 0x09, 0x33, 0x5c, 0xfa, 0x6a, 0xad, 0x1e, 0xed, 0x1c, 0xe1, 0xb4, 0x4d, 0xf2, 0xa5, 0xc3, 0x64, + 0x9a, 0x45, 0x81, 0xee, 0x1b, 0xa6, 0x1d, 0x01, 0x3c, 0x4d, 0xb5, 0x62, 0x9e, 0xff, 0x8e, 0xff, + 0x6c, 0x18, 0xed, 0xe9, 0x8e, 0x03, 0x2c, 0xc5, 0x94, 0x81, 0xca, 0x8b, 0x18, 0x3f, 0x25, 0xcd, + 0xe5, 0x42, 0x49, 0x43, 0x23, 0x1f, 0xdc, 0x3f, 0xa2, 0x43, 0xbc, 0xbd, 0x42, 0xf5, 0x60, 0xfb, + 0x01, 0xd3, 0x67, 0x0d, 0x8d, 0x85, 0x7b, 0x51, 0x14, 0xec, 0x26, 0x53, 0x00, 0x61, 0x25, 0x16, + 0x19, 0x10, 0x3c, 0x86, 0x16, 0x59, 0x84, 0x08, 0xd1, 0xf9, 0x1e, 0x05, 0x88, 0xbd, 0x4a, 0x01, + 0x43, 0x4e, 0xec, 0x76, 0x0b, 0xd7, 0x2c, 0xe9, 0x98, 0xb1, 0x4c, 0x0a, 0x13, 0xc6, 0x95, 0xf9, + 0x8f, 0x95, 0x5c, 0x98, 0x4c, 0x8f, 0x97, 0x4a, 0xad, 0x0d, 0xfe, 0x84, 0xf0, 0x56, 0xc3, 0x29, + 0x73, 0x75, 0x55, 0x3c, 0xd9, 0x5e, 0x5b, 0x6f, 0xf9, 0x81, 0xbc, 0xbc, 0x50, 0x75, 0x7d, 0xa8 + }; + + CollectionAssert.AreEqual(expectedSignedBytes, signedBytes); + + // Also verify RsaKey uses SHA-1 by default + CollectionAssert.AreEqual(expectedSignedBytes, rsaKey.Sign(data)); + + // The following fails due to the _isPrivate decision in RsaCipher.Transform. Is that really correct? + //Assert.IsTrue(digitalSignature.Verify(data, signedBytes)); + + // 'Workaround': use a key with no private key information + var digitalSignaturePublic = new RsaDigitalSignature(new RsaKey() + { + Public = rsaKey.Public + }); + Assert.IsTrue(digitalSignaturePublic.Verify(data, signedBytes)); + } - /// - ///A test for RsaDigitalSignature Constructor - /// [TestMethod] - [Ignore] // placeholder for actual test - public void RsaDigitalSignatureConstructorTest() + public void Sha256_SignAndVerify() { - RsaKey rsaKey = null; // TODO: Initialize to an appropriate value - RsaDigitalSignature target = new RsaDigitalSignature(rsaKey); - Assert.Inconclusive("TODO: Implement code to verify target"); + byte[] data = Encoding.UTF8.GetBytes("hello world"); + + RsaKey rsaKey = GetRsaKey(); + + var digitalSignature = new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA256); + + byte[] signedBytes = digitalSignature.Sign(data); + + CollectionAssert.AreEqual(new byte[] + { + // echo -n 'hello world' | openssl dgst -sha256 -sign Key.RSA.txt -out test.signed + 0x2e, 0xef, 0x01, 0x49, 0x5c, 0x66, 0x37, 0x56, 0xc2, 0xfb, 0x7b, 0xfa, 0x80, 0x2f, 0xdb, 0xaa, + 0x0d, 0x15, 0xd9, 0x8d, 0xa9, 0xad, 0x81, 0x4f, 0x09, 0x2e, 0x53, 0x9e, 0xce, 0x5d, 0x68, 0x07, + 0xae, 0xb9, 0xc0, 0x45, 0xfa, 0x30, 0xd0, 0xf7, 0xd6, 0xa6, 0x8d, 0x19, 0x24, 0x3a, 0xea, 0x91, + 0x3e, 0xa2, 0x4a, 0x42, 0x2e, 0x21, 0xf1, 0x48, 0x57, 0xca, 0x2b, 0x6c, 0x9f, 0x79, 0x54, 0x91, + 0x3e, 0x3a, 0x4d, 0xd1, 0x70, 0x87, 0x3d, 0xbe, 0x22, 0x97, 0xc9, 0xb0, 0x02, 0xf0, 0xa2, 0xae, + 0x7a, 0xbb, 0x8b, 0xaf, 0xc0, 0x3b, 0xab, 0x71, 0xe8, 0x29, 0x1c, 0x18, 0x88, 0xca, 0x74, 0x1b, + 0x34, 0x4f, 0xd1, 0x83, 0x39, 0x6e, 0x8f, 0x69, 0x3d, 0x7e, 0xef, 0xef, 0x57, 0x7c, 0xff, 0x21, + 0x9c, 0x10, 0x2b, 0xd1, 0x4f, 0x26, 0xbe, 0xaa, 0xd2, 0xd9, 0x03, 0x14, 0x75, 0x97, 0x11, 0xaf, + 0xf0, 0x28, 0xf2, 0xd3, 0x07, 0x79, 0x5b, 0x27, 0xdc, 0x97, 0xd8, 0xce, 0x4e, 0x78, 0x89, 0x16, + 0x91, 0x2a, 0xb2, 0x47, 0x53, 0x94, 0xe9, 0xa1, 0x15, 0x98, 0x29, 0x0c, 0xa1, 0xf5, 0xe2, 0x8e, + 0x11, 0xdc, 0x0c, 0x1c, 0x10, 0xa4, 0xf2, 0x46, 0x5c, 0x78, 0x0c, 0xc1, 0x4a, 0x65, 0x21, 0x8a, + 0x2e, 0x32, 0x6c, 0x72, 0x06, 0xf9, 0x7f, 0xa1, 0x6c, 0x2e, 0x13, 0x06, 0x41, 0xaa, 0x23, 0xdd, + 0xc8, 0x1c, 0x61, 0xb6, 0x96, 0x87, 0xc4, 0x84, 0xc8, 0x61, 0xec, 0x4e, 0xdd, 0x49, 0x9e, 0x4f, + 0x0d, 0x8c, 0xf1, 0x7f, 0xf2, 0x6c, 0x73, 0x5a, 0xa6, 0x3b, 0xbf, 0x4e, 0xba, 0x57, 0x6b, 0xb3, + 0x1e, 0x6c, 0x57, 0x76, 0x87, 0x9f, 0xb4, 0x3b, 0xcb, 0xcd, 0xe5, 0x10, 0x7a, 0x4c, 0xeb, 0xc0, + 0xc4, 0xc3, 0x75, 0x51, 0x5f, 0xb7, 0x7c, 0xbc, 0x55, 0x8d, 0x05, 0xc7, 0xed, 0xc7, 0x52, 0x4a + }, signedBytes); + + + // The following fails due to the _isPrivate decision in RsaCipher.Transform. Is that really correct? + //Assert.IsTrue(digitalSignature.Verify(data, signedBytes)); + + // 'Workaround': use a key with no private key information + var digitalSignaturePublic = new RsaDigitalSignature(new RsaKey() + { + Public = rsaKey.Public + }, HashAlgorithmName.SHA256); + Assert.IsTrue(digitalSignaturePublic.Verify(data, signedBytes)); + } + + [TestMethod] + public void Sha512_SignAndVerify() + { + byte[] data = Encoding.UTF8.GetBytes("hello world"); + + RsaKey rsaKey = GetRsaKey(); + + var digitalSignature = new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA512); + + byte[] signedBytes = digitalSignature.Sign(data); + + CollectionAssert.AreEqual(new byte[] + { + // echo -n 'hello world' | openssl dgst -sha512 -sign Key.RSA.txt -out test.signed + 0x69, 0x70, 0xb5, 0x9f, 0x32, 0x86, 0x3b, 0xae, 0xc0, 0x79, 0x6e, 0xdb, 0x35, 0xd5, 0xa6, 0x22, + 0xcd, 0x2b, 0x4b, 0xd2, 0x68, 0x1a, 0x65, 0x41, 0xa6, 0xd9, 0x20, 0x54, 0x31, 0x9a, 0xb1, 0x44, + 0x6e, 0x8f, 0x56, 0x4b, 0xfc, 0x27, 0x7f, 0x3f, 0xe7, 0x47, 0xcb, 0x78, 0x03, 0x05, 0x79, 0x8a, + 0x16, 0x7b, 0x12, 0x01, 0x3a, 0xa2, 0xd5, 0x0d, 0x2b, 0x16, 0x38, 0xef, 0x84, 0x6b, 0xd7, 0x19, + 0xeb, 0xac, 0x54, 0x01, 0x9d, 0xa6, 0x80, 0x74, 0x43, 0xa8, 0x6e, 0x5e, 0x33, 0x05, 0x06, 0x1d, + 0x6d, 0xfe, 0x32, 0x4f, 0xe3, 0xcb, 0x3e, 0x2d, 0x4e, 0xe1, 0x47, 0x03, 0x69, 0xb4, 0x59, 0x80, + 0x59, 0x05, 0x15, 0xa0, 0x11, 0x34, 0x47, 0x58, 0xd7, 0x93, 0x2d, 0x40, 0xf2, 0x2c, 0x37, 0x48, + 0x6b, 0x3c, 0xd3, 0x03, 0x09, 0x32, 0x74, 0xa0, 0x2d, 0x33, 0x11, 0x99, 0x10, 0xb4, 0x09, 0x31, + 0xec, 0xa3, 0x2c, 0x63, 0xba, 0x50, 0xd1, 0x02, 0x45, 0xae, 0xb5, 0x75, 0x7e, 0xfa, 0xfc, 0x06, + 0xb6, 0x6a, 0xb2, 0xa1, 0x73, 0x14, 0xa5, 0xaa, 0x17, 0x88, 0x03, 0x19, 0x14, 0x9b, 0xe1, 0x10, + 0xf8, 0x2f, 0x73, 0x01, 0xc7, 0x8d, 0x37, 0xef, 0x98, 0x69, 0xc2, 0xe2, 0x7a, 0x11, 0xd5, 0xb8, + 0xc9, 0x35, 0x45, 0xcb, 0x56, 0x4b, 0x92, 0x4a, 0xe0, 0x4c, 0xd6, 0x82, 0xae, 0xad, 0x5b, 0xe9, + 0x40, 0x7e, 0x2a, 0x48, 0x7d, 0x57, 0xc5, 0xfd, 0xe9, 0x98, 0xe0, 0xbb, 0x09, 0xa1, 0xf5, 0x48, + 0x45, 0xcb, 0xee, 0xb9, 0x99, 0x81, 0x44, 0x15, 0x2e, 0x50, 0x39, 0x64, 0x58, 0x4c, 0x34, 0x86, + 0xf8, 0x81, 0x9e, 0x1d, 0xb6, 0x97, 0xe0, 0xce, 0x16, 0xca, 0x20, 0x46, 0xe9, 0x49, 0x8f, 0xe6, + 0xa0, 0x23, 0x08, 0x80, 0xa6, 0x37, 0x70, 0x06, 0xcc, 0x8f, 0xf4, 0xa0, 0x74, 0x53, 0x26, 0x38 + }, signedBytes); + + // The following fails due to the _isPrivate decision in RsaCipher.Transform. Is that really correct? + //Assert.IsTrue(digitalSignature.Verify(data, signedBytes)); + + // 'Workaround': use a key with no private key information + var digitalSignaturePublic = new RsaDigitalSignature(new RsaKey() + { + Public = rsaKey.Public + }, HashAlgorithmName.SHA512); + Assert.IsTrue(digitalSignaturePublic.Verify(data, signedBytes)); + } + + [TestMethod] + public void Constructor_InvalidHashAlgorithm_ThrowsArgumentException() + { + ArgumentException exception = Assert.ThrowsException( + () => new RsaDigitalSignature(new RsaKey(), new HashAlgorithmName("invalid"))); + + Assert.AreEqual("hashAlgorithmName", exception.ParamName); + } + + private static RsaKey GetRsaKey() + { + using (var stream = GetData("Key.RSA.txt")) + { + return (RsaKey) ((KeyHostAlgorithm) new PrivateKeyFile(stream).HostKey).Key; + } } /// @@ -37,4 +181,4 @@ public void DisposeTest() Assert.Inconclusive("A method that does not return a value cannot be verified."); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs new file mode 100644 index 000000000..6f92362b4 --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs @@ -0,0 +1,215 @@ +锘縰sing System.Security.Cryptography; +using System.Text; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Security; +using Renci.SshNet.Security.Cryptography; +using Renci.SshNet.Tests.Common; + +namespace Renci.SshNet.Tests.Classes.Security +{ + [TestClass] + public class KeyHostAlgorithmTest : TestBase + { + [TestMethod] + public void NoSuppliedDigitalSignature_PropertyIsKeyDigitalSignature() + { + RsaKey rsaKey = GetRsaKey(); + + KeyHostAlgorithm keyHostAlgorithm = new KeyHostAlgorithm("ssh-rsa", rsaKey); + + Assert.AreEqual("ssh-rsa", keyHostAlgorithm.Name); + Assert.AreSame(rsaKey, keyHostAlgorithm.Key); + Assert.AreSame(rsaKey.DigitalSignature, keyHostAlgorithm.DigitalSignature); + } + + [TestMethod] + public void SuppliedDigitalSignature_PropertyIsSuppliedDigitalSignature() + { + RsaKey rsaKey = GetRsaKey(); + RsaDigitalSignature rsaDigitalSignature = new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA256); + KeyHostAlgorithm keyHostAlgorithm = new KeyHostAlgorithm("rsa-sha2-256", rsaKey, rsaDigitalSignature); + + Assert.AreEqual("rsa-sha2-256", keyHostAlgorithm.Name); + Assert.AreSame(rsaKey, keyHostAlgorithm.Key); + Assert.AreSame(rsaDigitalSignature, keyHostAlgorithm.DigitalSignature); + } + + [TestMethod] + public void RsaPublicKeyDataDoesNotDependOnSignatureAlgorithm() + { + TestRsaPublicKeyData("ssh-rsa", HashAlgorithmName.SHA1); + TestRsaPublicKeyData("rsa-sha2-256", HashAlgorithmName.SHA256); + } + + private void TestRsaPublicKeyData(string signatureIdentifier, HashAlgorithmName hashAlgorithmName) + { + RsaKey key = GetRsaKey(); + KeyHostAlgorithm keyAlgorithm = new KeyHostAlgorithm(signatureIdentifier, key, new RsaDigitalSignature(key, hashAlgorithmName)); + + CollectionAssert.AreEqual(GetRsaPublicKeyBytes(), keyAlgorithm.Data); + } + + [TestMethod] + public void SshRsa_SignAndVerify() + { + byte[] data = Encoding.UTF8.GetBytes("hello world"); + + RsaKey key = GetRsaKey(); + KeyHostAlgorithm keyAlgorithm = new KeyHostAlgorithm("ssh-rsa", key); + + byte[] expectedEncodedSignatureBytes = new byte[] + { + 0, 0, 0, 7, // byte count of "ssh-rsa" + (byte)'s', (byte)'s', (byte)'h', (byte)'-', (byte)'r', (byte)'s', (byte)'a', // ssh-rsa + 0, 0, 1, 0, // byte count of signature (=256) + + // echo -n 'hello world' | openssl dgst -sha1 -sign Key.RSA.txt -out test.signed + 0x41, 0x50, 0x12, 0x14, 0xd3, 0x7c, 0xe0, 0x40, 0x50, 0x65, 0xfb, 0x33, 0xd9, 0x17, 0x89, 0xbf, + 0xb2, 0x4b, 0x85, 0x15, 0xbf, 0x9e, 0x57, 0x3b, 0x01, 0x15, 0x2b, 0x99, 0xfa, 0x62, 0x9b, 0x2a, + 0x05, 0xa0, 0x73, 0xc7, 0xb7, 0x5b, 0xd9, 0x01, 0xaa, 0x56, 0x73, 0x95, 0x13, 0x41, 0x33, 0x0d, + 0x7f, 0x83, 0x8a, 0x60, 0x4d, 0x19, 0xdc, 0x9b, 0xba, 0x8e, 0x61, 0xed, 0xd0, 0x8a, 0x3e, 0x38, + 0x71, 0xee, 0x34, 0xc3, 0x55, 0x0f, 0x55, 0x65, 0x89, 0xbb, 0x3e, 0x41, 0xee, 0xdf, 0xf5, 0x2f, + 0xab, 0x9e, 0x89, 0x37, 0x68, 0x1f, 0x9f, 0x38, 0x00, 0x81, 0x29, 0x93, 0xeb, 0x61, 0x37, 0xad, + 0x8d, 0x35, 0xf1, 0x3d, 0x4b, 0x9b, 0x99, 0x74, 0x7b, 0xeb, 0xf4, 0xfb, 0x76, 0xb4, 0xb6, 0xb4, + 0x09, 0x33, 0x5c, 0xfa, 0x6a, 0xad, 0x1e, 0xed, 0x1c, 0xe1, 0xb4, 0x4d, 0xf2, 0xa5, 0xc3, 0x64, + 0x9a, 0x45, 0x81, 0xee, 0x1b, 0xa6, 0x1d, 0x01, 0x3c, 0x4d, 0xb5, 0x62, 0x9e, 0xff, 0x8e, 0xff, + 0x6c, 0x18, 0xed, 0xe9, 0x8e, 0x03, 0x2c, 0xc5, 0x94, 0x81, 0xca, 0x8b, 0x18, 0x3f, 0x25, 0xcd, + 0xe5, 0x42, 0x49, 0x43, 0x23, 0x1f, 0xdc, 0x3f, 0xa2, 0x43, 0xbc, 0xbd, 0x42, 0xf5, 0x60, 0xfb, + 0x01, 0xd3, 0x67, 0x0d, 0x8d, 0x85, 0x7b, 0x51, 0x14, 0xec, 0x26, 0x53, 0x00, 0x61, 0x25, 0x16, + 0x19, 0x10, 0x3c, 0x86, 0x16, 0x59, 0x84, 0x08, 0xd1, 0xf9, 0x1e, 0x05, 0x88, 0xbd, 0x4a, 0x01, + 0x43, 0x4e, 0xec, 0x76, 0x0b, 0xd7, 0x2c, 0xe9, 0x98, 0xb1, 0x4c, 0x0a, 0x13, 0xc6, 0x95, 0xf9, + 0x8f, 0x95, 0x5c, 0x98, 0x4c, 0x8f, 0x97, 0x4a, 0xad, 0x0d, 0xfe, 0x84, 0xf0, 0x56, 0xc3, 0x29, + 0x73, 0x75, 0x55, 0x3c, 0xd9, 0x5e, 0x5b, 0x6f, 0xf9, 0x81, 0xbc, 0xbc, 0x50, 0x75, 0x7d, 0xa8 + }; + + CollectionAssert.AreEqual(expectedEncodedSignatureBytes, keyAlgorithm.Sign(data)); + + keyAlgorithm = new KeyHostAlgorithm("ssh-rsa", new RsaKey(), GetRsaPublicKeyBytes()); + Assert.IsTrue(keyAlgorithm.VerifySignature(data, expectedEncodedSignatureBytes)); + } + + [TestMethod] + public void RsaSha256_SignAndVerify() + { + byte[] data = Encoding.UTF8.GetBytes("hello world"); + + RsaKey key = GetRsaKey(); + KeyHostAlgorithm keyAlgorithm = new KeyHostAlgorithm("rsa-sha2-256", key, new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); + + byte[] expectedEncodedSignatureBytes = new byte[] + { + 0, 0, 0, 12, // byte count of "rsa-sha2-256" + (byte)'r', (byte)'s', (byte)'a', (byte)'-', (byte)'s', (byte)'h', (byte)'a', (byte)'2', + (byte)'-', (byte)'2', (byte)'5', (byte)'6', + 0, 0, 1, 0, // byte count of signature (=256) + + // echo -n 'hello world' | openssl dgst -sha256 -sign Key.RSA.txt -out test.signed + 0x2e, 0xef, 0x01, 0x49, 0x5c, 0x66, 0x37, 0x56, 0xc2, 0xfb, 0x7b, 0xfa, 0x80, 0x2f, 0xdb, 0xaa, + 0x0d, 0x15, 0xd9, 0x8d, 0xa9, 0xad, 0x81, 0x4f, 0x09, 0x2e, 0x53, 0x9e, 0xce, 0x5d, 0x68, 0x07, + 0xae, 0xb9, 0xc0, 0x45, 0xfa, 0x30, 0xd0, 0xf7, 0xd6, 0xa6, 0x8d, 0x19, 0x24, 0x3a, 0xea, 0x91, + 0x3e, 0xa2, 0x4a, 0x42, 0x2e, 0x21, 0xf1, 0x48, 0x57, 0xca, 0x2b, 0x6c, 0x9f, 0x79, 0x54, 0x91, + 0x3e, 0x3a, 0x4d, 0xd1, 0x70, 0x87, 0x3d, 0xbe, 0x22, 0x97, 0xc9, 0xb0, 0x02, 0xf0, 0xa2, 0xae, + 0x7a, 0xbb, 0x8b, 0xaf, 0xc0, 0x3b, 0xab, 0x71, 0xe8, 0x29, 0x1c, 0x18, 0x88, 0xca, 0x74, 0x1b, + 0x34, 0x4f, 0xd1, 0x83, 0x39, 0x6e, 0x8f, 0x69, 0x3d, 0x7e, 0xef, 0xef, 0x57, 0x7c, 0xff, 0x21, + 0x9c, 0x10, 0x2b, 0xd1, 0x4f, 0x26, 0xbe, 0xaa, 0xd2, 0xd9, 0x03, 0x14, 0x75, 0x97, 0x11, 0xaf, + 0xf0, 0x28, 0xf2, 0xd3, 0x07, 0x79, 0x5b, 0x27, 0xdc, 0x97, 0xd8, 0xce, 0x4e, 0x78, 0x89, 0x16, + 0x91, 0x2a, 0xb2, 0x47, 0x53, 0x94, 0xe9, 0xa1, 0x15, 0x98, 0x29, 0x0c, 0xa1, 0xf5, 0xe2, 0x8e, + 0x11, 0xdc, 0x0c, 0x1c, 0x10, 0xa4, 0xf2, 0x46, 0x5c, 0x78, 0x0c, 0xc1, 0x4a, 0x65, 0x21, 0x8a, + 0x2e, 0x32, 0x6c, 0x72, 0x06, 0xf9, 0x7f, 0xa1, 0x6c, 0x2e, 0x13, 0x06, 0x41, 0xaa, 0x23, 0xdd, + 0xc8, 0x1c, 0x61, 0xb6, 0x96, 0x87, 0xc4, 0x84, 0xc8, 0x61, 0xec, 0x4e, 0xdd, 0x49, 0x9e, 0x4f, + 0x0d, 0x8c, 0xf1, 0x7f, 0xf2, 0x6c, 0x73, 0x5a, 0xa6, 0x3b, 0xbf, 0x4e, 0xba, 0x57, 0x6b, 0xb3, + 0x1e, 0x6c, 0x57, 0x76, 0x87, 0x9f, 0xb4, 0x3b, 0xcb, 0xcd, 0xe5, 0x10, 0x7a, 0x4c, 0xeb, 0xc0, + 0xc4, 0xc3, 0x75, 0x51, 0x5f, 0xb7, 0x7c, 0xbc, 0x55, 0x8d, 0x05, 0xc7, 0xed, 0xc7, 0x52, 0x4a + }; + + CollectionAssert.AreEqual(expectedEncodedSignatureBytes, keyAlgorithm.Sign(data)); + + key = new RsaKey(); + keyAlgorithm = new KeyHostAlgorithm("rsa-sha2-256", key, GetRsaPublicKeyBytes(), new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); + Assert.IsTrue(keyAlgorithm.VerifySignature(data, expectedEncodedSignatureBytes)); + } + + [TestMethod] + public void RsaSha512_SignAndVerify() + { + byte[] data = Encoding.UTF8.GetBytes("hello world"); + + RsaKey key = GetRsaKey(); + KeyHostAlgorithm keyAlgorithm = new KeyHostAlgorithm("rsa-sha2-512", key, new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); + + byte[] expectedEncodedSignatureBytes = new byte[] + { + 0, 0, 0, 12, // byte count of "rsa-sha2-512" + (byte)'r', (byte)'s', (byte)'a', (byte)'-', (byte)'s', (byte)'h', (byte)'a', (byte)'2', + (byte)'-', (byte)'5', (byte)'1', (byte)'2', + 0, 0, 1, 0, // byte count of signature (=256) + + // echo -n 'hello world' | openssl dgst -sha512 -sign Key.RSA.txt -out test.signed + 0x69, 0x70, 0xb5, 0x9f, 0x32, 0x86, 0x3b, 0xae, 0xc0, 0x79, 0x6e, 0xdb, 0x35, 0xd5, 0xa6, 0x22, + 0xcd, 0x2b, 0x4b, 0xd2, 0x68, 0x1a, 0x65, 0x41, 0xa6, 0xd9, 0x20, 0x54, 0x31, 0x9a, 0xb1, 0x44, + 0x6e, 0x8f, 0x56, 0x4b, 0xfc, 0x27, 0x7f, 0x3f, 0xe7, 0x47, 0xcb, 0x78, 0x03, 0x05, 0x79, 0x8a, + 0x16, 0x7b, 0x12, 0x01, 0x3a, 0xa2, 0xd5, 0x0d, 0x2b, 0x16, 0x38, 0xef, 0x84, 0x6b, 0xd7, 0x19, + 0xeb, 0xac, 0x54, 0x01, 0x9d, 0xa6, 0x80, 0x74, 0x43, 0xa8, 0x6e, 0x5e, 0x33, 0x05, 0x06, 0x1d, + 0x6d, 0xfe, 0x32, 0x4f, 0xe3, 0xcb, 0x3e, 0x2d, 0x4e, 0xe1, 0x47, 0x03, 0x69, 0xb4, 0x59, 0x80, + 0x59, 0x05, 0x15, 0xa0, 0x11, 0x34, 0x47, 0x58, 0xd7, 0x93, 0x2d, 0x40, 0xf2, 0x2c, 0x37, 0x48, + 0x6b, 0x3c, 0xd3, 0x03, 0x09, 0x32, 0x74, 0xa0, 0x2d, 0x33, 0x11, 0x99, 0x10, 0xb4, 0x09, 0x31, + 0xec, 0xa3, 0x2c, 0x63, 0xba, 0x50, 0xd1, 0x02, 0x45, 0xae, 0xb5, 0x75, 0x7e, 0xfa, 0xfc, 0x06, + 0xb6, 0x6a, 0xb2, 0xa1, 0x73, 0x14, 0xa5, 0xaa, 0x17, 0x88, 0x03, 0x19, 0x14, 0x9b, 0xe1, 0x10, + 0xf8, 0x2f, 0x73, 0x01, 0xc7, 0x8d, 0x37, 0xef, 0x98, 0x69, 0xc2, 0xe2, 0x7a, 0x11, 0xd5, 0xb8, + 0xc9, 0x35, 0x45, 0xcb, 0x56, 0x4b, 0x92, 0x4a, 0xe0, 0x4c, 0xd6, 0x82, 0xae, 0xad, 0x5b, 0xe9, + 0x40, 0x7e, 0x2a, 0x48, 0x7d, 0x57, 0xc5, 0xfd, 0xe9, 0x98, 0xe0, 0xbb, 0x09, 0xa1, 0xf5, 0x48, + 0x45, 0xcb, 0xee, 0xb9, 0x99, 0x81, 0x44, 0x15, 0x2e, 0x50, 0x39, 0x64, 0x58, 0x4c, 0x34, 0x86, + 0xf8, 0x81, 0x9e, 0x1d, 0xb6, 0x97, 0xe0, 0xce, 0x16, 0xca, 0x20, 0x46, 0xe9, 0x49, 0x8f, 0xe6, + 0xa0, 0x23, 0x08, 0x80, 0xa6, 0x37, 0x70, 0x06, 0xcc, 0x8f, 0xf4, 0xa0, 0x74, 0x53, 0x26, 0x38 + }; + + CollectionAssert.AreEqual(expectedEncodedSignatureBytes, keyAlgorithm.Sign(data)); + + key = new RsaKey(); + keyAlgorithm = new KeyHostAlgorithm("rsa-sha2-512", key, GetRsaPublicKeyBytes(), new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); + Assert.IsTrue(keyAlgorithm.VerifySignature(data, expectedEncodedSignatureBytes)); + } + + private static RsaKey GetRsaKey() + { + using (var stream = GetData("Key.RSA.txt")) + { + return (RsaKey) ((KeyHostAlgorithm) new PrivateKeyFile(stream).HostKey).Key; + } + } + + private static byte[] GetRsaPublicKeyBytes() + { + return new byte[] + { + 0, 0, 0, 7, // byte count of "ssh-rsa" + (byte)'s', (byte)'s', (byte)'h', (byte)'-', (byte)'r', (byte)'s', (byte)'a', // ssh-rsa + 0, 0, 0, 1, // byte count of exponent + 35, // exponent + 0, 0, 1, 1, // byte count of modulus (=257) + + // openssl rsa -in Key.RSA.txt -text + 0x00, 0xb9, 0x3b, 0x57, 0x9f, 0xe0, 0x5a, 0xb5, 0x7d, 0x68, 0x26, 0xeb, 0xe1, 0xa9, 0xf2, + 0x59, 0xc3, 0x98, 0xdc, 0xfe, 0x97, 0x08, 0xc4, 0x95, 0x0f, 0x9a, 0xea, 0x05, 0x08, 0x7d, + 0xfe, 0x6d, 0x77, 0xca, 0x04, 0x9f, 0xfd, 0xe2, 0x2c, 0x4d, 0x11, 0x3c, 0xd9, 0x05, 0xab, + 0x32, 0xbd, 0x3f, 0xe8, 0xcd, 0xba, 0x00, 0x6c, 0x21, 0xb7, 0xa9, 0xc2, 0x4e, 0x63, 0x17, + 0xf6, 0x04, 0x47, 0x93, 0x00, 0x85, 0xde, 0xd6, 0x32, 0xc0, 0xa1, 0x37, 0x75, 0x18, 0xa0, + 0xb0, 0x32, 0xf6, 0x4e, 0xca, 0x39, 0xec, 0x3c, 0xdf, 0x79, 0xfe, 0x50, 0xa1, 0xc1, 0xf7, + 0x67, 0x05, 0xb3, 0x33, 0xa5, 0x96, 0x13, 0x19, 0xfa, 0x14, 0xca, 0x55, 0xe6, 0x7b, 0xf9, + 0xb3, 0x8e, 0x32, 0xee, 0xfc, 0x9d, 0x2a, 0x5e, 0x04, 0x79, 0x97, 0x29, 0x3d, 0x1c, 0x54, + 0xfe, 0xc7, 0x96, 0x04, 0xb5, 0x19, 0x7c, 0x55, 0x21, 0xe2, 0x0e, 0x42, 0xca, 0x4d, 0x9d, + 0xfb, 0x77, 0x08, 0x6c, 0xaa, 0x07, 0x2c, 0xf8, 0xf9, 0x1f, 0xbd, 0x83, 0x14, 0x2b, 0xe0, + 0xbc, 0x7a, 0xf9, 0xdf, 0x13, 0x4b, 0x60, 0x5a, 0x02, 0x99, 0x93, 0x41, 0x1a, 0xb6, 0x5f, + 0x3b, 0x9c, 0xb5, 0xb2, 0x55, 0x70, 0x78, 0x2f, 0x38, 0x52, 0x0e, 0xd1, 0x8a, 0x2c, 0x23, + 0xc0, 0x3a, 0x0a, 0xd7, 0xed, 0xf6, 0x1f, 0xa6, 0x50, 0xf0, 0x27, 0x65, 0x8a, 0xd4, 0xde, + 0xa7, 0x1b, 0x41, 0x67, 0xc5, 0x6d, 0x47, 0x84, 0x37, 0x92, 0x2b, 0xb7, 0xb6, 0x4d, 0xb0, + 0x1a, 0xda, 0xf6, 0x50, 0x82, 0xf1, 0x57, 0x31, 0x69, 0xce, 0xe0, 0xef, 0xcd, 0x64, 0xaa, + 0x78, 0x08, 0xea, 0x4e, 0x45, 0xec, 0xa5, 0x89, 0x68, 0x5d, 0xb4, 0xa0, 0x23, 0xaf, 0xff, + 0x9c, 0x0f, 0x8c, 0x83, 0x7c, 0xf8, 0xe1, 0x8e, 0x32, 0x8e, 0x61, 0xfc, 0x5b, 0xbd, 0xd4, + 0x46, 0xe1 + }; + } + } +} diff --git a/src/Renci.SshNet.Tests/Common/TestBase.cs b/src/Renci.SshNet.Tests/Common/TestBase.cs index 4ae86fb41..5973aa4a3 100644 --- a/src/Renci.SshNet.Tests/Common/TestBase.cs +++ b/src/Renci.SshNet.Tests/Common/TestBase.cs @@ -49,9 +49,9 @@ protected void CreateTestFile(string fileName, int size) } } - protected Stream GetData(string name) + protected static Stream GetData(string name) { return ExecutingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", name)); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Common/ObjectIdentifier.cs b/src/Renci.SshNet/Common/ObjectIdentifier.cs index f1b2d88df..a02a40908 100644 --- a/src/Renci.SshNet/Common/ObjectIdentifier.cs +++ b/src/Renci.SshNet/Common/ObjectIdentifier.cs @@ -1,4 +1,6 @@ 锘縰sing System; +using System.Linq; +using System.Security.Cryptography; namespace Renci.SshNet.Common { @@ -32,5 +34,19 @@ public ObjectIdentifier(params ulong[] identifiers) Identifiers = identifiers; } + + internal static ObjectIdentifier FromHashAlgorithmName(HashAlgorithmName hashAlgorithmName) + { + var oid = CryptoConfig.MapNameToOID(hashAlgorithmName.Name); + + if (oid is null) + { + throw new ArgumentException($"Could not map `{hashAlgorithmName}` to OID.", nameof(hashAlgorithmName)); + } + + var identifiers = oid.Split('.').Select(ulong.Parse).ToArray(); + + return new ObjectIdentifier(identifiers); + } } } diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index e7bd6cdd2..a8089900a 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Security.Cryptography; using System.Text; using Renci.SshNet.Abstractions; @@ -9,6 +10,7 @@ using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Messages.Connection; using Renci.SshNet.Security; +using Renci.SshNet.Security.Cryptography; using Renci.SshNet.Security.Cryptography.Ciphers; using Renci.SshNet.Security.Cryptography.Ciphers.Modes; @@ -396,6 +398,8 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy { "ecdsa-sha2-nistp256", data => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(), data) }, { "ecdsa-sha2-nistp384", data => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(), data) }, { "ecdsa-sha2-nistp521", data => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(), data) }, + { "rsa-sha2-512", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-512", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); }}, + { "rsa-sha2-256", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-256", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); }}, { "ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data) }, { "ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(), data) }, }; diff --git a/src/Renci.SshNet/IHostAlgorithmsProvider.cs b/src/Renci.SshNet/IHostAlgorithmsProvider.cs new file mode 100644 index 000000000..89ac27128 --- /dev/null +++ b/src/Renci.SshNet/IHostAlgorithmsProvider.cs @@ -0,0 +1,21 @@ +锘縰sing System.Collections.Generic; + +using Renci.SshNet.Security; + +namespace Renci.SshNet +{ + /// + /// Represents a collection of host algorithms. + /// + public interface IHostAlgorithmsProvider + { + /// + /// The host algorithms provided by this . + /// + /// + /// In situations where there is a preferred order of usage of the host algorithms, + /// the collection should be ordered from most preferred to least. + /// + IReadOnlyCollection HostAlgorithms { get; } + } +} diff --git a/src/Renci.SshNet/IPrivateKeySource.cs b/src/Renci.SshNet/IPrivateKeySource.cs index fc3405462..466a36d2a 100644 --- a/src/Renci.SshNet/IPrivateKeySource.cs +++ b/src/Renci.SshNet/IPrivateKeySource.cs @@ -1,15 +1,26 @@ -锘縰sing Renci.SshNet.Security; +锘縰sing System; +using System.ComponentModel; + +using Renci.SshNet.Security; namespace Renci.SshNet { /// /// Represents private key source interface. /// - public interface IPrivateKeySource + /// + /// This interface has been replaced by + /// and is obsolete. + /// + [Obsolete($"Use {nameof(IHostAlgorithmsProvider)} instead. " + + $"{nameof(IPrivateKeySource)} may be removed in a future release. " + + $"See https://github.com/sshnet/SSH.NET/issues/1174 for details.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public interface IPrivateKeySource : IHostAlgorithmsProvider { /// /// Gets the host key. /// HostAlgorithm HostKey { get; } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/NetConfClient.cs b/src/Renci.SshNet/NetConfClient.cs index bbedca3c2..95cc99f7d 100644 --- a/src/Renci.SshNet/NetConfClient.cs +++ b/src/Renci.SshNet/NetConfClient.cs @@ -107,7 +107,7 @@ public NetConfClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public NetConfClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) + public NetConfClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -120,7 +120,7 @@ public NetConfClient(string host, int port, string username, params IPrivateKeyS /// Authentication private key file(s) . /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public NetConfClient(string host, string username, params IPrivateKeySource[] keyFiles) + public NetConfClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } diff --git a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs index 960a68b20..cb82cd7ac 100644 --- a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs +++ b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs @@ -1,6 +1,7 @@ 锘縰sing System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Linq; using System.Threading; using Renci.SshNet.Common; @@ -30,7 +31,7 @@ public override string Name /// /// Gets the key files used for authentication. /// - public ICollection KeyFiles { get; private set; } + public ICollection KeyFiles { get; private set; } /// /// Initializes a new instance of the class. @@ -38,7 +39,7 @@ public override string Name /// The username. /// The key files. /// is whitespace or null. - public PrivateKeyAuthenticationMethod(string username, params IPrivateKeySource[] keyFiles) + public PrivateKeyAuthenticationMethod(string username, params IHostAlgorithmsProvider[] keyFiles) : base(username) { if (keyFiles is null) @@ -46,7 +47,7 @@ public PrivateKeyAuthenticationMethod(string username, params IPrivateKeySource[ throw new ArgumentNullException(nameof(keyFiles)); } - KeyFiles = new Collection(keyFiles); + KeyFiles = new Collection(keyFiles); } /// @@ -64,24 +65,26 @@ public override AuthenticationResult Authenticate(Session session) session.RegisterMessage("SSH_MSG_USERAUTH_PK_OK"); + var hostAlgorithms = KeyFiles.SelectMany(x => x.HostAlgorithms).ToList(); + try { - foreach (var keyFile in KeyFiles) + foreach (var hostAlgorithm in hostAlgorithms) { _ = _authenticationCompleted.Reset(); _isSignatureRequired = false; var message = new RequestMessagePublicKey(ServiceName.Connection, Username, - keyFile.HostKey.Name, - keyFile.HostKey.Data); + hostAlgorithm.Name, + hostAlgorithm.Data); - if (KeyFiles.Count < 2) + if (hostAlgorithms.Count == 1) { // If only one key file provided then send signature for very first request var signatureData = new SignatureData(message, session.SessionId).GetBytes(); - message.Signature = keyFile.HostKey.Sign(signatureData); + message.Signature = hostAlgorithm.Sign(signatureData); } // Send public key authentication request @@ -95,12 +98,12 @@ public override AuthenticationResult Authenticate(Session session) var signatureMessage = new RequestMessagePublicKey(ServiceName.Connection, Username, - keyFile.HostKey.Name, - keyFile.HostKey.Data); + hostAlgorithm.Name, + hostAlgorithm.Data); var signatureData = new SignatureData(message, session.SessionId).GetBytes(); - signatureMessage.Signature = keyFile.HostKey.Sign(signatureData); + signatureMessage.Signature = hostAlgorithm.Sign(signatureData); // Send public key authentication request with signature session.SendMessage(signatureMessage); @@ -108,7 +111,7 @@ public override AuthenticationResult Authenticate(Session session) session.WaitOnHandle(_authenticationCompleted); - if (_authenticationResult == AuthenticationResult.Success) + if (_authenticationResult is AuthenticationResult.Success or AuthenticationResult.PartialSuccess) { break; } diff --git a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs index 29b48ffaa..5ea0dacfd 100644 --- a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs +++ b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs @@ -17,7 +17,7 @@ public class PrivateKeyConnectionInfo : ConnectionInfo, IDisposable /// /// Gets the key files used for authentication. /// - public ICollection KeyFiles { get; private set; } + public ICollection KeyFiles { get; private set; } /// /// Initializes a new instance of the class. @@ -41,7 +41,7 @@ public PrivateKeyConnectionInfo(string host, string username, params PrivateKeyF /// Connection port. /// Connection username. /// Connection key files. - public PrivateKeyConnectionInfo(string host, int port, string username, params IPrivateKeySource[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) : this(host, port, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty, keyFiles) { } @@ -56,7 +56,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, params I /// The proxy host. /// The proxy port. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IHostAlgorithmsProvider[] keyFiles) : this(host, port, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles) { } @@ -72,7 +72,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp /// The proxy port. /// The proxy username. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IHostAlgorithmsProvider[] keyFiles) : this(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles) { } @@ -86,7 +86,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp /// The proxy host. /// The proxy port. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IHostAlgorithmsProvider[] keyFiles) : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles) { } @@ -101,7 +101,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy port. /// The proxy username. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IHostAlgorithmsProvider[] keyFiles) : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles) { } @@ -117,7 +117,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy username. /// The proxy password. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IHostAlgorithmsProvider[] keyFiles) : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, keyFiles) { } @@ -134,10 +134,10 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy username. /// The proxy password. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IHostAlgorithmsProvider[] keyFiles) : base(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, new PrivateKeyAuthenticationMethod(username, keyFiles)) { - KeyFiles = new Collection(keyFiles); + KeyFiles = new Collection(keyFiles); } /// diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 3a2dbe049..ebd50fa42 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -1,7 +1,9 @@ 锘縰sing System; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.IO; +using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; @@ -63,18 +65,48 @@ namespace Renci.SshNet /// /// /// - public class PrivateKeyFile : IPrivateKeySource, IDisposable + public class PrivateKeyFile : IHostAlgorithmsProvider, +#pragma warning disable CS0618 // Type or member is obsolete + IPrivateKeySource, +#pragma warning restore CS0618 // Type or member is obsolete + IDisposable { private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?[A-Z0-9-]+),(?[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?([a-zA-Z0-9/+=]{1,80}\r?\n)+)-+ *END \k PRIVATE KEY *-+", RegexOptions.Compiled | RegexOptions.Multiline); + private readonly List _hostAlgorithms = new List(); private Key _key; private bool _isDisposed; /// /// Gets the host key. /// - public HostAlgorithm HostKey { get; private set; } + /// + /// This property returns the first item in . + /// + public HostAlgorithm HostKey + { + get + { + return _hostAlgorithms[0]; + } + private set + { + Debug.Assert(_hostAlgorithms.Count == 0, $"Only expected to set {nameof(HostKey)} at most once."); + _hostAlgorithms.Add(value); + } + } + + /// + /// The supported host algorithms for this key file. + /// + public IReadOnlyCollection HostAlgorithms + { + get + { + return _hostAlgorithms; + } + } /// /// Initializes a new instance of the class. @@ -92,6 +124,7 @@ public PrivateKeyFile(Key key) public PrivateKeyFile(Stream privateKey) { Open(privateKey, passPhrase: null); + Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKey)} is not set."); } /// @@ -127,6 +160,8 @@ public PrivateKeyFile(string fileName, string passPhrase) { Open(keyFile, passPhrase); } + + Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKey)} is not set."); } /// @@ -138,6 +173,7 @@ public PrivateKeyFile(string fileName, string passPhrase) public PrivateKeyFile(Stream privateKey, string passPhrase) { Open(privateKey, passPhrase); + Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKey)} is not set."); } /// @@ -222,8 +258,11 @@ private void Open(Stream privateKey, string passPhrase) switch (keyName) { case "RSA": - _key = new RsaKey(decryptedData); - HostKey = new KeyHostAlgorithm("ssh-rsa", _key); + var rsaKey = new RsaKey(decryptedData); + _key = rsaKey; + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA512))); + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA256))); + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); break; case "DSA": _key = new DsaKey(decryptedData); @@ -235,7 +274,17 @@ private void Open(Stream privateKey, string passPhrase) break; case "OPENSSH": _key = ParseOpenSshV1Key(decryptedData, passPhrase); - HostKey = new KeyHostAlgorithm(_key.ToString(), _key); + if (_key is RsaKey parsedRsaKey) + { + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA512))); + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA256))); + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); + } + else + { + HostKey = new KeyHostAlgorithm(_key.ToString(), _key); + } + break; case "SSH2 ENCRYPTED": var reader = new SshDataReader(decryptedData); @@ -290,8 +339,11 @@ private void Open(Stream privateKey, string passPhrase) var inverseQ = reader.ReadBigIntWithBits(); // u var q = reader.ReadBigIntWithBits(); // p var p = reader.ReadBigIntWithBits(); // q - _key = new RsaKey(modulus, exponent, d, p, q, inverseQ); - HostKey = new KeyHostAlgorithm("ssh-rsa", _key); + var decryptedRsaKey = new RsaKey(modulus, exponent, d, p, q, inverseQ); + _key = decryptedRsaKey; + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(decryptedRsaKey, HashAlgorithmName.SHA512))); + _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(decryptedRsaKey, HashAlgorithmName.SHA256))); + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); } else if (keyType == "dl-modp{sign{dsa-nist-sha1},dh{plain}}") { diff --git a/src/Renci.SshNet/ScpClient.cs b/src/Renci.SshNet/ScpClient.cs index 177a83bb5..fc12413de 100644 --- a/src/Renci.SshNet/ScpClient.cs +++ b/src/Renci.SshNet/ScpClient.cs @@ -146,7 +146,7 @@ public ScpClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public ScpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) + public ScpClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -159,7 +159,7 @@ public ScpClient(string host, int port, string username, params IPrivateKeySourc /// Authentication private key file(s) . /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public ScpClient(string host, string username, params IPrivateKeySource[] keyFiles) + public ScpClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs index fda7fc5b5..749083c03 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs @@ -8,8 +8,6 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers /// public class RsaCipher : AsymmetricCipher { - private readonly bool _isPrivate; - private readonly RsaKey _key; /// @@ -24,7 +22,6 @@ public RsaCipher(RsaKey key) } _key = key; - _isPrivate = !_key.D.IsZero; } /// @@ -116,7 +113,9 @@ private byte[] Transform(byte[] data, int offset, int length) BigInteger result; - if (_isPrivate) + var isPrivate = !_key.D.IsZero; + + if (isPrivate) { var random = BigInteger.One; var max = _key.Modulus - 1; diff --git a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs index d9664bdd9..1c239aebe 100644 --- a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs @@ -84,7 +84,7 @@ public override int KeyLength /// /// Gets the digital signature. /// - protected override DigitalSignature DigitalSignature + protected internal override DigitalSignature DigitalSignature { get { diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs index 99892fa59..84dc61178 100644 --- a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs @@ -62,7 +62,7 @@ public override int KeyLength /// /// Gets the digital signature. /// - protected override DigitalSignature DigitalSignature + protected internal override DigitalSignature DigitalSignature { get { diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs index 0958ef0ce..f6bd50bd0 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -128,7 +128,7 @@ public override int KeyLength /// /// Gets the digital signature. /// - protected override DigitalSignature DigitalSignature + protected internal override DigitalSignature DigitalSignature { get { diff --git a/src/Renci.SshNet/Security/Cryptography/Key.cs b/src/Renci.SshNet/Security/Cryptography/Key.cs index e23673b1e..fcc01efbc 100644 --- a/src/Renci.SshNet/Security/Cryptography/Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/Key.cs @@ -17,9 +17,9 @@ public abstract class Key protected BigInteger[] _privateKey; /// - /// Gets the key specific digital signature. + /// Gets the default digital signature implementation for this key. /// - protected abstract DigitalSignature DigitalSignature { get; } + protected internal abstract DigitalSignature DigitalSignature { get; } /// /// Gets or sets the public key. diff --git a/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs index 9af398b46..790a0da64 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs @@ -1,6 +1,5 @@ 锘縰sing System; using System.Security.Cryptography; -using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Security.Cryptography.Ciphers; @@ -14,13 +13,23 @@ public class RsaDigitalSignature : CipherDigitalSignature, IDisposable private HashAlgorithm _hash; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class with the SHA-1 hash algorithm. /// /// The RSA key. public RsaDigitalSignature(RsaKey rsaKey) - : base(new ObjectIdentifier(1, 3, 14, 3, 2, 26), new RsaCipher(rsaKey)) + : this(rsaKey, HashAlgorithmName.SHA1) + { } + + /// + /// Initializes a new instance of the class. + /// + /// The RSA key. + /// The hash algorithm to use in the digital signature. + public RsaDigitalSignature(RsaKey rsaKey, HashAlgorithmName hashAlgorithmName) + : base(ObjectIdentifier.FromHashAlgorithmName(hashAlgorithmName), new RsaCipher(rsaKey)) { - _hash = CryptoAbstraction.CreateSHA1(); + _hash = CryptoConfig.CreateFromName(hashAlgorithmName.Name) as HashAlgorithm + ?? throw new ArgumentException($"Could not create {nameof(HashAlgorithm)} from `{hashAlgorithmName}`.", nameof(hashAlgorithmName)); } /// diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs index dbb5ebb02..7b088ea6e 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs @@ -153,10 +153,14 @@ public override int KeyLength } private RsaDigitalSignature _digitalSignature; + /// - /// Gets the digital signature. + /// /// - protected override DigitalSignature DigitalSignature + /// + /// 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/Security/KeyExchange.cs b/src/Renci.SshNet/Security/KeyExchange.cs index 771ac6bf4..96a912b66 100644 --- a/src/Renci.SshNet/Security/KeyExchange.cs +++ b/src/Renci.SshNet/Security/KeyExchange.cs @@ -318,6 +318,28 @@ protected bool CanTrustHostKey(KeyHostAlgorithm host) /// true if exchange hash is valid; otherwise false. protected abstract bool ValidateExchangeHash(); + private protected bool ValidateExchangeHash(byte[] encodedKey, byte[] encodedSignature) + { + var exchangeHash = CalculateHash(); + + var signatureData = new KeyHostAlgorithm.SignatureKeyData(); + signatureData.Load(encodedSignature); + + var keyAlgorithm = Session.ConnectionInfo.HostKeyAlgorithms[signatureData.AlgorithmName](encodedKey); + + Session.ConnectionInfo.CurrentHostKeyAlgorithm = signatureData.AlgorithmName; + + if (CanTrustHostKey(keyAlgorithm)) + { + // keyAlgorithm.VerifySignature decodes the signature data before verifying. + // But as we have already decoded the data to find the signature algorithm, + // we just verify the decoded data directly through the DigitalSignature. + return keyAlgorithm.DigitalSignature.Verify(exchangeHash, signatureData.Signature); + } + + return false; + } + /// /// Calculates key exchange hash value. /// diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs index 836c607f3..5cdba5b4d 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs @@ -1,5 +1,4 @@ 锘縰sing System; -using System.Text; using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; @@ -72,20 +71,7 @@ internal abstract class KeyExchangeDiffieHellman : KeyExchange /// protected override bool ValidateExchangeHash() { - var exchangeHash = CalculateHash(); - - var length = Pack.BigEndianToUInt32(_hostKey); - var algorithmName = Encoding.UTF8.GetString(_hostKey, 4, (int)length); - var key = Session.ConnectionInfo.HostKeyAlgorithms[algorithmName](_hostKey); - - Session.ConnectionInfo.CurrentHostKeyAlgorithm = algorithmName; - - if (CanTrustHostKey(key)) - { - return key.VerifySignature(exchangeHash, _signature); - } - - return false; + return ValidateExchangeHash(_hostKey, _signature); } /// diff --git a/src/Renci.SshNet/Security/KeyExchangeEC.cs b/src/Renci.SshNet/Security/KeyExchangeEC.cs index 864f55d2f..f2ae22fb7 100644 --- a/src/Renci.SshNet/Security/KeyExchangeEC.cs +++ b/src/Renci.SshNet/Security/KeyExchangeEC.cs @@ -1,7 +1,4 @@ -锘縰sing System.Text; - -using Renci.SshNet.Common; -using Renci.SshNet.Messages.Transport; +锘縰sing Renci.SshNet.Messages.Transport; namespace Renci.SshNet.Security { @@ -76,20 +73,7 @@ protected override byte[] CalculateHash() /// protected override bool ValidateExchangeHash() { - var exchangeHash = CalculateHash(); - - var length = Pack.BigEndianToUInt32(_hostKey); - var algorithmName = Encoding.UTF8.GetString(_hostKey, 4, (int)length); - var key = Session.ConnectionInfo.HostKeyAlgorithms[algorithmName](_hostKey); - - Session.ConnectionInfo.CurrentHostKeyAlgorithm = algorithmName; - - if (CanTrustHostKey(key)) - { - return key.VerifySignature(exchangeHash, _signature); - } - - return false; + return ValidateExchangeHash(_hostKey, _signature); } /// diff --git a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs index aad8e20c1..f0d2b41d8 100644 --- a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs +++ b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs @@ -1,6 +1,9 @@ 锘縰sing System.Collections.Generic; +using System.Text; + using Renci.SshNet.Common; using Renci.SshNet.Security.Chaos.NaCl; +using Renci.SshNet.Security.Cryptography; namespace Renci.SshNet.Security { @@ -10,38 +13,76 @@ namespace Renci.SshNet.Security public class KeyHostAlgorithm : HostAlgorithm { /// - /// Gets the key. + /// The key used in this host key algorithm. /// public Key Key { get; private set; } /// - /// Gets the public key data. + /// The signature implementation used in this host key algorithm. + /// + public DigitalSignature DigitalSignature { get; private set; } + + /// + /// Gets the encoded public key data. /// public override byte[] Data { get { - return new SshKeyData(Name, Key.Public).GetBytes(); + var keyFormatIdentifier = Key is RsaKey ? "ssh-rsa" : Name; + return new SshKeyData(keyFormatIdentifier, Key.Public).GetBytes(); } } /// /// Initializes a new instance of the class. /// - /// Host key name. - /// Host key. + /// The signature format identifier. + /// + /// + /// This constructor is typically passed a private key in order to create an encoded signature for later + /// verification by the host. + /// public KeyHostAlgorithm(string name, Key key) : base(name) { Key = key; + DigitalSignature = key.DigitalSignature; } /// /// Initializes a new instance of the class. /// - /// Host key name. - /// Host key. + /// The signature format identifier. + /// + /// + /// + /// + /// This constructor is typically passed a private key in order to create an encoded signature for later + /// verification by the host. + /// + /// The key used by is intended to be equal to . + /// This is not verified. + /// + public KeyHostAlgorithm(string name, Key key, DigitalSignature digitalSignature) + : base(name) + { + Key = key; + DigitalSignature = digitalSignature; + } + + /// + /// Initializes a new instance of the class + /// with the given encoded public key data. The data will be decoded into . + /// + /// The signature format identifier. + /// /// Host key encoded data. + /// + /// This constructor is typically passed a new or reusable instance in + /// order to verify an encoded signature sent by the host, created by the private counterpart + /// to the host's public key, which is encoded in . + /// public KeyHostAlgorithm(string name, Key key, byte[] data) : base(name) { @@ -50,34 +91,66 @@ public KeyHostAlgorithm(string name, Key key, byte[] data) var sshKey = new SshKeyData(); sshKey.Load(data); Key.Public = sshKey.Keys; + + DigitalSignature = key.DigitalSignature; } /// - /// Signs the specified data. + /// Initializes a new instance of the class + /// with the given encoded public key data. The data will be decoded into . /// - /// The data. + /// The signature format identifier. + /// + /// Host key encoded data. + /// + /// + /// + /// This constructor is typically passed a new or reusable instance in + /// order to verify an encoded signature sent by the host, created by the private counterpart + /// to the host's public key, which is encoded in . + /// + /// The key used by is intended to be equal to . + /// This is not verified. + /// + public KeyHostAlgorithm(string name, Key key, byte[] data, DigitalSignature digitalSignature) + : base(name) + { + Key = key; + + var sshKey = new SshKeyData(); + sshKey.Load(data); + Key.Public = sshKey.Keys; + + DigitalSignature = digitalSignature; + } + + /// + /// Signs and encodes the specified data. + /// + /// The data to be signed. /// - /// Signed data. + /// The encoded signature. /// public override byte[] Sign(byte[] data) { - return new SignatureKeyData(Name, Key.Sign(data)).GetBytes(); + return new SignatureKeyData(Name, DigitalSignature.Sign(data)).GetBytes(); } /// /// Verifies the signature. /// - /// The data. - /// The signature. + /// The data to verify the signature against. + /// The encoded signature data. /// - /// True is signature was successfully verifies; otherwise false. + /// if is the result of signing + /// with the corresponding private key to . /// public override bool VerifySignature(byte[] data, byte[] signature) { var signatureData = new SignatureKeyData(); signatureData.Load(signature); - return Key.VerifySignature(data, signatureData.Signature); + return DigitalSignature.Verify(data, signatureData.Signature); } private sealed class SshKeyData : SshData @@ -170,15 +243,12 @@ protected override void SaveData() } } - private sealed class SignatureKeyData : SshData + internal sealed class SignatureKeyData : SshData { /// - /// Gets or sets the name of the algorithm as UTF-8 encoded byte array. + /// Gets or sets the signature format identifier /// - /// - /// The name of the algorithm. - /// - private byte[] AlgorithmName { get; set; } + public string AlgorithmName { get; set; } /// /// Gets the signature. @@ -200,7 +270,7 @@ protected override int BufferCapacity { var capacity = base.BufferCapacity; capacity += 4; // AlgorithmName length - capacity += AlgorithmName.Length; // AlgorithmName + capacity += Encoding.UTF8.GetByteCount(AlgorithmName); // AlgorithmName capacity += 4; // Signature length capacity += Signature.Length; // Signature return capacity; @@ -213,7 +283,7 @@ public SignatureKeyData() public SignatureKeyData(string name, byte[] signature) { - AlgorithmName = Utf8.GetBytes(name); + AlgorithmName = name; Signature = signature; } @@ -222,7 +292,7 @@ public SignatureKeyData(string name, byte[] signature) /// protected override void LoadData() { - AlgorithmName = ReadBinary(); + AlgorithmName = Encoding.UTF8.GetString(ReadBinary()); Signature = ReadBinary(); } @@ -231,7 +301,7 @@ protected override void LoadData() /// protected override void SaveData() { - WriteBinaryString(AlgorithmName); + WriteBinaryString(Encoding.UTF8.GetBytes(AlgorithmName)); WriteBinaryString(Signature); } } diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index e6f9cb2d6..b5f757b96 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -218,7 +218,7 @@ public SftpClient(string host, string username, string password) /// is invalid. -or- is nunullll or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public SftpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) + public SftpClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -231,7 +231,7 @@ public SftpClient(string host, int port, string username, params IPrivateKeySour /// Authentication private key file(s) . /// is null. /// is invalid. -or- is null or contains only whitespace characters. - public SftpClient(string host, string username, params IPrivateKeySource[] keyFiles) + public SftpClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } diff --git a/src/Renci.SshNet/SshClient.cs b/src/Renci.SshNet/SshClient.cs index fb8bb37f0..e596caaa0 100644 --- a/src/Renci.SshNet/SshClient.cs +++ b/src/Renci.SshNet/SshClient.cs @@ -103,7 +103,7 @@ public SshClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public SshClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) + public SshClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -120,7 +120,7 @@ public SshClient(string host, int port, string username, params IPrivateKeySourc /// /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public SshClient(string host, string username, params IPrivateKeySource[] keyFiles) + public SshClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } From 18e667303195a91d6e934104197396bd06b36069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Sat, 23 Sep 2023 08:33:10 +0200 Subject: [PATCH 38/96] Improvements after #1177 (#1180) --- .../Ciphers/RsaCipherBenchmarks.cs | 3 +- .../ED25519DigitalSignatureBenchmarks.cs | 2 +- ...Test_Connect_OnConnectedThrowsException.cs | 3 +- .../Classes/Common/HostKeyEventArgsTest.cs | 2 +- ...st_Connect_NetConfSessionConnectFailure.cs | 3 +- .../Classes/PrivateKeyFileTest.cs | 21 ++++----- .../Cryptography/RsaDigitalSignatureTest.cs | 2 +- .../Classes/Security/KeyAlgorithmTest.cs | 4 +- ...tTest_Connect_SftpSessionConnectFailure.cs | 3 +- src/Renci.SshNet/IHostAlgorithmsProvider.cs | 21 --------- src/Renci.SshNet/IPrivateKeySource.cs | 21 ++++----- src/Renci.SshNet/NetConfClient.cs | 4 +- .../PrivateKeyAuthenticationMethod.cs | 8 ++-- src/Renci.SshNet/PrivateKeyConnectionInfo.cs | 18 ++++---- src/Renci.SshNet/PrivateKeyFile.cs | 45 +++++++------------ src/Renci.SshNet/ScpClient.cs | 4 +- src/Renci.SshNet/SftpClient.cs | 4 +- src/Renci.SshNet/SshClient.cs | 4 +- 18 files changed, 68 insertions(+), 104 deletions(-) delete mode 100644 src/Renci.SshNet/IHostAlgorithmsProvider.cs diff --git a/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs b/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs index f25e6db71..13c08edb1 100644 --- a/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs +++ b/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs @@ -21,7 +21,8 @@ public RsaCipherBenchmarks() using (var s = typeof(RsaCipherBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.RSA.txt")) { - _privateKey = (RsaKey)((KeyHostAlgorithm) new PrivateKeyFile(s).HostKey).Key; + + _privateKey = (RsaKey)new PrivateKeyFile(s).Key; // The implementations of RsaCipher.Encrypt/Decrypt differ based on whether the supplied RsaKey has private key information // or only public. So we extract out the public key information to a separate variable. diff --git a/src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs b/src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs index 2f07a2d3a..44b2da8a6 100644 --- a/src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs +++ b/src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs @@ -21,7 +21,7 @@ public ED25519DigitalSignatureBenchmarks() using (var s = typeof(ED25519DigitalSignatureBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.OPENSSH.ED25519.txt")) { - _key = (ED25519Key) ((KeyHostAlgorithm) new PrivateKeyFile(s).HostKey).Key; + _key = (ED25519Key) new PrivateKeyFile(s).Key; } _signature = new ED25519DigitalSignature(_key).Sign(_data); } diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs index f2a30bbe2..806f6c30a 100644 --- a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs +++ b/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs @@ -1,4 +1,5 @@ 锘縰sing System; +using System.Linq; using System.Reflection; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -140,7 +141,7 @@ private static KeyHostAlgorithm GetKeyHostAlgorithm() using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) { var privateKey = new PrivateKeyFile(s); - return (KeyHostAlgorithm) privateKey.HostKey; + return (KeyHostAlgorithm) privateKey.HostKeyAlgorithms.First(); } } diff --git a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs index e7ee53b90..28001655a 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs @@ -89,7 +89,7 @@ private static KeyHostAlgorithm GetKeyHostAlgorithm() using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) { var privateKey = new PrivateKeyFile(s); - return (KeyHostAlgorithm)privateKey.HostKey; + return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First(); } } diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs index 88410acc1..41c285a84 100644 --- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs +++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs @@ -1,4 +1,5 @@ 锘縰sing System; +using System.Linq; using System.Reflection; using System.Threading; @@ -113,7 +114,7 @@ private static KeyHostAlgorithm GetKeyHostAlgorithm() using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) { var privateKey = new PrivateKeyFile(s); - return (KeyHostAlgorithm)privateKey.HostKey; + return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First(); } } } diff --git a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index c684f0be7..879dfa840 100644 --- a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs @@ -1,9 +1,7 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; -using Renci.SshNet.Security; using Renci.SshNet.Tests.Common; using System; -using System.Collections.Generic; using System.IO; using System.Linq; @@ -412,7 +410,7 @@ public void ConstructorWithStreamAndPassphrase() using (var stream = GetData("Key.RSA.Encrypted.Aes.128.CBC.12345.txt")) { var privateKeyFile = new PrivateKeyFile(stream, "12345"); - Assert.IsNotNull(privateKeyFile.HostKey); + TestRsaKeyFile(privateKeyFile); } } @@ -430,7 +428,7 @@ public void ConstructorWithFileNameAndPassphrase() using (var fs = File.Open(_temporaryFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { var privateKeyFile = new PrivateKeyFile(_temporaryFile, "12345"); - Assert.IsNotNull(privateKeyFile.HostKey); + TestRsaKeyFile(privateKeyFile); fs.Close(); } @@ -498,7 +496,7 @@ public void ConstructorWithFileName() } var privateKeyFile = new PrivateKeyFile(_temporaryFile, "12345"); - Assert.IsNotNull(privateKeyFile.HostKey); + TestRsaKeyFile(privateKeyFile); } /// @@ -510,7 +508,7 @@ public void ConstructorWithStream() using (var stream = GetData("Key.RSA.txt")) { var privateKeyFile = new PrivateKeyFile(stream); - Assert.IsNotNull(privateKeyFile.HostKey); + TestRsaKeyFile(privateKeyFile); } } @@ -526,7 +524,7 @@ public void ConstructorWithFileNameShouldBeAbleToReadFileThatIsSharedForReadAcce using (var fs = File.Open(_temporaryFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { var privateKeyFile = new PrivateKeyFile(_temporaryFile); - Assert.IsNotNull(privateKeyFile.HostKey); + TestRsaKeyFile(privateKeyFile); fs.Close(); } @@ -544,7 +542,7 @@ public void ConstructorWithFileNameAndPassPhraseShouldBeAbleToReadFileThatIsShar using (var fs = File.Open(_temporaryFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { var privateKeyFile = new PrivateKeyFile(_temporaryFile, "12345"); - Assert.IsNotNull(privateKeyFile.HostKey); + TestRsaKeyFile(privateKeyFile); fs.Close(); } @@ -684,15 +682,14 @@ private string GetTempFileName() private static void TestRsaKeyFile(PrivateKeyFile rsaPrivateKeyFile) { - Assert.AreEqual(3, rsaPrivateKeyFile.HostAlgorithms.Count); + Assert.IsNotNull(rsaPrivateKeyFile.HostKeyAlgorithms); + Assert.AreEqual(3, rsaPrivateKeyFile.HostKeyAlgorithms.Count); - List algorithms = rsaPrivateKeyFile.HostAlgorithms.Cast().ToList(); + var algorithms = rsaPrivateKeyFile.HostKeyAlgorithms.ToList(); Assert.AreEqual("rsa-sha2-512", algorithms[0].Name); Assert.AreEqual("rsa-sha2-256", algorithms[1].Name); Assert.AreEqual("ssh-rsa", algorithms[2].Name); - - Assert.AreSame(algorithms[0], rsaPrivateKeyFile.HostKey); } } } diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs index 0c5c7eb02..4691fef27 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs @@ -164,7 +164,7 @@ private static RsaKey GetRsaKey() { using (var stream = GetData("Key.RSA.txt")) { - return (RsaKey) ((KeyHostAlgorithm) new PrivateKeyFile(stream).HostKey).Key; + return (RsaKey) new PrivateKeyFile(stream).Key; } } diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs index 6f92362b4..d024c05a6 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs @@ -1,4 +1,4 @@ -锘縰sing System.Security.Cryptography; +锘匡豢using System.Security.Cryptography; using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -176,7 +176,7 @@ private static RsaKey GetRsaKey() { using (var stream = GetData("Key.RSA.txt")) { - return (RsaKey) ((KeyHostAlgorithm) new PrivateKeyFile(stream).HostKey).Key; + return (RsaKey) new PrivateKeyFile(stream).Key; } } diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs index 6f9650487..80c050a82 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs @@ -1,4 +1,5 @@ 锘縰sing System; +using System.Linq; using System.Reflection; using System.Threading; @@ -122,7 +123,7 @@ private static KeyHostAlgorithm GetKeyHostAlgorithm() using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) { var privateKey = new PrivateKeyFile(s); - return (KeyHostAlgorithm)privateKey.HostKey; + return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First(); } } } diff --git a/src/Renci.SshNet/IHostAlgorithmsProvider.cs b/src/Renci.SshNet/IHostAlgorithmsProvider.cs deleted file mode 100644 index 89ac27128..000000000 --- a/src/Renci.SshNet/IHostAlgorithmsProvider.cs +++ /dev/null @@ -1,21 +0,0 @@ -锘縰sing System.Collections.Generic; - -using Renci.SshNet.Security; - -namespace Renci.SshNet -{ - /// - /// Represents a collection of host algorithms. - /// - public interface IHostAlgorithmsProvider - { - /// - /// The host algorithms provided by this . - /// - /// - /// In situations where there is a preferred order of usage of the host algorithms, - /// the collection should be ordered from most preferred to least. - /// - IReadOnlyCollection HostAlgorithms { get; } - } -} diff --git a/src/Renci.SshNet/IPrivateKeySource.cs b/src/Renci.SshNet/IPrivateKeySource.cs index 466a36d2a..96ab4574f 100644 --- a/src/Renci.SshNet/IPrivateKeySource.cs +++ b/src/Renci.SshNet/IPrivateKeySource.cs @@ -1,5 +1,4 @@ -锘縰sing System; -using System.ComponentModel; +using System.Collections.Generic; using Renci.SshNet.Security; @@ -8,19 +7,15 @@ namespace Renci.SshNet /// /// Represents private key source interface. /// - /// - /// This interface has been replaced by - /// and is obsolete. - /// - [Obsolete($"Use {nameof(IHostAlgorithmsProvider)} instead. " + - $"{nameof(IPrivateKeySource)} may be removed in a future release. " + - $"See https://github.com/sshnet/SSH.NET/issues/1174 for details.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public interface IPrivateKeySource : IHostAlgorithmsProvider + public interface IPrivateKeySource { /// - /// Gets the host key. + /// Gets the host keys algorithms. /// - HostAlgorithm HostKey { get; } + /// + /// In situations where there is a preferred order of usage of the host algorithms, + /// the collection should be ordered from most preferred to least. + /// + IReadOnlyCollection HostKeyAlgorithms { get; } } } diff --git a/src/Renci.SshNet/NetConfClient.cs b/src/Renci.SshNet/NetConfClient.cs index 95cc99f7d..bbedca3c2 100644 --- a/src/Renci.SshNet/NetConfClient.cs +++ b/src/Renci.SshNet/NetConfClient.cs @@ -107,7 +107,7 @@ public NetConfClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public NetConfClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) + public NetConfClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -120,7 +120,7 @@ public NetConfClient(string host, int port, string username, params IHostAlgorit /// Authentication private key file(s) . /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public NetConfClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles) + public NetConfClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } diff --git a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs index cb82cd7ac..224f8d295 100644 --- a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs +++ b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs @@ -31,7 +31,7 @@ public override string Name /// /// Gets the key files used for authentication. /// - public ICollection KeyFiles { get; private set; } + public ICollection KeyFiles { get; private set; } /// /// Initializes a new instance of the class. @@ -39,7 +39,7 @@ public override string Name /// The username. /// The key files. /// is whitespace or null. - public PrivateKeyAuthenticationMethod(string username, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyAuthenticationMethod(string username, params IPrivateKeySource[] keyFiles) : base(username) { if (keyFiles is null) @@ -47,7 +47,7 @@ public PrivateKeyAuthenticationMethod(string username, params IHostAlgorithmsPro throw new ArgumentNullException(nameof(keyFiles)); } - KeyFiles = new Collection(keyFiles); + KeyFiles = new Collection(keyFiles); } /// @@ -65,7 +65,7 @@ public override AuthenticationResult Authenticate(Session session) session.RegisterMessage("SSH_MSG_USERAUTH_PK_OK"); - var hostAlgorithms = KeyFiles.SelectMany(x => x.HostAlgorithms).ToList(); + var hostAlgorithms = KeyFiles.SelectMany(x => x.HostKeyAlgorithms).ToList(); try { diff --git a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs index 5ea0dacfd..29b48ffaa 100644 --- a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs +++ b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs @@ -17,7 +17,7 @@ public class PrivateKeyConnectionInfo : ConnectionInfo, IDisposable /// /// Gets the key files used for authentication. /// - public ICollection KeyFiles { get; private set; } + public ICollection KeyFiles { get; private set; } /// /// Initializes a new instance of the class. @@ -41,7 +41,7 @@ public PrivateKeyConnectionInfo(string host, string username, params PrivateKeyF /// Connection port. /// Connection username. /// Connection key files. - public PrivateKeyConnectionInfo(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(host, port, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty, keyFiles) { } @@ -56,7 +56,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, params I /// The proxy host. /// The proxy port. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles) : this(host, port, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles) { } @@ -72,7 +72,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp /// The proxy port. /// The proxy username. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles) : this(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles) { } @@ -86,7 +86,7 @@ public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTyp /// The proxy host. /// The proxy port. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, params IPrivateKeySource[] keyFiles) : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, string.Empty, string.Empty, keyFiles) { } @@ -101,7 +101,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy port. /// The proxy username. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, params IPrivateKeySource[] keyFiles) : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, proxyUsername, string.Empty, keyFiles) { } @@ -117,7 +117,7 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy username. /// The proxy password. /// The key files. - public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles) : this(host, DefaultPort, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, keyFiles) { } @@ -134,10 +134,10 @@ public PrivateKeyConnectionInfo(string host, string username, ProxyTypes proxyTy /// The proxy username. /// The proxy password. /// The key files. - public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IHostAlgorithmsProvider[] keyFiles) + public PrivateKeyConnectionInfo(string host, int port, string username, ProxyTypes proxyType, string proxyHost, int proxyPort, string proxyUsername, string proxyPassword, params IPrivateKeySource[] keyFiles) : base(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, new PrivateKeyAuthenticationMethod(username, keyFiles)) { - KeyFiles = new Collection(keyFiles); + KeyFiles = new Collection(keyFiles); } /// diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index ebd50fa42..6dc8d4274 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -65,11 +65,7 @@ namespace Renci.SshNet /// /// /// - public class PrivateKeyFile : IHostAlgorithmsProvider, -#pragma warning disable CS0618 // Type or member is obsolete - IPrivateKeySource, -#pragma warning restore CS0618 // Type or member is obsolete - IDisposable + public class PrivateKeyFile : IPrivateKeySource, IDisposable { private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?[A-Z0-9-]+),(?[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?([a-zA-Z0-9/+=]{1,80}\r?\n)+)-+ *END \k PRIVATE KEY *-+", RegexOptions.Compiled | RegexOptions.Multiline); @@ -79,32 +75,24 @@ public class PrivateKeyFile : IHostAlgorithmsProvider, private bool _isDisposed; /// - /// Gets the host key. + /// The supported host algorithms for this key file. /// - /// - /// This property returns the first item in . - /// - public HostAlgorithm HostKey + public IReadOnlyCollection HostKeyAlgorithms { get { - return _hostAlgorithms[0]; - } - private set - { - Debug.Assert(_hostAlgorithms.Count == 0, $"Only expected to set {nameof(HostKey)} at most once."); - _hostAlgorithms.Add(value); + return _hostAlgorithms; } } /// - /// The supported host algorithms for this key file. + /// Gets the key. /// - public IReadOnlyCollection HostAlgorithms + public Key Key { get { - return _hostAlgorithms; + return _key; } } @@ -114,7 +102,8 @@ public IReadOnlyCollection HostAlgorithms /// The key. public PrivateKeyFile(Key key) { - HostKey = new KeyHostAlgorithm(key.ToString(), key); + _key = key; + _hostAlgorithms.Add(new KeyHostAlgorithm(key.ToString(), key)); } /// @@ -124,7 +113,7 @@ public PrivateKeyFile(Key key) public PrivateKeyFile(Stream privateKey) { Open(privateKey, passPhrase: null); - Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKey)} is not set."); + Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKeyAlgorithms)} is not set."); } /// @@ -161,7 +150,7 @@ public PrivateKeyFile(string fileName, string passPhrase) Open(keyFile, passPhrase); } - Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKey)} is not set."); + Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKeyAlgorithms)} is not set."); } /// @@ -173,7 +162,8 @@ public PrivateKeyFile(string fileName, string passPhrase) public PrivateKeyFile(Stream privateKey, string passPhrase) { Open(privateKey, passPhrase); - Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKey)} is not set."); + + Debug.Assert(_hostAlgorithms.Count > 0, $"{nameof(HostKeyAlgorithms)} is not set."); } /// @@ -266,11 +256,11 @@ private void Open(Stream privateKey, string passPhrase) break; case "DSA": _key = new DsaKey(decryptedData); - HostKey = new KeyHostAlgorithm("ssh-dss", _key); + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key)); break; case "EC": _key = new EcdsaKey(decryptedData); - HostKey = new KeyHostAlgorithm(_key.ToString(), _key); + _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); break; case "OPENSSH": _key = ParseOpenSshV1Key(decryptedData, passPhrase); @@ -282,9 +272,8 @@ private void Open(Stream privateKey, string passPhrase) } else { - HostKey = new KeyHostAlgorithm(_key.ToString(), _key); + _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); } - break; case "SSH2 ENCRYPTED": var reader = new SshDataReader(decryptedData); @@ -358,7 +347,7 @@ private void Open(Stream privateKey, string passPhrase) var y = reader.ReadBigIntWithBits(); var x = reader.ReadBigIntWithBits(); _key = new DsaKey(p, q, g, y, x); - HostKey = new KeyHostAlgorithm("ssh-dss", _key); + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-dss", _key)); } else { diff --git a/src/Renci.SshNet/ScpClient.cs b/src/Renci.SshNet/ScpClient.cs index fc12413de..177a83bb5 100644 --- a/src/Renci.SshNet/ScpClient.cs +++ b/src/Renci.SshNet/ScpClient.cs @@ -146,7 +146,7 @@ public ScpClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public ScpClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) + public ScpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -159,7 +159,7 @@ public ScpClient(string host, int port, string username, params IHostAlgorithmsP /// Authentication private key file(s) . /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public ScpClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles) + public ScpClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index b5f757b96..e6f9cb2d6 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -218,7 +218,7 @@ public SftpClient(string host, string username, string password) /// is invalid. -or- is nunullll or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public SftpClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) + public SftpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -231,7 +231,7 @@ public SftpClient(string host, int port, string username, params IHostAlgorithms /// Authentication private key file(s) . /// is null. /// is invalid. -or- is null or contains only whitespace characters. - public SftpClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles) + public SftpClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } diff --git a/src/Renci.SshNet/SshClient.cs b/src/Renci.SshNet/SshClient.cs index e596caaa0..fb8bb37f0 100644 --- a/src/Renci.SshNet/SshClient.cs +++ b/src/Renci.SshNet/SshClient.cs @@ -103,7 +103,7 @@ public SshClient(string host, string username, string password) /// is invalid, -or- is null or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] - public SshClient(string host, int port, string username, params IHostAlgorithmsProvider[] keyFiles) + public SshClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) : this(new PrivateKeyConnectionInfo(host, port, username, keyFiles), ownsConnectionInfo: true) { } @@ -120,7 +120,7 @@ public SshClient(string host, int port, string username, params IHostAlgorithmsP /// /// is null. /// is invalid, -or- is null or contains only whitespace characters. - public SshClient(string host, string username, params IHostAlgorithmsProvider[] keyFiles) + public SshClient(string host, string username, params IPrivateKeySource[] keyFiles) : this(host, ConnectionInfo.DefaultPort, username, keyFiles) { } From aade354748153cc534fa8a1e45ddfd0e0a2dc8b9 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Sat, 23 Sep 2023 16:20:59 +0100 Subject: [PATCH 39/96] Use ExceptionDispatchInfo in more places (#1182) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Wojciech Nag贸rski --- .../KeyboardInteractiveAuthenticationMethod.cs | 3 ++- src/Renci.SshNet/PasswordAuthenticationMethod.cs | 3 ++- src/Renci.SshNet/Sftp/SftpFileReader.cs | 5 +++-- src/Renci.SshNet/SshCommand.cs | 4 +++- src/Renci.SshNet/SubsystemSession.cs | 13 +++++++++---- 5 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs b/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs index b559808d1..1e0a743ce 100644 --- a/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs +++ b/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs @@ -1,5 +1,6 @@ 锘縰sing System; using System.Linq; +using System.Runtime.ExceptionServices; using System.Threading; using Renci.SshNet.Abstractions; @@ -78,7 +79,7 @@ public override AuthenticationResult Authenticate(Session session) if (_exception != null) { - throw _exception; + ExceptionDispatchInfo.Capture(_exception).Throw(); } return _authenticationResult; diff --git a/src/Renci.SshNet/PasswordAuthenticationMethod.cs b/src/Renci.SshNet/PasswordAuthenticationMethod.cs index ffa8213d8..bebfd3c47 100644 --- a/src/Renci.SshNet/PasswordAuthenticationMethod.cs +++ b/src/Renci.SshNet/PasswordAuthenticationMethod.cs @@ -1,4 +1,5 @@ 锘縰sing System; +using System.Runtime.ExceptionServices; using System.Text; using System.Threading; @@ -114,7 +115,7 @@ public override AuthenticationResult Authenticate(Session session) if (_exception != null) { - throw _exception; + ExceptionDispatchInfo.Capture(_exception).Throw(); } return _authenticationResult; diff --git a/src/Renci.SshNet/Sftp/SftpFileReader.cs b/src/Renci.SshNet/Sftp/SftpFileReader.cs index 9d44bb330..c28dd8ac5 100644 --- a/src/Renci.SshNet/Sftp/SftpFileReader.cs +++ b/src/Renci.SshNet/Sftp/SftpFileReader.cs @@ -1,6 +1,7 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; +using System.Runtime.ExceptionServices; using System.Threading; using Renci.SshNet.Abstractions; @@ -80,7 +81,7 @@ public byte[] Read() if (_exception is not null) { - throw _exception; + ExceptionDispatchInfo.Capture(_exception).Throw(); } if (_isEndOfFileRead) @@ -102,7 +103,7 @@ public byte[] Read() // throw when exception occured in read-ahead, or the current instance is already disposed if (_exception != null) { - throw _exception; + ExceptionDispatchInfo.Capture(_exception).Throw(); } var data = nextChunk.Data; diff --git a/src/Renci.SshNet/SshCommand.cs b/src/Renci.SshNet/SshCommand.cs index 13c00992a..a4b861cda 100644 --- a/src/Renci.SshNet/SshCommand.cs +++ b/src/Renci.SshNet/SshCommand.cs @@ -1,6 +1,7 @@ 锘縰sing System; using System.Globalization; using System.IO; +using System.Runtime.ExceptionServices; using System.Text; using System.Threading; @@ -483,7 +484,8 @@ private void WaitOnHandle(WaitHandle waitHandle) switch (signaledElement) { case 0: - throw _exception; + ExceptionDispatchInfo.Capture(_exception).Throw(); + break; case 1: // Specified waithandle was signaled break; diff --git a/src/Renci.SshNet/SubsystemSession.cs b/src/Renci.SshNet/SubsystemSession.cs index b89d30fd1..86a081bbf 100644 --- a/src/Renci.SshNet/SubsystemSession.cs +++ b/src/Renci.SshNet/SubsystemSession.cs @@ -1,5 +1,6 @@ 锘縰sing System; using System.Globalization; +using System.Runtime.ExceptionServices; using System.Threading; using Renci.SshNet.Abstractions; @@ -241,7 +242,8 @@ public void WaitOnHandle(WaitHandle waitHandle, int millisecondsTimeout) switch (result) { case 0: - throw _exception; + ExceptionDispatchInfo.Capture(_exception).Throw(); + break; case 1: throw new SshException("Connection was closed by the server."); case 2: @@ -286,7 +288,8 @@ public bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout) switch (result) { case 0: - throw _exception; + ExceptionDispatchInfo.Capture(_exception).Throw(); + return false; // unreached case 1: throw new SshException("Connection was closed by the server."); case 2: @@ -340,7 +343,8 @@ public int WaitAny(WaitHandle waitHandle1, WaitHandle waitHandle2, int milliseco switch (result) { case 0: - throw _exception; + ExceptionDispatchInfo.Capture(_exception).Throw(); + return -1; // unreached case 1: throw new SshException("Connection was closed by the server."); case 2: @@ -377,7 +381,8 @@ public int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout) switch (result) { case 0: - throw _exception; + ExceptionDispatchInfo.Capture(_exception).Throw(); + return -1; // unreached case 1: throw new SshException("Connection was closed by the server."); case 2: From 51e0c67f40aaf4b22d45099b59fd38840a8c4df2 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Mon, 25 Sep 2023 20:35:14 +0100 Subject: [PATCH 40/96] Try to "fix" the flaky test (#1185) --- .../Classes/ForwardedPortRemoteTest_Start_PortStarted.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStarted.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStarted.cs index a75026806..0cd8a6ad7 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStarted.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStarted.cs @@ -139,6 +139,10 @@ public void ForwardedPortShouldAcceptNewConnections() new ForwardedTcpipChannelInfo(_forwardedPort.BoundHost, _forwardedPort.BoundPort, originatorAddress, originatorPort)))); + // CreateChannelForwardedTcpip gets called on a separate thread. + // Sleep on this thread briefly to avoid a race. + Thread.Sleep(500); + _sessionMock.Verify(p => p.CreateChannelForwardedTcpip(channelNumber, initialWindowSize, maximumPacketSize), Times.Once); channelMock.Verify(p => p.Bind(It.Is(ep => ep.Address.Equals(_remoteEndpoint.Address) && ep.Port == _remoteEndpoint.Port), _forwardedPort), Times.Once); channelMock.Verify(p => p.Dispose(), Times.Once); From fdd113022bec2a4fc322841280f21d1881783402 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Mon, 25 Sep 2023 21:22:15 +0100 Subject: [PATCH 41/96] Enable DSA tests (#1181) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Wojciech Nag贸rski --- README.md | 2 ++ .../HostKeyAlgorithmTests.cs | 7 ++----- .../HostKeyFile.cs | 2 +- .../PrivateKeyAuthenticationTests.cs | 5 +---- .../server/ssh/ssh_host_dsa_key | 20 +++++++++++++++++++ .../user/sshnet/authorized_keys | 1 + .../HostKeyAlgorithm.cs | 2 +- 7 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_dsa_key diff --git a/README.md b/README.md index 86d0e309b..9ab4978f2 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,8 @@ Private keys can be encrypted using one of the following cipher methods: * ecdsa-sha2-nistp256 * ecdsa-sha2-nistp384 * ecdsa-sha2-nistp521 +* rsa-sha2-512 +* rsa-sha2-256 * ssh-rsa * ssh-dss diff --git a/src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs b/src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs index 7f177a6f4..d827fb47c 100644 --- a/src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs +++ b/src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs @@ -24,12 +24,9 @@ public void TearDown() } [TestMethod] - [Ignore] // No longer supported in recent versions of OpenSSH - // TODO: We should be able to enable some legacy settings to make it work - // https://www.openssh.com/legacy.html e.g. PubkeyAcceptedKeyTypes / HostbasedAcceptedKeyTypes ? - public void SshDsa() + public void SshDss() { - DoTest(HostKeyAlgorithm.SshDsa, HostKeyFile.Dsa, 1024); + DoTest(HostKeyAlgorithm.SshDss, HostKeyFile.Dsa, 2048); } [TestMethod] diff --git a/src/Renci.SshNet.IntegrationTests/HostKeyFile.cs b/src/Renci.SshNet.IntegrationTests/HostKeyFile.cs index 01cf957f5..66d09fd29 100644 --- a/src/Renci.SshNet.IntegrationTests/HostKeyFile.cs +++ b/src/Renci.SshNet.IntegrationTests/HostKeyFile.cs @@ -3,7 +3,7 @@ public sealed class HostKeyFile { public static readonly HostKeyFile Rsa = new HostKeyFile("ssh-rsa", "/etc/ssh/ssh_host_rsa_key", new byte[] { 0x3d, 0x90, 0xd8, 0x0d, 0xd5, 0xe0, 0xb6, 0x13, 0x42, 0x7c, 0x78, 0x1e, 0x19, 0xa3, 0x99, 0x2b }); - public static readonly HostKeyFile Dsa = new HostKeyFile("ssh-dsa", "/etc/ssh/ssh_host_dsa_key", new byte[] { 0x3d, 0x90, 0xd8, 0x0d, 0xd5, 0xe0, 0xb6, 0x13, 0x42, 0x7c, 0x78, 0x1e, 0x19, 0xa3, 0x99, 0x2b }); + public static readonly HostKeyFile Dsa = new HostKeyFile("ssh-dsa", "/etc/ssh/ssh_host_dsa_key", new byte[] { 0x50, 0xe0, 0xd5, 0x11, 0xf7, 0xed, 0x54, 0x75, 0x0d, 0x03, 0xc6, 0x52, 0x9b, 0x3b, 0x3c, 0x9f }); public static readonly HostKeyFile Ed25519 = new HostKeyFile("ssh-ed25519", "/etc/ssh/ssh_host_ed25519_key", new byte[] { 0xb3, 0xb9, 0xd0, 0x1b, 0x73, 0xc4, 0x60, 0xb4, 0xce, 0xed, 0x06, 0xf8, 0x58, 0x49, 0xa3, 0xda }); public const string Ecdsa = "/etc/ssh/ssh_host_ecdsa_key"; diff --git a/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs b/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs index 308f2ab3f..950079370 100644 --- a/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs +++ b/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs @@ -23,10 +23,7 @@ public void TearDown() } [TestMethod] - [Ignore] // No longer supported in recent versions of OpenSSH - // TODO: We should be able to enable some legacy settings to make it work - // https://www.openssh.com/legacy.html e.g. PubkeyAcceptedKeyTypes / HostbasedAcceptedKeyTypes ? - public void SshDsa() + public void SshDss() { DoTest(PublicKeyAlgorithm.SshDss, "id_dsa"); } diff --git a/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_dsa_key b/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_dsa_key new file mode 100644 index 000000000..eedaafb05 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_dsa_key @@ -0,0 +1,20 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIDPgIBAAKCAQEAuXza5HoqeOTKgTBY0iTglJGVLmmGvp9mWbrx20Xj8V1ouy8u +0ceju7/4AR6m9BzYWm2sAMAwvQcDeUi6pD4C4oIRzQSOg/nuUJO6RkneLQjMYEzD +61FokmxcUzHXQiKtqRRGL97naxj5fFIOppQXfllRASuvHeiG+I6EiFJL4zL7Uwen +CshEkpZsLZ2Xj8nfaD8yPmviDT/QWRUsZgw8lte7MonYVdKd0yeRQwS3vgJwusZv +fFHP4X7aXSwDJTlTGagxFV7jCktwtSc6QFoLWv5LZ2OAJxmgBM1HJQKOnP8dvn56 +EZub3DQrx3IpAgtsxa/8bxt/xFbbfp4sDHwLLQIVAKTEaiNtqneHljGoEGhUWJrs ++kdpAoIBAQCdBG7aHBIV83/icpkELAZ87I/0XDA9pVG+Sgs/OFgUd24tXi9S+dwp +LsVMVaBnN9TaEwZYR6z7Zg12r2j2q8BDTrRwwYHYJvwjHtsZVqaHi35fgBT2RO4T +SqRKYjrjb4mtPodUEo7CzK5+rLpvLM1SiiHfeqmUJqbkDwxQ9xXkCjRP50huJ+tA +ccgQIUyOYioz9omszJGANZlF5ZabzbAiTcXews2p97OeFWNTGTbXebV3FPSV+KBO +c0A5jxzQhEo3Kk58GXuog8t3OksNISdZPIJxHn+th644ZOj0L1v6PrUbXshPL1hp +VNlbn9fO4/HbQzL4NThmgzaZkT2FqxPxAoIBADuwcLTKtLX2cy9cqFiraeEaBXT3 +lQiPTFSLQKVm/k+iumXuOy5Fh3Akzu35MpNLK2gsdoWN9ZRQ8eWODdcnFXSJrnqX +cMWV6ONQ+nZ9YHrRp47KHKWKe+2c0T++S8QZAimb3KCjSOyEwn+i4aAGIvoaYIoH ++tRKmeL+7z1Ff/zJEB1FYVDmcqxhUKd74En6O17EmUHPfiQvwwTYvP5NvlLB23Hz +9ZO4nwrUSUIyVsWYT01s0JThkjI06N0dqKS1we94Ht1mT7iNJ5x5DhVR6qSNOgQH +FMKxKdXHdSFopwwHUrzm3BpKzKW3NuQHazcdZEl1vHb6LpfTv6O6bZIANyACFGBZ +9othW6gmt8t4cI6IyoaLCtLp +-----END DSA PRIVATE KEY----- diff --git a/src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys b/src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys index 8f0372d84..d91b4786c 100644 --- a/src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys +++ b/src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys @@ -3,3 +3,4 @@ ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPzzrPpI ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBLSsu/HNKiaALhQ26UDv+N0AFdMb26fMVrOKe866CGu6ajSf9HUOhJFdjhseihB2rTalMPr8MrcXNLufii4mL8u4l9fUQXFgwnM/ZpiVPSs6C+8i4u/ZDg7Nx2NXybNIgQ== ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACB4WgRgGBRo6Uk+cRgg8tJPCbEtGURRWlUA7PDDerXR+P9O6mm3L99Etxsyh5XNYqXyaMNtH5c51ooMajrFwcayAHIhPPb8X3CsTwEfIUQ96aDyHQMotbRfnkn6uefeUTRrSNcqeAndUtVyAqBdqbsq2mgJYXHrz2NUKlPFYgauQi+WQ== ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAkNGPVOTuzuKTgGfHcve2MRj57yXhmZgkUyi9RpmJrl +ssh-dss AAAAB3NzaC1kc3MAAACBALVl3fae2O4qwsAK95SUShX0KMUNP+yl/uT3lGH9T/ZptnHSlrTxnTWXCl0g91KEeCaEnDDhLxm4aCv1Ag4B/yvcM4u34qkmaNLy2LiAxiqdobZcNG61Pqwqd5IDkp38LBsn8tmb12xu9NalpUfOiSEB1cyCr4zFZMrm0wtdyJQVAAAAFQCu+iNkqf/YOAYjYrHSCHFmWAfEYQAAAIAOVJ434UAR3Hn6lA5nWNfFOuUVH3W7nJaP0FQJiIPx7GUbdxO9qtDNTbWkWL3c9qx5+B7Ole4xM7cvyXPrNQUYDHCFlS+Ue2x3IeJrkdfZkH9ePP25y5A0J4/c+8XXvQaj4zA5nfw13oy5Ptyd7d3Kq5tEDM8KiVdIhwkXjUA3PQAAAIEAm8IGZQatS7M6AfNITNWG4TI7Z2aRQjLb9/MWJIID7c/VQ4zdTZdG3kpk0Gj9n4xreopK5NmYAdj8rtFfPBgmXltsLqt+bBcXkpxW//7WC29WOXW3t90ySTh+cWuWfr9fV7mf4Ql/6u/ZIgpQNvnNYezazt3fK8EXjI1dAXEuQxE= diff --git a/src/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs b/src/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs index 0c79f7792..65807f462 100644 --- a/src/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs +++ b/src/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs @@ -16,7 +16,7 @@ public class HostKeyAlgorithm public static readonly HostKeyAlgorithm RsaSha2512 = new HostKeyAlgorithm("rsa-sha2-512"); public static readonly HostKeyAlgorithm RsaSha2256 = new HostKeyAlgorithm("rsa-sha2-256"); public static readonly HostKeyAlgorithm SshRsa = new HostKeyAlgorithm("ssh-rsa"); - public static readonly HostKeyAlgorithm SshDsa = new HostKeyAlgorithm("ssh-dsa"); + public static readonly HostKeyAlgorithm SshDss = new HostKeyAlgorithm("ssh-dss"); public HostKeyAlgorithm(string name) { From 4ba591ee0ba8769fecdd28ddc8fd06c2b9b5820a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Tue, 26 Sep 2023 21:00:20 +0200 Subject: [PATCH 42/96] FingerPrints (#1186) --- .../Common/HostKeyEventArgsBenchmarks.cs | 66 +++++++++++++++++++ .../ConnectivityTests.cs | 47 +++++++++++++ src/Renci.SshNet.IntegrationTests/Dockerfile | 4 +- .../Classes/Common/HostKeyEventArgsTest.cs | 2 + src/Renci.SshNet/Common/HostKeyEventArgs.cs | 57 +++++++++++++--- 5 files changed, 165 insertions(+), 11 deletions(-) create mode 100644 src/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs diff --git a/src/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs b/src/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs new file mode 100644 index 000000000..54900d046 --- /dev/null +++ b/src/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs @@ -0,0 +1,66 @@ +锘縰sing BenchmarkDotNet.Attributes; + +using Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers; +using Renci.SshNet.Common; +using Renci.SshNet.Security; + +namespace Renci.SshNet.Benchmarks.Common +{ + [MemoryDiagnoser] + [ShortRunJob] + public class HostKeyEventArgsBenchmarks + { + private readonly KeyHostAlgorithm _keyHostAlgorithm; + + public HostKeyEventArgsBenchmarks() + { + _keyHostAlgorithm = GetKeyHostAlgorithm(); + } + private static KeyHostAlgorithm GetKeyHostAlgorithm() + { + using (var s = typeof(RsaCipherBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.RSA.txt")) + { + var privateKey = new PrivateKeyFile(s); + return (KeyHostAlgorithm) privateKey.HostKeyAlgorithms.First(); + } + } + + [Benchmark()] + public HostKeyEventArgs Constructor() + { + return new HostKeyEventArgs(_keyHostAlgorithm); + } + + [Benchmark()] + public (string, string) CalculateFingerPrintSHA256AndMD5() + { + var test = new HostKeyEventArgs(_keyHostAlgorithm); + + return (test.FingerPrintSHA256, test.FingerPrintMD5); + } + + [Benchmark()] + public string CalculateFingerPrintSHA256() + { + var test = new HostKeyEventArgs(_keyHostAlgorithm); + + return test.FingerPrintSHA256; + } + + [Benchmark()] + public byte[] CalculateFingerPrint() + { + var test = new HostKeyEventArgs(_keyHostAlgorithm); + + return test.FingerPrint; + } + + [Benchmark()] + public string CalculateFingerPrintMD5() + { + var test = new HostKeyEventArgs(_keyHostAlgorithm); + + return test.FingerPrintSHA256; + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/ConnectivityTests.cs b/src/Renci.SshNet.IntegrationTests/ConnectivityTests.cs index 5401e6b6b..2f94ba7ff 100644 --- a/src/Renci.SshNet.IntegrationTests/ConnectivityTests.cs +++ b/src/Renci.SshNet.IntegrationTests/ConnectivityTests.cs @@ -380,6 +380,53 @@ public void Common_HostKeyValidation_Success() Assert.IsTrue(hostValidationSuccessful); } + [TestMethod] + public void Common_HostKeyValidationSHA256_Success() + { + var hostValidationSuccessful = false; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.HostKeyReceived += (sender, e) => + { + if (e.FingerPrintSHA256 == "9fa6vbz64gimzsGZ/xZi3aaYE1o7E96iU2NjcfQNGwI") + { + hostValidationSuccessful = e.CanTrust; + } + else + { + e.CanTrust = false; + } + }; + client.Connect(); + } + + Assert.IsTrue(hostValidationSuccessful); + } + + [TestMethod] + public void Common_HostKeyValidationMD5_Success() + { + var hostValidationSuccessful = false; + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.HostKeyReceived += (sender, e) => + { + if (e.FingerPrintMD5 == "3d:90:d8:0d:d5:e0:b6:13:42:7c:78:1e:19:a3:99:2b") + { + hostValidationSuccessful = e.CanTrust; + } + else + { + e.CanTrust = false; + } + }; + client.Connect(); + } + + Assert.IsTrue(hostValidationSuccessful); + } /// /// Verifies whether we handle a disconnect initiated by the SSH server (through a SSH_MSG_DISCONNECT message). /// diff --git a/src/Renci.SshNet.IntegrationTests/Dockerfile b/src/Renci.SshNet.IntegrationTests/Dockerfile index 160ea6f29..19ef6e19e 100644 --- a/src/Renci.SshNet.IntegrationTests/Dockerfile +++ b/src/Renci.SshNet.IntegrationTests/Dockerfile @@ -14,6 +14,8 @@ RUN apk update && apk upgrade --no-cache && \ chmod 400 /etc/ssh/ssh*key && \ sed -i 's/#PasswordAuthentication yes/PasswordAuthentication yes/' /etc/ssh/sshd_config && \ sed -i 's/#LogLevel\s*INFO/LogLevel DEBUG3/' /etc/ssh/sshd_config && \ + # Set the default RSA key + echo 'HostKey /etc/ssh/ssh_host_rsa_key' >> /etc/ssh/sshd_config && \ chmod 646 /etc/ssh/sshd_config && \ # install and configure sudo apk add --no-cache sudo && \ @@ -45,4 +47,4 @@ RUN apk update && apk upgrade --no-cache && \ EXPOSE 22 22 -ENTRYPOINT ["/opt/sshnet/start.sh"] \ No newline at end of file +ENTRYPOINT ["/opt/sshnet/start.sh"] diff --git a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs index 28001655a..39ff85d7b 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs @@ -56,6 +56,8 @@ public void HostKeyEventArgsConstructorTest_VerifyMD5() Assert.IsTrue(new byte[] { 0x92, 0xea, 0x54, 0xa1, 0x01, 0xf9, 0x95, 0x9c, 0x71, 0xd9, 0xbb, 0x51, 0xb2, 0x55, 0xf8, 0xd9 }.SequenceEqual(target.FingerPrint)); + Assert.AreEqual("92:ea:54:a1:01:f9:95:9c:71:d9:bb:51:b2:55:f8:d9", target.FingerPrintMD5); + } /// diff --git a/src/Renci.SshNet/Common/HostKeyEventArgs.cs b/src/Renci.SshNet/Common/HostKeyEventArgs.cs index ddf49d0ac..993b6d645 100644 --- a/src/Renci.SshNet/Common/HostKeyEventArgs.cs +++ b/src/Renci.SshNet/Common/HostKeyEventArgs.cs @@ -1,4 +1,5 @@ 锘縰sing System; + using Renci.SshNet.Abstractions; using Renci.SshNet.Security; @@ -9,6 +10,10 @@ namespace Renci.SshNet.Common /// public class HostKeyEventArgs : EventArgs { + private readonly Lazy _lazyFingerPrint; + private readonly Lazy _lazyFingerPrintSHA256; + private readonly Lazy _lazyFingerPrintMD5; + /// /// Gets or sets a value indicating whether host key can be trusted. /// @@ -33,15 +38,42 @@ public class HostKeyEventArgs : EventArgs /// /// MD5 fingerprint as byte array. /// - public byte[] FingerPrint { get; private set; } + public byte[] FingerPrint + { + get + { + return _lazyFingerPrint.Value; + } + } /// - /// Gets the SHA256 fingerprint. + /// Gets the SHA256 fingerprint of the host key in the same format as the ssh command, + /// i.e. non-padded base64, but without the SHA256: prefix. /// + /// ohD8VZEXGWo6Ez8GSEJQ9WpafgLFsOfLOtGGQCQo6Og /// /// Base64 encoded SHA256 fingerprint with padding (equals sign) removed. /// - public string FingerPrintSHA256 { get; private set; } + public string FingerPrintSHA256 + { + get + { + return _lazyFingerPrintSHA256.Value; + } + } + + /// + /// Gets the MD5 fingerprint of the host key in the same format as the ssh command, + /// i.e. hexadecimal bytes separated by colons, but without the MD5: prefix. + /// + /// 97:70:33:82:fd:29:3a:73:39:af:6a:07:ad:f8:80:49 + public string FingerPrintMD5 + { + get + { + return _lazyFingerPrintMD5.Value; + } + } /// /// Gets the length of the key in bits. @@ -61,16 +93,21 @@ public HostKeyEventArgs(KeyHostAlgorithm host) HostKey = host.Data; HostKeyName = host.Name; KeyLength = host.Key.KeyLength; - - using (var md5 = CryptoAbstraction.CreateMD5()) + + _lazyFingerPrint = new Lazy(() => { - FingerPrint = md5.ComputeHash(host.Data); - } + using var md5 = CryptoAbstraction.CreateMD5(); + return md5.ComputeHash(HostKey); + }); - using (var sha256 = CryptoAbstraction.CreateSHA256()) + _lazyFingerPrintSHA256 = new Lazy(() => { - FingerPrintSHA256 = Convert.ToBase64String(sha256.ComputeHash(host.Data)).Replace("=", ""); - } + using var sha256 = CryptoAbstraction.CreateSHA256(); + return Convert.ToBase64String(sha256.ComputeHash(HostKey)).Replace("=", ""); + }); + + _lazyFingerPrintMD5 = new Lazy(() => + BitConverter.ToString(FingerPrint).Replace("-", ":").ToLowerInvariant()); } } } From dd2e55209bf9236d489c59ec41efb7fd0fb57bef Mon Sep 17 00:00:00 2001 From: Dmitry Tsarevich Date: Tue, 26 Sep 2023 22:29:45 +0300 Subject: [PATCH 43/96] Use OS-agnostic socket error codes to allow tests run on different OSes (#1179) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SocketErrorCode is OS agnostic, ErrorCode is OS specific. On Windows ErrorCode = (int) SocketErrorCode, but on Mac and Unix it is not. For example ExitCode for HostNotFound (11001) on Windows is 11001, on Mac & Unix is -131073. So testing for ExitCode == 11001 fails on Mac & Unix. Co-authored-by: Wojciech Nag贸rski --- src/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs index c2798104a..db03567b4 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs @@ -20,7 +20,7 @@ public void Connect_HostNameInvalid_ShouldThrowSocketExceptionWithErrorCodeHostN } catch (SocketException ex) { - Assert.IsTrue(ex.ErrorCode is (int) SocketError.HostNotFound or (int) SocketError.TryAgain); + Assert.IsTrue(ex.SocketErrorCode is SocketError.HostNotFound or SocketError.TryAgain); } } @@ -38,7 +38,7 @@ public void Connect_ProxyHostNameInvalid_ShouldThrowSocketExceptionWithErrorCode } catch (SocketException ex) { - Assert.IsTrue(ex.ErrorCode is (int) SocketError.HostNotFound or (int) SocketError.TryAgain); + Assert.IsTrue(ex.SocketErrorCode is SocketError.HostNotFound or SocketError.TryAgain); } } } From f28c2c2dd03c95230fd1b16b3460ec4dbc5131fa Mon Sep 17 00:00:00 2001 From: Patrick Yates <114094360+patrick-yates-redgate@users.noreply.github.com> Date: Thu, 28 Sep 2023 20:01:18 +0100 Subject: [PATCH 44/96] Fix for channel session semaphore from thread blocking (#1071) * Merging fix from @clivetong into our own SSH.NET fork - The following article describes some of the issues with the double check lock that we have seen issues with: https://www.sudhanshutheone.com/posts/double-check-lock-csharp * Merging fix from @clivetong into our own SSH.NET fork - The following article describes some of the issues with the double check lock that we have seen issues with: https://www.sudhanshutheone.com/posts/double-check-lock-csharp * Update Channel to fix AppVeyor failure (field should be readonly) --- src/Renci.SshNet/Channels/Channel.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Renci.SshNet/Channels/Channel.cs b/src/Renci.SshNet/Channels/Channel.cs index df76e67cc..d3ec7ca6c 100644 --- a/src/Renci.SshNet/Channels/Channel.cs +++ b/src/Renci.SshNet/Channels/Channel.cs @@ -22,7 +22,7 @@ internal abstract class Channel : IChannel private uint? _remoteWindowSize; private uint? _remoteChannelNumber; private uint? _remotePacketSize; - private ISession _session; + private readonly ISession _session; private bool _isDisposed; /// @@ -834,7 +834,6 @@ protected virtual void Dispose(bool disposing) var session = _session; if (session != null) { - _session = null; session.ChannelWindowAdjustReceived -= OnChannelWindowAdjust; session.ChannelDataReceived -= OnChannelData; session.ChannelExtendedDataReceived -= OnChannelExtendedData; From cd1151decac9f5672411eebb12d939cedc53b317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Fri, 29 Sep 2023 09:05:45 +0200 Subject: [PATCH 45/96] Update ISftpClient for #120 (#1193) --- src/Renci.SshNet/ISftpClient.cs | 42 ++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/Renci.SshNet/ISftpClient.cs b/src/Renci.SshNet/ISftpClient.cs index 21d05ae7c..29f958d9f 100644 --- a/src/Renci.SshNet/ISftpClient.cs +++ b/src/Renci.SshNet/ISftpClient.cs @@ -239,6 +239,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// /// is null. /// is null or contains only whitespace. + /// If a problem occurs while copying the file IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback asyncCallback, object state); /// @@ -338,7 +339,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// /// /// When refers to an existing file, set to true to overwrite and truncate that file. - /// If is false, the upload will fail and will throw an + /// If is false, the upload will fail and will throw an /// . /// /// @@ -515,7 +516,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// is null or contains only whitespace characters. /// Client is not connected. /// Permission to perform the operation was denied by the remote host. -or- A SSH command was denied by the server. - /// was not found on the remote host./// + /// was not found on the remote host./// /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. /// @@ -527,7 +528,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// Ends an asynchronous file downloading into the stream. /// /// The pending asynchronous SFTP request. - /// The object did not come from the corresponding async method on this type.-or- was called multiple times with the same . + /// The object did not come from the corresponding async method on this type.-or- was called multiple times with the same . /// Client is not connected. /// Permission to perform the operation was denied by the remote host. -or- A SSH command was denied by the server. /// The path was not found on the remote host. @@ -541,7 +542,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// /// A list of files. /// - /// The object did not come from the corresponding async method on this type.-or- was called multiple times with the same . + /// The object did not come from the corresponding async method on this type.-or- was called multiple times with the same . IEnumerable EndListDirectory(IAsyncResult asyncResult); /// @@ -551,7 +552,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// /// A list of uploaded files. /// - /// The object did not come from the corresponding async method on this type.-or- was called multiple times with the same . + /// The object did not come from the corresponding async method on this type.-or- was called multiple times with the same . /// The destination path was not found on the remote host. IEnumerable EndSynchronizeDirectories(IAsyncResult asyncResult); @@ -559,7 +560,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// Ends an asynchronous uploading the stream into remote file. /// /// The pending asynchronous SFTP request. - /// The object did not come from the corresponding async method on this type.-or- was called multiple times with the same . + /// The object did not come from the corresponding async method on this type.-or- was called multiple times with the same . /// Client is not connected. /// The directory of the file was not found on the remote host. /// Permission to upload the file was denied by the remote host. -or- A SSH command was denied by the server. @@ -925,6 +926,34 @@ public interface ISftpClient : IBaseClient, IDisposable /// The method was called after the client was disposed. void RenameFile(string oldPath, string newPath, bool isPosix); + /// + /// Sets the date and time the specified file was last accessed. + /// + /// The file for which to set the access date and time information. + /// A containing the value to set for the last access date and time of path. This value is expressed in local time. + void SetLastAccessTime(string path, DateTime lastAccessTime); + + /// + /// Sets the date and time, in coordinated universal time (UTC), that the specified file was last accessed. + /// + /// The file for which to set the access date and time information. + /// A containing the value to set for the last access date and time of path. This value is expressed in UTC time. + void SetLastAccessTimeUtc(string path, DateTime lastAccessTimeUtc); + + /// + /// Sets the date and time that the specified file was last written to. + /// + /// The file for which to set the date and time information. + /// A containing the value to set for the last write date and time of path. This value is expressed in local time. + void SetLastWriteTime(string path, DateTime lastWriteTime); + + /// + /// Sets the date and time, in coordinated universal time (UTC), that the specified file was last written to. + /// + /// The file for which to set the date and time information. + /// A containing the value to set for the last write date and time of path. This value is expressed in UTC time. + void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc); + /// /// Sets the specified of the file on the specified path. /// @@ -959,6 +988,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// is null. /// is null or contains only whitespace. /// was not found on the remote host. + /// If a problem occurs while copying the file IEnumerable SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern); /// From 5803ada7cf8e373016d673c7c1922c8154b6e22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Fri, 29 Sep 2023 10:07:18 +0200 Subject: [PATCH 46/96] Implement set last write and access time (#1194) --- .../SftpTests.cs | 128 ++++++++++++++++++ src/Renci.SshNet/SftpClient.cs | 20 +-- 2 files changed, 140 insertions(+), 8 deletions(-) diff --git a/src/Renci.SshNet.IntegrationTests/SftpTests.cs b/src/Renci.SshNet.IntegrationTests/SftpTests.cs index dc316cfbc..a5a80bfef 100644 --- a/src/Renci.SshNet.IntegrationTests/SftpTests.cs +++ b/src/Renci.SshNet.IntegrationTests/SftpTests.cs @@ -6137,6 +6137,134 @@ public void Sftp_OpenRead() } } + [TestMethod] + public void Sftp_SetLastAccessTime() + { + var testFilePath = "/home/sshnet/test-file.txt"; + var testContent = "File"; + using var client = new SftpClient(_connectionInfoFactory.Create()); + client.Connect(); + + using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(testContent)); + var currentTime = DateTime.Now; + + client.UploadFile(fileStream, testFilePath); + + try + { + var time = client.GetLastAccessTime(testFilePath); + Assert.AreEqual(currentTime.Year, time.Year); + Assert.AreEqual(currentTime.Month, time.Month); + Assert.AreEqual(currentTime.Day, time.Day); + + var newTime = new DateTime(1986, 03, 15, 01, 02, 03); + + client.SetLastAccessTime(testFilePath, newTime); + time = client.GetLastAccessTime(testFilePath); + Assert.AreEqual(newTime, time); + } + finally + { + client.DeleteFile(testFilePath); + } + } + + + [TestMethod] + public void Sftp_SetLastAccessTimeUtc() + { + var testFilePath = "/home/sshnet/test-file.txt"; + var testContent = "File"; + using var client = new SftpClient(_connectionInfoFactory.Create()); + client.Connect(); + + using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(testContent)); + var currentTime = DateTime.UtcNow; + + client.UploadFile(fileStream, testFilePath); + try + { + var time = client.GetLastAccessTimeUtc(testFilePath); + Assert.AreEqual(currentTime.Year, time.Year); + Assert.AreEqual(currentTime.Month, time.Month); + Assert.AreEqual(currentTime.Day, time.Day); + + var newTime = new DateTime(1986, 03, 15, 01, 02, 03); + DateTime.SpecifyKind(newTime, DateTimeKind.Utc); + + client.SetLastAccessTimeUtc(testFilePath, newTime); + time = client.GetLastAccessTimeUtc(testFilePath); + Assert.AreEqual(newTime, time); + } + finally + { + client.DeleteFile(testFilePath); + } + } + + [TestMethod] + public void Sftp_SetLastWriteTime() + { + var testFilePath = "/home/sshnet/test-file.txt"; + var testContent = "File"; + using var client = new SftpClient(_connectionInfoFactory.Create()); + client.Connect(); + + using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(testContent)); + var currentTime = DateTime.Now; + + client.UploadFile(fileStream, testFilePath); + try + { + var time = client.GetLastWriteTime(testFilePath); + Assert.AreEqual(currentTime.Year, time.Year); + Assert.AreEqual(currentTime.Month, time.Month); + Assert.AreEqual(currentTime.Day, time.Day); + + var newTime = new DateTime(1986, 03, 15, 01, 02, 03); + + client.SetLastWriteTime(testFilePath, newTime); + time = client.GetLastWriteTime(testFilePath); + Assert.AreEqual(newTime, time); + } + finally + { + client.DeleteFile(testFilePath); + } + } + + [TestMethod] + public void Sftp_SetLastWriteTimeUtc() + { + var testFilePath = "/home/sshnet/test-file.txt"; + var testContent = "File"; + using var client = new SftpClient(_connectionInfoFactory.Create()); + client.Connect(); + + using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(testContent)); + var currentTime = DateTime.UtcNow; + + client.UploadFile(fileStream, testFilePath); + try + { + var time = client.GetLastWriteTimeUtc(testFilePath); + Assert.AreEqual(currentTime.Year, time.Year); + Assert.AreEqual(currentTime.Month, time.Month); + Assert.AreEqual(currentTime.Day, time.Day); + + var newTime = new DateTime(1986, 03, 15, 01, 02, 03); + DateTime.SpecifyKind(newTime, DateTimeKind.Utc); + + client.SetLastWriteTimeUtc(testFilePath, newTime); + time = client.GetLastWriteTimeUtc(testFilePath); + Assert.AreEqual(newTime, time); + } + finally + { + client.DeleteFile(testFilePath); + } + } + private static IEnumerable GetSftpUploadFileFileStreamData() { yield return new object[] { 0 }; diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index e6f9cb2d6..877fed092 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -1801,10 +1801,11 @@ public IEnumerable ReadLines(string path, Encoding encoding) /// /// The file for which to set the access date and time information. /// A containing the value to set for the last access date and time of path. This value is expressed in local time. - [Obsolete("Note: This method currently throws NotImplementedException because it has not yet been implemented.")] public void SetLastAccessTime(string path, DateTime lastAccessTime) { - throw new NotImplementedException(); + var attributes = GetAttributes(path); + attributes.LastAccessTime = lastAccessTime; + SetAttributes(path, attributes); } /// @@ -1812,10 +1813,11 @@ public void SetLastAccessTime(string path, DateTime lastAccessTime) /// /// The file for which to set the access date and time information. /// A containing the value to set for the last access date and time of path. This value is expressed in UTC time. - [Obsolete("Note: This method currently throws NotImplementedException because it has not yet been implemented.")] public void SetLastAccessTimeUtc(string path, DateTime lastAccessTimeUtc) { - throw new NotImplementedException(); + var attributes = GetAttributes(path); + attributes.LastAccessTimeUtc = lastAccessTimeUtc; + SetAttributes(path, attributes); } /// @@ -1823,10 +1825,11 @@ public void SetLastAccessTimeUtc(string path, DateTime lastAccessTimeUtc) /// /// The file for which to set the date and time information. /// A containing the value to set for the last write date and time of path. This value is expressed in local time. - [Obsolete("Note: This method currently throws NotImplementedException because it has not yet been implemented.")] public void SetLastWriteTime(string path, DateTime lastWriteTime) { - throw new NotImplementedException(); + var attributes = GetAttributes(path); + attributes.LastWriteTime = lastWriteTime; + SetAttributes(path, attributes); } /// @@ -1834,10 +1837,11 @@ public void SetLastWriteTime(string path, DateTime lastWriteTime) /// /// The file for which to set the date and time information. /// A containing the value to set for the last write date and time of path. This value is expressed in UTC time. - [Obsolete("Note: This method currently throws NotImplementedException because it has not yet been implemented.")] public void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc) { - throw new NotImplementedException(); + var attributes = GetAttributes(path); + attributes.LastWriteTimeUtc = lastWriteTimeUtc; + SetAttributes(path, attributes); } /// From 70f58b76605e0a55e17d1b5fe42ee58b74275a71 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Fri, 29 Sep 2023 13:38:32 +0100 Subject: [PATCH 47/96] Add/migrate hmac+cipher integration tests (#1189) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add/migrate hmac+cipher integration tests * fix integration tests --------- Co-authored-by: Wojciech Nag贸rski --- .../CipherTests.cs | 81 ++++++++++ .../Common/RemoteSshdConfigExtensions.cs | 1 + .../HmacTests.cs | 75 +++++++++ .../OldIntegrationTests/AesCipherTests.cs | 147 ------------------ .../OldIntegrationTests/HMacTest.cs | 67 -------- .../TripleDesCipherTest.cs | 50 ------ .../PrivateKeyAuthenticationTests.cs | 2 +- .../RemoteSshd.cs | 14 +- 8 files changed, 171 insertions(+), 266 deletions(-) create mode 100644 src/Renci.SshNet.IntegrationTests/CipherTests.cs create mode 100644 src/Renci.SshNet.IntegrationTests/HmacTests.cs delete mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/AesCipherTests.cs delete mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/HMacTest.cs delete mode 100644 src/Renci.SshNet.IntegrationTests/OldIntegrationTests/TripleDesCipherTest.cs diff --git a/src/Renci.SshNet.IntegrationTests/CipherTests.cs b/src/Renci.SshNet.IntegrationTests/CipherTests.cs new file mode 100644 index 000000000..1a11f9814 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/CipherTests.cs @@ -0,0 +1,81 @@ +锘縰sing Renci.SshNet.IntegrationTests.Common; +using Renci.SshNet.TestTools.OpenSSH; + +namespace Renci.SshNet.IntegrationTests +{ + [TestClass] + public class CipherTests : IntegrationTestBase + { + private IConnectionInfoFactory _connectionInfoFactory; + private RemoteSshdConfig _remoteSshdConfig; + + [TestInitialize] + public void SetUp() + { + _connectionInfoFactory = new LinuxVMConnectionFactory(SshServerHostName, SshServerPort); + _remoteSshdConfig = new RemoteSshd(new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort)).OpenConfig(); + } + + [TestCleanup] + public void TearDown() + { + _remoteSshdConfig?.Reset(); + } + + [TestMethod] + public void TripledesCbc() + { + DoTest(Cipher.TripledesCbc); + } + + [TestMethod] + public void Aes128Cbc() + { + DoTest(Cipher.Aes128Cbc); + } + + [TestMethod] + public void Aes192Cbc() + { + DoTest(Cipher.Aes192Cbc); + } + + [TestMethod] + public void Aes256Cbc() + { + DoTest(Cipher.Aes256Cbc); + } + + [TestMethod] + public void Aes128Ctr() + { + DoTest(Cipher.Aes128Ctr); + } + + [TestMethod] + public void Aes192Ctr() + { + DoTest(Cipher.Aes192Ctr); + } + + [TestMethod] + public void Aes256Ctr() + { + DoTest(Cipher.Aes256Ctr); + } + + private void DoTest(Cipher cipher) + { + _remoteSshdConfig.ClearCiphers() + .AddCipher(cipher) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs b/src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs index af64ff62a..865154bfb 100644 --- a/src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs +++ b/src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs @@ -21,6 +21,7 @@ public static void Reset(this RemoteSshdConfig remoteSshdConfig) .ClearKeyExchangeAlgorithms() .ClearHostKeyAlgorithms() .ClearPublicKeyAcceptedAlgorithms() + .ClearMessageAuthenticationCodeAlgorithms() .WithUsePAM(true) .Update() .Restart(); diff --git a/src/Renci.SshNet.IntegrationTests/HmacTests.cs b/src/Renci.SshNet.IntegrationTests/HmacTests.cs new file mode 100644 index 000000000..993e5ec98 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/HmacTests.cs @@ -0,0 +1,75 @@ +锘縰sing Renci.SshNet.IntegrationTests.Common; +using Renci.SshNet.TestTools.OpenSSH; + +namespace Renci.SshNet.IntegrationTests +{ + [TestClass] + public class HmacTests : IntegrationTestBase + { + private IConnectionInfoFactory _connectionInfoFactory; + private RemoteSshdConfig _remoteSshdConfig; + + [TestInitialize] + public void SetUp() + { + _connectionInfoFactory = new LinuxVMConnectionFactory(SshServerHostName, SshServerPort); + _remoteSshdConfig = new RemoteSshd(new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort)).OpenConfig(); + } + + [TestCleanup] + public void TearDown() + { + _remoteSshdConfig?.Reset(); + } + + [TestMethod] + public void HmacMd5() + { + DoTest(MessageAuthenticationCodeAlgorithm.HmacMd5); + } + + [TestMethod] + public void HmacMd5_96() + { + DoTest(MessageAuthenticationCodeAlgorithm.HmacMd5_96); + } + + [TestMethod] + public void HmacSha1() + { + DoTest(MessageAuthenticationCodeAlgorithm.HmacSha1); + } + + [TestMethod] + public void HmacSha1_96() + { + DoTest(MessageAuthenticationCodeAlgorithm.HmacSha1_96); + } + + [TestMethod] + public void HmacSha2_256() + { + DoTest(MessageAuthenticationCodeAlgorithm.HmacSha2_256); + } + + [TestMethod] + public void HmacSha2_512() + { + DoTest(MessageAuthenticationCodeAlgorithm.HmacSha2_512); + } + + private void DoTest(MessageAuthenticationCodeAlgorithm macAlgorithm) + { + _remoteSshdConfig.ClearMessageAuthenticationCodeAlgorithms() + .AddMessageAuthenticationCodeAlgorithm(macAlgorithm) + .Update() + .Restart(); + + using (var client = new SshClient(_connectionInfoFactory.Create())) + { + client.Connect(); + client.Disconnect(); + } + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/AesCipherTests.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/AesCipherTests.cs deleted file mode 100644 index 7e9e97b01..000000000 --- a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/AesCipherTests.cs +++ /dev/null @@ -1,147 +0,0 @@ -锘縰sing Renci.SshNet.IntegrationTests.Common; -using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; -using Renci.SshNet.TestTools.OpenSSH; - -namespace Renci.SshNet.IntegrationTests.OldIntegrationTests -{ - [TestClass] - public class AesCipherTests : IntegrationTestBase - { - private IConnectionInfoFactory _adminConnectionInfoFactory; - private RemoteSshdConfig _remoteSshdConfig; - - [TestInitialize] - public void SetUp() - { - _adminConnectionInfoFactory = new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort); - _remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig(); - } - - [TestCleanup] - public void TearDown() - { - _remoteSshdConfig?.Reset(); - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - public void Test_Cipher_AEes128CBC_Connection() - { - _remoteSshdConfig.AddCipher(Cipher.Aes128Cbc) - .Update() - .Restart(); - - var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes128-cbc", new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - public void Test_Cipher_Aes192CBC_Connection() - { - _remoteSshdConfig.AddCipher(Cipher.Aes192Cbc) - .Update() - .Restart(); - - var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes192-cbc", new CipherInfo(192, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - public void Test_Cipher_Aes256CBC_Connection() - { - _remoteSshdConfig.AddCipher(Cipher.Aes256Cbc) - .Update() - .Restart(); - - var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes256-cbc", new CipherInfo(256, (key, iv) => { return new AesCipher(key, new CbcCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - public void Test_Cipher_Aes128CTR_Connection() - { - _remoteSshdConfig.AddCipher(Cipher.Aes128Ctr) - .Update() - .Restart(); - - var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes128-ctr", new CipherInfo(128, (key, iv) => { return new AesCipher(key, new CtrCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - public void Test_Cipher_Aes192CTR_Connection() - { - _remoteSshdConfig.AddCipher(Cipher.Aes192Ctr) - .Update() - .Restart(); - - var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes192-ctr", new CipherInfo(192, (key, iv) => { return new AesCipher(key, new CtrCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - public void Test_Cipher_Aes256CTR_Connection() - { - _remoteSshdConfig.AddCipher(Cipher.Aes256Ctr) - .Update() - .Restart(); - - var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("aes256-ctr", new CipherInfo(256, (key, iv) => { return new AesCipher(key, new CtrCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - } -} diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/HMacTest.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/HMacTest.cs deleted file mode 100644 index c8df34e9d..000000000 --- a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/HMacTest.cs +++ /dev/null @@ -1,67 +0,0 @@ -锘縰sing Renci.SshNet.Abstractions; -using Renci.SshNet.IntegrationTests.Common; - -namespace Renci.SshNet.IntegrationTests.OldIntegrationTests -{ - [TestClass] - public class HMacTest : IntegrationTestBase - { - private IConnectionInfoFactory _adminConnectionInfoFactory; - private RemoteSshdConfig _remoteSshdConfig; - - [TestInitialize] - public void SetUp() - { - _adminConnectionInfoFactory = new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort); - _remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig(); - } - - [TestCleanup] - public void TearDown() - { - _remoteSshdConfig?.Reset(); - } - - [TestMethod] - public void Test_HMac_Sha1_Connection() - { - var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); - connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-sha1", new HashInfo(20 * 8, CryptoAbstraction.CreateHMACSHA1)); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - public void Test_HMac_Sha256_Connection() - { - var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); - connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-sha2-256", new HashInfo(32 * 8, CryptoAbstraction.CreateHMACSHA256)); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - - [TestMethod] - public void Test_HMac_Sha2_512_Connection() - { - var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); - connectionInfo.HmacAlgorithms.Clear(); - connectionInfo.HmacAlgorithms.Add("hmac-sha2-512", new HashInfo(64 * 8, CryptoAbstraction.CreateHMACSHA512)); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - } -} diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/TripleDesCipherTest.cs b/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/TripleDesCipherTest.cs deleted file mode 100644 index a9195cf5e..000000000 --- a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/TripleDesCipherTest.cs +++ /dev/null @@ -1,50 +0,0 @@ -锘縰sing Renci.SshNet.IntegrationTests.Common; -using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; -using Renci.SshNet.TestTools.OpenSSH; - -namespace Renci.SshNet.IntegrationTests.OldIntegrationTests -{ - /// - /// Implements 3DES cipher algorithm. - /// - [TestClass] - public class TripleDesCipherTest : IntegrationTestBase - { - private IConnectionInfoFactory _adminConnectionInfoFactory; - private RemoteSshdConfig _remoteSshdConfig; - - [TestInitialize] - public void SetUp() - { - _adminConnectionInfoFactory = new LinuxAdminConnectionFactory(SshServerHostName, SshServerPort); - _remoteSshdConfig = new RemoteSshd(_adminConnectionInfoFactory).OpenConfig(); - } - - [TestCleanup] - public void TearDown() - { - _remoteSshdConfig?.Reset(); - } - - [TestMethod] - [Owner("olegkap")] - [TestCategory("Cipher")] - public void Test_Cipher_TripleDESCBC_Connection() - { - _remoteSshdConfig.AddCipher(Cipher.TripledesCbc) - .Update() - .Restart(); - - var connectionInfo = new PasswordConnectionInfo(SshServerHostName, SshServerPort, User.UserName, User.Password); - connectionInfo.Encryptions.Clear(); - connectionInfo.Encryptions.Add("3des-cbc", new CipherInfo(192, (key, iv) => { return new TripleDesCipher(key, new CbcCipherMode(iv), null); })); - - using (var client = new SshClient(connectionInfo)) - { - client.Connect(); - client.Disconnect(); - } - } - } -} diff --git a/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs b/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs index 950079370..05b6c4787 100644 --- a/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs +++ b/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs @@ -73,7 +73,7 @@ public void Ed25519() private void DoTest(PublicKeyAlgorithm publicKeyAlgorithm, string keyResource) { _remoteSshdConfig.ClearPublicKeyAcceptedAlgorithms() - .AddPublicKeyAcceptedAlgorithms(publicKeyAlgorithm) + .AddPublicKeyAcceptedAlgorithm(publicKeyAlgorithm) .Update() .Restart(); diff --git a/src/Renci.SshNet.IntegrationTests/RemoteSshd.cs b/src/Renci.SshNet.IntegrationTests/RemoteSshd.cs index c81bf96f5..b9a32e67a 100644 --- a/src/Renci.SshNet.IntegrationTests/RemoteSshd.cs +++ b/src/Renci.SshNet.IntegrationTests/RemoteSshd.cs @@ -167,12 +167,24 @@ public RemoteSshdConfig ClearPublicKeyAcceptedAlgorithms() return this; } - public RemoteSshdConfig AddPublicKeyAcceptedAlgorithms(PublicKeyAlgorithm publicKeyAlgorithm) + public RemoteSshdConfig AddPublicKeyAcceptedAlgorithm(PublicKeyAlgorithm publicKeyAlgorithm) { _config.PublicKeyAcceptedAlgorithms.Add(publicKeyAlgorithm); return this; } + public RemoteSshdConfig ClearMessageAuthenticationCodeAlgorithms() + { + _config.MessageAuthenticationCodeAlgorithms.Clear(); + return this; + } + + public RemoteSshdConfig AddMessageAuthenticationCodeAlgorithm(MessageAuthenticationCodeAlgorithm messageAuthenticationCodeAlgorithm) + { + _config.MessageAuthenticationCodeAlgorithms.Add(messageAuthenticationCodeAlgorithm); + return this; + } + public RemoteSshdConfig ClearHostKeyAlgorithms() { _config.HostKeyAlgorithms.Clear(); From 1c7166a002d7633fe1595b3df4634ba0ef6e3138 Mon Sep 17 00:00:00 2001 From: Gert Driesen Date: Mon, 9 Oct 2023 05:45:16 +0200 Subject: [PATCH 48/96] Update tests for SetLastAccessTime(Utc) to also verify the time component and the Kind of the DateTime value returned by GetLastAccessTime(Utc). (#1198) --- .../Common/DateTimeAssert.cs | 11 +++++ .../Common/DateTimeExtensions.cs | 12 ++++++ .../SftpTests.cs | 42 +++++++++---------- src/Renci.SshNet.sln | 6 +++ 4 files changed, 49 insertions(+), 22 deletions(-) create mode 100644 src/Renci.SshNet.IntegrationTests/Common/DateTimeAssert.cs create mode 100644 src/Renci.SshNet.IntegrationTests/Common/DateTimeExtensions.cs diff --git a/src/Renci.SshNet.IntegrationTests/Common/DateTimeAssert.cs b/src/Renci.SshNet.IntegrationTests/Common/DateTimeAssert.cs new file mode 100644 index 000000000..036a122d5 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/Common/DateTimeAssert.cs @@ -0,0 +1,11 @@ +锘縩amespace Renci.SshNet.IntegrationTests.Common +{ + public static class DateTimeAssert + { + public static void AreEqual(DateTime expected, DateTime actual) + { + Assert.AreEqual(expected, actual, $"Expected {expected:o}, but was {actual:o}."); + Assert.AreEqual(expected.Kind, actual.Kind); + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/Common/DateTimeExtensions.cs b/src/Renci.SshNet.IntegrationTests/Common/DateTimeExtensions.cs new file mode 100644 index 000000000..d9f0d22e7 --- /dev/null +++ b/src/Renci.SshNet.IntegrationTests/Common/DateTimeExtensions.cs @@ -0,0 +1,12 @@ +锘縩amespace Renci.SshNet.IntegrationTests.Common +{ + public static class DateTimeExtensions + { + public static DateTime TruncateToWholeSeconds(this DateTime dateTime) + { + return dateTime.AddMilliseconds(-dateTime.Millisecond) + .AddMicroseconds(-dateTime.Microsecond) + .AddTicks(-(dateTime.Nanosecond / 100)); + } + } +} diff --git a/src/Renci.SshNet.IntegrationTests/SftpTests.cs b/src/Renci.SshNet.IntegrationTests/SftpTests.cs index a5a80bfef..7fb18c709 100644 --- a/src/Renci.SshNet.IntegrationTests/SftpTests.cs +++ b/src/Renci.SshNet.IntegrationTests/SftpTests.cs @@ -6153,15 +6153,15 @@ public void Sftp_SetLastAccessTime() try { var time = client.GetLastAccessTime(testFilePath); - Assert.AreEqual(currentTime.Year, time.Year); - Assert.AreEqual(currentTime.Month, time.Month); - Assert.AreEqual(currentTime.Day, time.Day); - var newTime = new DateTime(1986, 03, 15, 01, 02, 03); + DateTimeAssert.AreEqual(currentTime.TruncateToWholeSeconds(), time); + + var newTime = new DateTime(1986, 03, 15, 01, 02, 03, 123, DateTimeKind.Local); client.SetLastAccessTime(testFilePath, newTime); time = client.GetLastAccessTime(testFilePath); - Assert.AreEqual(newTime, time); + + DateTimeAssert.AreEqual(newTime.TruncateToWholeSeconds(), time); } finally { @@ -6185,16 +6185,15 @@ public void Sftp_SetLastAccessTimeUtc() try { var time = client.GetLastAccessTimeUtc(testFilePath); - Assert.AreEqual(currentTime.Year, time.Year); - Assert.AreEqual(currentTime.Month, time.Month); - Assert.AreEqual(currentTime.Day, time.Day); - var newTime = new DateTime(1986, 03, 15, 01, 02, 03); - DateTime.SpecifyKind(newTime, DateTimeKind.Utc); + DateTimeAssert.AreEqual(currentTime.TruncateToWholeSeconds(), time); + + var newTime = new DateTime(1986, 03, 15, 01, 02, 03, 123, DateTimeKind.Utc); client.SetLastAccessTimeUtc(testFilePath, newTime); time = client.GetLastAccessTimeUtc(testFilePath); - Assert.AreEqual(newTime, time); + + DateTimeAssert.AreEqual(newTime.TruncateToWholeSeconds(), time); } finally { @@ -6217,15 +6216,15 @@ public void Sftp_SetLastWriteTime() try { var time = client.GetLastWriteTime(testFilePath); - Assert.AreEqual(currentTime.Year, time.Year); - Assert.AreEqual(currentTime.Month, time.Month); - Assert.AreEqual(currentTime.Day, time.Day); - var newTime = new DateTime(1986, 03, 15, 01, 02, 03); + DateTimeAssert.AreEqual(currentTime.TruncateToWholeSeconds(), time); + + var newTime = new DateTime(1986, 03, 15, 01, 02, 03, 123, DateTimeKind.Local); client.SetLastWriteTime(testFilePath, newTime); time = client.GetLastWriteTime(testFilePath); - Assert.AreEqual(newTime, time); + + DateTimeAssert.AreEqual(newTime.TruncateToWholeSeconds(), time); } finally { @@ -6248,16 +6247,15 @@ public void Sftp_SetLastWriteTimeUtc() try { var time = client.GetLastWriteTimeUtc(testFilePath); - Assert.AreEqual(currentTime.Year, time.Year); - Assert.AreEqual(currentTime.Month, time.Month); - Assert.AreEqual(currentTime.Day, time.Day); - var newTime = new DateTime(1986, 03, 15, 01, 02, 03); - DateTime.SpecifyKind(newTime, DateTimeKind.Utc); + DateTimeAssert.AreEqual(currentTime.TruncateToWholeSeconds(), time); + + var newTime = new DateTime(1986, 03, 15, 01, 02, 03, 123, DateTimeKind.Utc); client.SetLastWriteTimeUtc(testFilePath, newTime); time = client.GetLastWriteTimeUtc(testFilePath); - Assert.AreEqual(newTime, time); + + DateTimeAssert.AreEqual(newTime.TruncateToWholeSeconds(), time); } finally { diff --git a/src/Renci.SshNet.sln b/src/Renci.SshNet.sln index 459d129c4..259ae16ed 100644 --- a/src/Renci.SshNet.sln +++ b/src/Renci.SshNet.sln @@ -48,6 +48,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.IntegrationTes EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.TestTools.OpenSSH", "Renci.SshNet.TestTools.OpenSSH\Renci.SshNet.TestTools.OpenSSH.csproj", "{78239046-2019-494E-B6EC-240AF787E4D0}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E8A42832-1183-4E66-9141-DEBA662374DF}" + ProjectSection(SolutionItems) = preProject + global.json = global.json + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -158,6 +163,7 @@ Global {94EE3919-19FA-4D9B-8DA9-249050B15232} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} {A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} {D21A4D03-0AC2-4613-BB6D-74D2D16A72CC} = {04E8CC26-116E-4116-9558-7ED542548E70} + {E8A42832-1183-4E66-9141-DEBA662374DF} = {04E8CC26-116E-4116-9558-7ED542548E70} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BAD6019D-4AF7-4E15-99A0-8036E16FC0E5} From 91d1ed2cbdfacaed242f834c535ad8f2184148bb Mon Sep 17 00:00:00 2001 From: Patrick-3000 <38472350+Patrick-3000@users.noreply.github.com> Date: Sat, 14 Oct 2023 16:35:31 +0200 Subject: [PATCH 49/96] Enable list directory async for net framework (#1206) * Enable ListDirectoryAsync for .NET Framework * Removed (now) unused constant. --- .../Classes/SftpClientTest.ListDirectory.cs | 5 ++-- .../SftpClientTest.ListDirectoryAsync.cs | 29 +++++++++++++++++++ src/Renci.SshNet/ISftpClient.cs | 2 -- src/Renci.SshNet/Renci.SshNet.csproj | 8 ++--- src/Renci.SshNet/SftpClient.cs | 6 +--- 5 files changed, 36 insertions(+), 14 deletions(-) create mode 100644 src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectoryAsync.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs index ceafd4c50..f44016ecb 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs @@ -1,9 +1,8 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System.Diagnostics; +using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; using Renci.SshNet.Tests.Properties; -using System.Diagnostics; - namespace Renci.SshNet.Tests.Classes { /// diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectoryAsync.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectoryAsync.cs new file mode 100644 index 000000000..c800452eb --- /dev/null +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectoryAsync.cs @@ -0,0 +1,29 @@ +锘縰sing System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Renci.SshNet.Common; +using Renci.SshNet.Tests.Properties; + +namespace Renci.SshNet.Tests.Classes +{ + /// + /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. + /// + public partial class SftpClientTest + { + [TestMethod] + [TestCategory("Sftp")] + [ExpectedException(typeof(SshConnectionException))] + public async Task Test_Sftp_ListDirectoryAsync_Without_ConnectingAsync() + { + using (var sftp = new SftpClient(Resources.HOST, Resources.USERNAME, Resources.PASSWORD)) + { + await foreach (var file in sftp.ListDirectoryAsync(".", CancellationToken.None)) + { + Debug.WriteLine(file.FullName); + } + } + } + } +} diff --git a/src/Renci.SshNet/ISftpClient.cs b/src/Renci.SshNet/ISftpClient.cs index 29f958d9f..b79a22793 100644 --- a/src/Renci.SshNet/ISftpClient.cs +++ b/src/Renci.SshNet/ISftpClient.cs @@ -700,7 +700,6 @@ public interface ISftpClient : IBaseClient, IDisposable /// The method was called after the client was disposed. IEnumerable ListDirectory(string path, Action listCallback = null); -#if FEATURE_ASYNC_ENUMERABLE /// /// Asynchronously enumerates the files in remote directory. /// @@ -716,7 +715,6 @@ public interface ISftpClient : IBaseClient, IDisposable /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. IAsyncEnumerable ListDirectoryAsync(string path, CancellationToken cancellationToken); -#endif //FEATURE_ASYNC_ENUMERABLE /// /// Opens a on the specified path with read/write access. diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index e55911d55..4ccf6c72e 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -13,11 +13,11 @@ + + + + FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP - - - $(DefineConstants);FEATURE_ASYNC_ENUMERABLE - diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 877fed092..ae8ba29af 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -10,9 +10,7 @@ using Renci.SshNet.Common; using Renci.SshNet.Sftp; using System.Threading.Tasks; -#if FEATURE_ASYNC_ENUMERABLE using System.Runtime.CompilerServices; -#endif namespace Renci.SshNet { @@ -587,7 +585,6 @@ public IEnumerable ListDirectory(string path, Action listCallbac return InternalListDirectory(path, listCallback); } -#if FEATURE_ASYNC_ENUMERABLE /// /// Asynchronously enumerates the files in remote directory. /// @@ -646,7 +643,6 @@ public async IAsyncEnumerable ListDirectoryAsync(string path, [Enumer await _sftpSession.RequestCloseAsync(handle, cancellationToken).ConfigureAwait(false); } } -#endif //FEATURE_ASYNC_ENUMERABLE /// /// Begins an asynchronous operation of retrieving list of files in remote directory. @@ -1613,7 +1609,7 @@ public Task OpenAsync(string path, FileMode mode, FileAccess acc cancellationToken.ThrowIfCancellationRequested(); - return SftpFileStream.OpenAsync(_sftpSession, path, mode, access, (int)_bufferSize, cancellationToken); + return SftpFileStream.OpenAsync(_sftpSession, path, mode, access, (int) _bufferSize, cancellationToken); } /// From 0e9b518492748c777cc19994b7ce260f4baa575e Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Sat, 14 Oct 2023 20:41:04 +0100 Subject: [PATCH 50/96] Remove placeholder tests (#1183) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Remove placeholder tests * Move Reverse perf test to benchmarks project --------- Co-authored-by: Wojciech Nag贸rski --- .../Common/ExtensionsBenchmarks.cs | 27 + .../Classes/CipherInfoTest.cs | 29 - .../Classes/Common/AsyncResultTest.cs | 136 -- .../Classes/Common/DerDataTest.cs | 173 --- .../Classes/Common/ExtensionsTest_Reverse.cs | 21 +- .../Common/SshConnectionExceptionTest.cs | 15 - .../Classes/Common/SshExceptionTest.cs | 15 - .../Classes/Compression/CompressorTest.cs | 75 - .../Classes/Compression/ZlibOpenSshTest.cs | 49 - .../Classes/Compression/ZlibStreamTest.cs | 47 - .../Classes/Compression/ZlibTest.cs | 13 - .../Classes/ForwardedPortRemoteTest.cs | 59 - ...oardInteractiveAuthenticationMethodTest.cs | 58 +- .../KeyboardInteractiveConnectionInfoTest.cs | 159 --- .../Classes/MessageEventArgsTest.cs | 29 - .../Authentication/BannerMessageTest.cs | 25 - .../Authentication/FailureMessageTest.cs | 42 - .../InformationRequestMessageTest.cs | 13 - .../InformationResponseMessageTest.cs | 13 - .../PasswordChangeRequiredMessageTest.cs | 13 - .../Authentication/PublicKeyMessageTest.cs | 13 - .../Authentication/RequestMessageHostTest.cs | 11 - .../RequestMessageKeyboardInteractiveTest.cs | 13 - .../Authentication/RequestMessageNoneTest.cs | 11 - .../RequestMessagePasswordTest.cs | 13 - .../RequestMessagePublicKeyTest.cs | 82 -- .../Authentication/SuccessMessageTest.cs | 25 - .../Connection/ChannelCloseMessageTest.cs | 37 - .../Connection/ChannelEofMessageTest.cs | 37 - .../ChannelExtendedDataMessageTest.cs | 38 - .../Connection/ChannelFailureMessageTest.cs | 38 - .../Messages/Connection/ChannelMessageTest.cs | 36 - .../ChannelOpen/DirectTcpipChannelInfoTest.cs | 13 - .../ForwardedTcpipChannelInfoTest.cs | 13 - .../ChannelOpen/SessionChannelOpenInfoTest.cs | 13 - .../ChannelOpen/X11ChannelOpenInfoTest.cs | 13 - .../ChannelOpenConfirmationMessageTest.cs | 41 - .../ChannelOpenFailureMessageTest.cs | 40 - .../Connection/ChannelOpenInfoTest.cs | 34 - .../ChannelRequest/BreakRequestInfoTest.cs | 13 - .../ChannelRequestMessageTest.cs | 36 - .../EndOfWriteRequestInfoTest.cs | 39 - .../EnvironmentVariableRequestInfoTest.cs | 13 - .../ChannelRequest/ExecRequestInfoTest.cs | 13 - .../ExitSignalRequestInfoTest.cs | 13 - .../ExitStatusRequestInfoTest.cs | 13 - .../KeepAliveRequestInfoTest.cs | 38 - .../ChannelRequest/ShellRequestInfoTest.cs | 13 - .../ChannelRequest/SignalRequestInfoTest.cs | 13 - .../SubsystemRequestInfoTest.cs | 13 - .../WindowChangeRequestInfoTest.cs | 13 - .../X11ForwardingRequestInfoTest.cs | 13 - .../ChannelRequest/XonXoffRequestInfoTest.cs | 13 - .../Connection/ChannelSuccessMessageTest.cs | 38 - .../ChannelWindowAdjustMessageTest.cs | 39 - .../Connection/RequestFailureMessageTest.cs | 25 - .../Messages/Connection/RequestInfoTest.cs | 34 - .../Connection/RequestSuccessMessageTest.cs | 38 - .../Classes/Messages/MessageAttributeTest.cs | 62 - .../Classes/Messages/MessageTest.cs | 49 - .../Messages/Transport/DebugMessageTest.cs | 25 - .../Transport/DisconnectMessageTest.cs | 39 - .../KeyExchangeDhGroupExchangeGroupTest.cs | 26 - .../Transport/KeyExchangeDhInitMessageTest.cs | 13 - .../KeyExchangeDhReplyMessageTest.cs | 26 - .../Transport/KeyExchangeInitMessageTest.cs | 193 +-- .../Messages/Transport/NewKeysMessageTest.cs | 26 - .../Transport/ServiceAcceptMessageTest.cs | 25 - .../Transport/ServiceRequestMessageTest.cs | 27 - .../Transport/UnimplementedMessageTest.cs | 25 - .../Classes/NetConfClientTest.cs | 168 +-- .../Classes/NoneAuthenticationMethodTest.cs | 44 +- .../PasswordAuthenticationMethodTest.cs | 73 - .../Classes/PasswordConnectionInfoTest.cs | 276 ---- .../PrivateKeyAuthenticationMethodTest.cs | 62 +- .../Classes/PrivateKeyConnectionInfoTest.cs | 167 --- .../Classes/ScpClientTest.cs | 124 -- .../Classes/Security/AlgorithmTest.cs | 34 - .../Security/CertificateHostAlgorithmTest.cs | 75 - .../CipherDigitalSignatureTest.cs | 54 - .../Security/Cryptography/CipherTest.cs | 53 - .../Cryptography/Ciphers/AesCipherTest.cs | 60 - .../Cryptography/Ciphers/Arc4CipherTest.cs | 54 - .../Ciphers/BlowfishCipherTest.cs | 59 - .../Cryptography/Ciphers/CastCipherTest.cs | 60 - .../Cryptography/Ciphers/CipherModeTest.cs | 61 - .../Cryptography/Ciphers/CipherPaddingTest.cs | 38 - .../Ciphers/Modes/CbcCipherModeTest.cs | 67 - .../Ciphers/Modes/CfbCipherModeTest.cs | 68 - .../Ciphers/Modes/CtrCipherModeTest.cs | 68 - .../Ciphers/Modes/OfbCipherModeTest.cs | 68 - .../Cryptography/Ciphers/RsaCipherTest.cs | 60 - .../Cryptography/Ciphers/SerpentCipherTest.cs | 73 - .../Ciphers/TripleDesCipherTest.cs | 60 - .../Cryptography/Ciphers/TwofishCipherTest.cs | 73 - .../Cryptography/DigitalSignatureTest.cs | 54 - .../Cryptography/DsaDigitalSignatureTest.cs | 72 - .../Security/Cryptography/DsaKeyTest.cs | 160 --- .../Cryptography/RsaDigitalSignatureTest.cs | 13 - .../Security/Cryptography/RsaKeyTest.cs | 13 - .../Cryptography/SymmetricCipherTest.cs | 60 - .../Classes/Security/HostAlgorithmTest.cs | 67 - ...hangeDiffieHellmanGroupExchangeSha1Test.cs | 13 - ...ngeDiffieHellmanGroupExchangeSha256Test.cs | 65 - .../KeyExchangeDiffieHellmanGroupSha1Test.cs | 62 - .../Security/KeyExchangeDiffieHellmanTest.cs | 36 - .../Classes/Security/KeyExchangeTest.cs | 16 - .../Classes/Security/KeyTest.cs | 84 -- .../Classes/Sftp/SftpFileAttributesTest.cs | 238 ---- ...am_OriginBeginAndOffsetZero_NoBuffering.cs | 1 - ...eam_OriginBeginAndOffsetZero_ReadBuffer.cs | 1 - .../Sftp/SftpFileSystemInformationTest.cs | 62 - .../Classes/Sftp/SftpFileTest.cs | 510 ------- .../Sftp/SftpListDirectoryAsyncResultTest.cs | 28 - ...tpSynchronizeDirectoriesAsyncResultTest.cs | 28 - .../Classes/Sftp/SftpUploadAsyncResultTest.cs | 28 - .../Classes/SftpClientTest.cs | 1210 ----------------- .../Classes/ShellTestTest.cs | 82 -- .../Classes/SshClientTest.cs | 355 ----- .../Classes/SshCommandTest.cs | 126 -- src/Renci.SshNet/Properties/AssemblyInfo.cs | 1 + 121 files changed, 34 insertions(+), 7848 deletions(-) create mode 100644 src/Renci.SshNet.Benchmarks/Common/ExtensionsBenchmarks.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/CipherInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Common/AsyncResultTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Common/DerDataTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Compression/CompressorTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Compression/ZlibOpenSshTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Compression/ZlibStreamTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Compression/ZlibTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/KeyboardInteractiveConnectionInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/MessageEventArgsTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Authentication/BannerMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Authentication/FailureMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Authentication/InformationRequestMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Authentication/InformationResponseMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Authentication/PasswordChangeRequiredMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Authentication/PublicKeyMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessageHostTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessageKeyboardInteractiveTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessageNoneTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessagePasswordTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessagePublicKeyTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Authentication/SuccessMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelCloseMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelEofMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelExtendedDataMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelFailureMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/DirectTcpipChannelInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/SessionChannelOpenInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/X11ChannelOpenInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenConfirmationMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenFailureMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/BreakRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ChannelRequestMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/EndOfWriteRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ExecRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ExitSignalRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ExitStatusRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/KeepAliveRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ShellRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/SignalRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/SubsystemRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/WindowChangeRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/X11ForwardingRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/XonXoffRequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelSuccessMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelWindowAdjustMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestFailureMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestSuccessMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/MessageAttributeTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/MessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Transport/DebugMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Transport/DisconnectMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhInitMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhReplyMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Transport/NewKeysMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceAcceptMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceRequestMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Messages/Transport/UnimplementedMessageTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/PrivateKeyConnectionInfoTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/AlgorithmTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/CertificateHostAlgorithmTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/CipherDigitalSignatureTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/CipherTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CipherModeTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CipherPaddingTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/CbcCipherModeTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/CfbCipherModeTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/CtrCipherModeTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/OfbCipherModeTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/RsaCipherTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/SerpentCipherTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TwofishCipherTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/DigitalSignatureTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/DsaDigitalSignatureTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/DsaKeyTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaKeyTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/Cryptography/SymmetricCipherTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/HostAlgorithmTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupExchangeSha1Test.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupExchangeSha256Test.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupSha1Test.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/KeyExchangeTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Security/KeyTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Sftp/SftpFileAttributesTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Sftp/SftpFileSystemInformationTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Sftp/SftpFileTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Sftp/SftpListDirectoryAsyncResultTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Sftp/SftpSynchronizeDirectoriesAsyncResultTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/Sftp/SftpUploadAsyncResultTest.cs delete mode 100644 src/Renci.SshNet.Tests/Classes/ShellTestTest.cs diff --git a/src/Renci.SshNet.Benchmarks/Common/ExtensionsBenchmarks.cs b/src/Renci.SshNet.Benchmarks/Common/ExtensionsBenchmarks.cs new file mode 100644 index 000000000..547c20d6a --- /dev/null +++ b/src/Renci.SshNet.Benchmarks/Common/ExtensionsBenchmarks.cs @@ -0,0 +1,27 @@ +锘縰sing BenchmarkDotNet.Attributes; + +using Renci.SshNet.Common; + +namespace Renci.SshNet.Benchmarks.Common +{ + public class ExtensionsBenchmarks + { + private byte[]? _data; + + [Params(1000, 10000)] + public int N; + + [GlobalSetup] + public void Setup() + { + _data = new byte[N]; + new Random(42).NextBytes(_data); + } + + [Benchmark] + public byte[] Reverse() + { + return _data.Reverse(); + } + } +} diff --git a/src/Renci.SshNet.Tests/Classes/CipherInfoTest.cs b/src/Renci.SshNet.Tests/Classes/CipherInfoTest.cs deleted file mode 100644 index 832c92f8b..000000000 --- a/src/Renci.SshNet.Tests/Classes/CipherInfoTest.cs +++ /dev/null @@ -1,29 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Security.Cryptography; -using Renci.SshNet.Tests.Common; - -using System; - -namespace Renci.SshNet.Tests.Classes -{ - /// - /// Holds information about key size and cipher to use - /// - [TestClass] - public class CipherInfoTest : TestBase - { - /// - ///A test for CipherInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void CipherInfoConstructorTest() - { - var keySize = 0; // TODO: Initialize to an appropriate value - Func cipher = null; // TODO: Initialize to an appropriate value - var target = new CipherInfo(keySize, cipher); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Common/AsyncResultTest.cs b/src/Renci.SshNet.Tests/Classes/Common/AsyncResultTest.cs deleted file mode 100644 index 5a972e69f..000000000 --- a/src/Renci.SshNet.Tests/Classes/Common/AsyncResultTest.cs +++ /dev/null @@ -1,136 +0,0 @@ -锘縰sing System; - -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for AsyncResultTest and is intended - ///to contain all AsyncResultTest Unit Tests - /// - [TestClass] - [Ignore] // placeholder for actual test - public class AsyncResultTest : TestBase - { - /// - ///A test for EndInvoke - /// - public void EndInvokeTest1Helper() - { - var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - var expected = default(TResult); // TODO: Initialize to an appropriate value - var actual = target.EndInvoke(); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - internal virtual AsyncResult CreateAsyncResult() - { - // TODO: Instantiate an appropriate concrete class. - AsyncResult target = null; - return target; - } - - [TestMethod] - public void EndInvokeTest1() - { - EndInvokeTest1Helper(); - } - - /// - ///A test for SetAsCompleted - /// - public void SetAsCompletedTest1Helper() - { - var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - TResult result = default; // TODO: Initialize to an appropriate value - var completedSynchronously = false; // TODO: Initialize to an appropriate value - target.SetAsCompleted(result, completedSynchronously); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - [TestMethod] - public void SetAsCompletedTest1() - { - SetAsCompletedTest1Helper(); - } - - internal virtual AsyncResult CreateAsyncResult() - { - // TODO: Instantiate an appropriate concrete class. - AsyncResult target = null; - return target; - } - - /// - ///A test for EndInvoke - /// - [TestMethod] - public void EndInvokeTest() - { - var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - target.EndInvoke(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for SetAsCompleted - /// - [TestMethod] - public void SetAsCompletedTest() - { - var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - Exception exception = null; // TODO: Initialize to an appropriate value - var completedSynchronously = false; // TODO: Initialize to an appropriate value - target.SetAsCompleted(exception, completedSynchronously); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for AsyncState - /// - [TestMethod] - public void AsyncStateTest() - { - var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - var actual = target.AsyncState; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for AsyncWaitHandle - /// - [TestMethod] - public void AsyncWaitHandleTest() - { - var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - var actual = target.AsyncWaitHandle; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CompletedSynchronously - /// - [TestMethod] - public void CompletedSynchronouslyTest() - { - var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - var actual = target.CompletedSynchronously; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for IsCompleted - /// - [TestMethod] - public void IsCompletedTest() - { - var target = CreateAsyncResult(); // TODO: Initialize to an appropriate value - var actual = target.IsCompleted; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Common/DerDataTest.cs b/src/Renci.SshNet.Tests/Classes/Common/DerDataTest.cs deleted file mode 100644 index d0f567909..000000000 --- a/src/Renci.SshNet.Tests/Classes/Common/DerDataTest.cs +++ /dev/null @@ -1,173 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for DerDataTest and is intended - ///to contain all DerDataTest Unit Tests - /// - [TestClass] - [Ignore] // placeholder for actual test - public class DerDataTest : TestBase - { - /// - ///A test for DerData Constructor - /// - [TestMethod] - public void DerDataConstructorTest() - { - DerData target = new DerData(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for DerData Constructor - /// - [TestMethod] - public void DerDataConstructorTest1() - { - byte[] data = null; // TODO: Initialize to an appropriate value - DerData target = new DerData(data); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for Encode - /// - [TestMethod] - public void EncodeTest() - { - DerData target = new DerData(); // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Encode(); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ReadBigInteger - /// - [TestMethod] - public void ReadBigIntegerTest() - { - DerData target = new DerData(); // TODO: Initialize to an appropriate value - BigInteger expected = new BigInteger(); // TODO: Initialize to an appropriate value - BigInteger actual; - actual = target.ReadBigInteger(); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ReadInteger - /// - [TestMethod] - public void ReadIntegerTest() - { - DerData target = new DerData(); // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.ReadInteger(); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Write - /// - [TestMethod] - public void WriteTest() - { - DerData target = new DerData(); // TODO: Initialize to an appropriate value - bool data = false; // TODO: Initialize to an appropriate value - target.Write(data); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Write - /// - [TestMethod] - public void WriteTest1() - { - DerData target = new DerData(); // TODO: Initialize to an appropriate value - uint data = 0; // TODO: Initialize to an appropriate value - target.Write(data); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Write - /// - [TestMethod] - public void WriteTest2() - { - DerData target = new DerData(); // TODO: Initialize to an appropriate value - BigInteger data = new BigInteger(); // TODO: Initialize to an appropriate value - target.Write(data); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Write - /// - [TestMethod] - public void WriteTest3() - { - DerData target = new DerData(); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - target.Write(data); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Write - /// - [TestMethod] - public void WriteTest4() - { - DerData target = new DerData(); // TODO: Initialize to an appropriate value - ObjectIdentifier identifier = new ObjectIdentifier(); // TODO: Initialize to an appropriate value - target.Write(identifier); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Write - /// - [TestMethod] - public void WriteTest5() - { - DerData target = new DerData(); // TODO: Initialize to an appropriate value - DerData data = null; // TODO: Initialize to an appropriate value - target.Write(data); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for WriteNull - /// - [TestMethod] - public void WriteNullTest() - { - DerData target = new DerData(); // TODO: Initialize to an appropriate value - target.WriteNull(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for IsEndOfData - /// - [TestMethod] - public void IsEndOfDataTest() - { - DerData target = new DerData(); // TODO: Initialize to an appropriate value - bool actual; - actual = target.IsEndOfData; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Reverse.cs b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Reverse.cs index 3088d254c..32727ab75 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Reverse.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Reverse.cs @@ -1,5 +1,4 @@ 锘縰sing System; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; @@ -21,7 +20,7 @@ public void Empty() Assert.AreEqual(0, actual.Length); } - [TestInitialize] + [TestMethod] public void Null() { const byte[] value = null; @@ -61,24 +60,6 @@ public void Small() Assert.AreEqual(1, value[4]); Assert.AreEqual(0, value[5]); } - - [TestMethod] - [Ignore] - public void Perf_Large() - { - var value = new byte[2048]; - new Random().NextBytes(value); - - var stopwatch = Stopwatch.StartNew(); - - for (var i = 0; i < 1000000; i++) - { - Extensions.Reverse(value); - } - - stopwatch.Stop(); - Console.WriteLine(stopwatch.ElapsedMilliseconds); - } } } diff --git a/src/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs b/src/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs index 2a305fcb9..ccb2a643a 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs @@ -1,5 +1,4 @@ 锘縰sing System; -using System.Runtime.Serialization; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -61,19 +60,5 @@ public void SshConnectionExceptionConstructorTest3() var target = new SshConnectionException(message, disconnectReasonCode, inner); Assert.Inconclusive("TODO: Implement code to verify target"); } - - /// - ///A test for GetObjectData - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GetObjectDataTest() - { - var target = new SshConnectionException(); // TODO: Initialize to an appropriate value - SerializationInfo info = null; // TODO: Initialize to an appropriate value - var context = new StreamingContext(); // TODO: Initialize to an appropriate value - target.GetObjectData(info, context); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } } } diff --git a/src/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs b/src/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs index 435845086..ebf5ca894 100644 --- a/src/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs @@ -1,5 +1,4 @@ 锘縰sing System; -using System.Runtime.Serialization; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; using Renci.SshNet.Tests.Common; @@ -45,19 +44,5 @@ public void SshExceptionConstructorTest2() SshException target = new SshException(message, inner); Assert.Inconclusive("TODO: Implement code to verify target"); } - - /// - ///A test for GetObjectData - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GetObjectDataTest() - { - SshException target = new SshException(); // TODO: Initialize to an appropriate value - SerializationInfo info = null; // TODO: Initialize to an appropriate value - StreamingContext context = new StreamingContext(); // TODO: Initialize to an appropriate value - target.GetObjectData(info, context); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } } } diff --git a/src/Renci.SshNet.Tests/Classes/Compression/CompressorTest.cs b/src/Renci.SshNet.Tests/Classes/Compression/CompressorTest.cs deleted file mode 100644 index 9a94f6dc6..000000000 --- a/src/Renci.SshNet.Tests/Classes/Compression/CompressorTest.cs +++ /dev/null @@ -1,75 +0,0 @@ -锘縰sing Renci.SshNet.Compression; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Compression -{ - /// - ///This is a test class for CompressorTest and is intended - ///to contain all CompressorTest Unit Tests - /// - [TestClass] - [Ignore] // placeholders only - public class CompressorTest : TestBase - { - internal virtual Compressor CreateCompressor() - { - // TODO: Instantiate an appropriate concrete class. - Compressor target = null; - return target; - } - - /// - ///A test for Compress - /// - [TestMethod()] - public void CompressTest() - { - Compressor target = CreateCompressor(); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Compress(data); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Decompress - /// - [TestMethod()] - public void DecompressTest() - { - Compressor target = CreateCompressor(); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Decompress(data); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Dispose - /// - [TestMethod()] - public void DisposeTest() - { - Compressor target = CreateCompressor(); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Init - /// - [TestMethod()] - public void InitTest() - { - Compressor target = CreateCompressor(); // TODO: Initialize to an appropriate value - Session session = null; // TODO: Initialize to an appropriate value - target.Init(session); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Compression/ZlibOpenSshTest.cs b/src/Renci.SshNet.Tests/Classes/Compression/ZlibOpenSshTest.cs deleted file mode 100644 index b3e166501..000000000 --- a/src/Renci.SshNet.Tests/Classes/Compression/ZlibOpenSshTest.cs +++ /dev/null @@ -1,49 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Compression; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Compression -{ - /// - ///This is a test class for ZlibOpenSshTest and is intended - ///to contain all ZlibOpenSshTest Unit Tests - /// - [TestClass] - [Ignore] // placeholders only - public class ZlibOpenSshTest : TestBase - { - /// - ///A test for ZlibOpenSsh Constructor - /// - [TestMethod()] - public void ZlibOpenSshConstructorTest() - { - var target = new ZlibOpenSsh(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for Init - /// - [TestMethod()] - public void InitTest() - { - var target = new ZlibOpenSsh(); // TODO: Initialize to an appropriate value - Session session = null; // TODO: Initialize to an appropriate value - target.Init(session); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Name - /// - [TestMethod()] - public void NameTest() - { - var target = new ZlibOpenSsh(); // TODO: Initialize to an appropriate value - var actual = target.Name; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Compression/ZlibStreamTest.cs b/src/Renci.SshNet.Tests/Classes/Compression/ZlibStreamTest.cs deleted file mode 100644 index 6ee6236c2..000000000 --- a/src/Renci.SshNet.Tests/Classes/Compression/ZlibStreamTest.cs +++ /dev/null @@ -1,47 +0,0 @@ -锘縰sing System.IO; - -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Compression; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Compression -{ - /// - ///This is a test class for ZlibStreamTest and is intended - ///to contain all ZlibStreamTest Unit Tests - /// - [TestClass] - public class ZlibStreamTest : TestBase - { - /// - ///A test for ZlibStream Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ZlibStreamConstructorTest() - { - Stream stream = null; // TODO: Initialize to an appropriate value - var mode = new CompressionMode(); // TODO: Initialize to an appropriate value - var target = new ZlibStream(stream, mode); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for Write - /// - [TestMethod] - [Ignore] // placeholder - public void WriteTest() - { - Stream stream = null; // TODO: Initialize to an appropriate value - var mode = new CompressionMode(); // TODO: Initialize to an appropriate value - var target = new ZlibStream(stream, mode); // TODO: Initialize to an appropriate value - byte[] buffer = null; // TODO: Initialize to an appropriate value - var offset = 0; // TODO: Initialize to an appropriate value - var count = 0; // TODO: Initialize to an appropriate value - target.Write(buffer, offset, count); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Compression/ZlibTest.cs b/src/Renci.SshNet.Tests/Classes/Compression/ZlibTest.cs deleted file mode 100644 index d460b3eb4..000000000 --- a/src/Renci.SshNet.Tests/Classes/Compression/ZlibTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Compression -{ - /// - /// Represents "zlib" compression implementation - /// - [TestClass] - public class ZlibTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs index be6adef7b..b18e4ab57 100644 --- a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs @@ -12,21 +12,6 @@ namespace Renci.SshNet.Tests.Classes [TestClass] public partial class ForwardedPortRemoteTest : TestBase { - /// - ///A test for Stop - /// - [TestMethod] - [Ignore] // placeholder - public void StopTest() - { - uint boundPort = 0; // TODO: Initialize to an appropriate value - var host = string.Empty; // TODO: Initialize to an appropriate value - uint port = 0; // TODO: Initialize to an appropriate value - var target = new ForwardedPortRemote(boundPort, host, port); // TODO: Initialize to an appropriate value - target.Stop(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - [TestMethod] public void Start_NotAddedToClient() { @@ -46,49 +31,5 @@ public void Start_NotAddedToClient() Assert.AreEqual("Forwarded port is not added to a client.", ex.Message); } } - - /// - ///A test for Dispose - /// - [TestMethod] - [Ignore] // placeholder - public void DisposeTest() - { - uint boundPort = 0; // TODO: Initialize to an appropriate value - var host = string.Empty; // TODO: Initialize to an appropriate value - uint port = 0; // TODO: Initialize to an appropriate value - var target = new ForwardedPortRemote(boundPort, host, port); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for ForwardedPortRemote Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ForwardedPortRemoteConstructorTest() - { - var boundHost = string.Empty; // TODO: Initialize to an appropriate value - uint boundPort = 0; // TODO: Initialize to an appropriate value - var host = string.Empty; // TODO: Initialize to an appropriate value - uint port = 0; // TODO: Initialize to an appropriate value - var target = new ForwardedPortRemote(boundHost, boundPort, host, port); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ForwardedPortRemote Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ForwardedPortRemoteConstructorTest1() - { - uint boundPort = 0; // TODO: Initialize to an appropriate value - var host = string.Empty; // TODO: Initialize to an appropriate value - uint port = 0; // TODO: Initialize to an appropriate value - var target = new ForwardedPortRemote(boundPort, host, port); - Assert.Inconclusive("TODO: Implement code to verify target"); - } } } diff --git a/src/Renci.SshNet.Tests/Classes/KeyboardInteractiveAuthenticationMethodTest.cs b/src/Renci.SshNet.Tests/Classes/KeyboardInteractiveAuthenticationMethodTest.cs index b85b88a8c..2940388d1 100644 --- a/src/Renci.SshNet.Tests/Classes/KeyboardInteractiveAuthenticationMethodTest.cs +++ b/src/Renci.SshNet.Tests/Classes/KeyboardInteractiveAuthenticationMethodTest.cs @@ -29,61 +29,5 @@ public void Keyboard_Test_Pass_Whitespace() { new KeyboardInteractiveAuthenticationMethod(string.Empty); } - - /// - ///A test for Name - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void NameTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - KeyboardInteractiveAuthenticationMethod target = new KeyboardInteractiveAuthenticationMethod(username); // TODO: Initialize to an appropriate value - string actual; - actual = target.Name; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Dispose - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DisposeTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - KeyboardInteractiveAuthenticationMethod target = new KeyboardInteractiveAuthenticationMethod(username); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Authenticate - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AuthenticateTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - KeyboardInteractiveAuthenticationMethod target = new KeyboardInteractiveAuthenticationMethod(username); // TODO: Initialize to an appropriate value - Session session = null; // TODO: Initialize to an appropriate value - AuthenticationResult expected = new AuthenticationResult(); // TODO: Initialize to an appropriate value - AuthenticationResult actual; - actual = target.Authenticate(session); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for KeyboardInteractiveAuthenticationMethod Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyboardInteractiveAuthenticationMethodConstructorTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - KeyboardInteractiveAuthenticationMethod target = new KeyboardInteractiveAuthenticationMethod(username); - Assert.Inconclusive("TODO: Implement code to verify target"); - } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/KeyboardInteractiveConnectionInfoTest.cs b/src/Renci.SshNet.Tests/Classes/KeyboardInteractiveConnectionInfoTest.cs deleted file mode 100644 index f50aaf9b7..000000000 --- a/src/Renci.SshNet.Tests/Classes/KeyboardInteractiveConnectionInfoTest.cs +++ /dev/null @@ -1,159 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes -{ - /// - /// Provides connection information when keyboard interactive authentication method is used - /// - [TestClass] - public class KeyboardInteractiveConnectionInfoTest : TestBase - { - /// - ///A test for Dispose - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DisposeTest() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - KeyboardInteractiveConnectionInfo target = new KeyboardInteractiveConnectionInfo(host, username); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for KeyboardInteractiveConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyboardInteractiveConnectionInfoConstructorTest() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - string proxyPassword = string.Empty; // TODO: Initialize to an appropriate value - KeyboardInteractiveConnectionInfo target = new KeyboardInteractiveConnectionInfo(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for KeyboardInteractiveConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyboardInteractiveConnectionInfoConstructorTest1() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - string proxyPassword = string.Empty; // TODO: Initialize to an appropriate value - KeyboardInteractiveConnectionInfo target = new KeyboardInteractiveConnectionInfo(host, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for KeyboardInteractiveConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyboardInteractiveConnectionInfoConstructorTest2() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - KeyboardInteractiveConnectionInfo target = new KeyboardInteractiveConnectionInfo(host, username, proxyType, proxyHost, proxyPort, proxyUsername); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for KeyboardInteractiveConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyboardInteractiveConnectionInfoConstructorTest3() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - KeyboardInteractiveConnectionInfo target = new KeyboardInteractiveConnectionInfo(host, username, proxyType, proxyHost, proxyPort); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for KeyboardInteractiveConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyboardInteractiveConnectionInfoConstructorTest4() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - KeyboardInteractiveConnectionInfo target = new KeyboardInteractiveConnectionInfo(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for KeyboardInteractiveConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyboardInteractiveConnectionInfoConstructorTest5() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - KeyboardInteractiveConnectionInfo target = new KeyboardInteractiveConnectionInfo(host, port, username, proxyType, proxyHost, proxyPort); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for KeyboardInteractiveConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyboardInteractiveConnectionInfoConstructorTest6() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - KeyboardInteractiveConnectionInfo target = new KeyboardInteractiveConnectionInfo(host, port, username); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for KeyboardInteractiveConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyboardInteractiveConnectionInfoConstructorTest7() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - KeyboardInteractiveConnectionInfo target = new KeyboardInteractiveConnectionInfo(host, username); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/MessageEventArgsTest.cs b/src/Renci.SshNet.Tests/Classes/MessageEventArgsTest.cs deleted file mode 100644 index da6ab8517..000000000 --- a/src/Renci.SshNet.Tests/Classes/MessageEventArgsTest.cs +++ /dev/null @@ -1,29 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes -{ - /// - /// Provides data for message events. - /// - [TestClass] - public class MessageEventArgsTest : TestBase - { - /// - ///A test for MessageEventArgs`1 Constructor - /// - public void MessageEventArgsConstructorTestHelper() - { - T message = default; // TODO: Initialize to an appropriate value - var target = new MessageEventArgs(message); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - [TestMethod] - [Ignore] // placeholder for actual test - public void MessageEventArgsConstructorTest() - { - MessageEventArgsConstructorTestHelper(); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/BannerMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/BannerMessageTest.cs deleted file mode 100644 index 0c1021351..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/BannerMessageTest.cs +++ /dev/null @@ -1,25 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Messages.Authentication; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Authentication -{ - /// - ///This is a test class for BannerMessageTest and is intended - ///to contain all BannerMessageTest Unit Tests - /// - [TestClass] - public class BannerMessageTest : TestBase - { - /// - ///A test for BannerMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void BannerMessageConstructorTest() - { - BannerMessage target = new BannerMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/FailureMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/FailureMessageTest.cs deleted file mode 100644 index 979b1d750..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/FailureMessageTest.cs +++ /dev/null @@ -1,42 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Authentication; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Messages.Authentication -{ - /// - ///This is a test class for FailureMessageTest and is intended - ///to contain all FailureMessageTest Unit Tests - /// - [TestClass] - public class FailureMessageTest : TestBase - { - /// - ///A test for FailureMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void FailureMessageConstructorTest() - { - var target = new FailureMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for AllowedAuthentications - /// - [TestMethod] - [Ignore] // placeholder - public void AllowedAuthenticationsTest() - { - var target = new FailureMessage(); // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - string[] actual; - target.AllowedAuthentications = expected; - actual = target.AllowedAuthentications; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/InformationRequestMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/InformationRequestMessageTest.cs deleted file mode 100644 index 31dbd4e6e..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/InformationRequestMessageTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Messages.Authentication -{ - /// - /// Represents SSH_MSG_USERAUTH_INFO_REQUEST message. - /// - [TestClass] - public class InformationRequestMessageTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/InformationResponseMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/InformationResponseMessageTest.cs deleted file mode 100644 index f5d0f0ae3..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/InformationResponseMessageTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Messages.Authentication -{ - /// - /// Represents SSH_MSG_USERAUTH_INFO_RESPONSE message. - /// - [TestClass] - public class InformationResponseMessageTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/PasswordChangeRequiredMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/PasswordChangeRequiredMessageTest.cs deleted file mode 100644 index 3d876373f..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/PasswordChangeRequiredMessageTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Messages.Authentication -{ - /// - /// Represents SSH_MSG_USERAUTH_PASSWD_CHANGEREQ message. - /// - [TestClass] - public class PasswordChangeRequiredMessageTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/PublicKeyMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/PublicKeyMessageTest.cs deleted file mode 100644 index 1ab453989..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/PublicKeyMessageTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Messages.Authentication -{ - /// - /// Represents SSH_MSG_USERAUTH_PK_OK message. - /// - [TestClass] - public class PublicKeyMessageTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessageHostTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessageHostTest.cs deleted file mode 100644 index e50ee295e..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessageHostTest.cs +++ /dev/null @@ -1,11 +0,0 @@ -锘縰sing Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Messages.Authentication -{ - /// - /// Represents "hostbased" SSH_MSG_USERAUTH_REQUEST message. - /// - public class RequestMessageHostTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessageKeyboardInteractiveTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessageKeyboardInteractiveTest.cs deleted file mode 100644 index b038ed9d9..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessageKeyboardInteractiveTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Messages.Authentication -{ - /// - /// Represents "keyboard-interactive" SSH_MSG_USERAUTH_REQUEST message. - /// - [TestClass] - public class RequestMessageKeyboardInteractiveTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessageNoneTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessageNoneTest.cs deleted file mode 100644 index cfae6875a..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessageNoneTest.cs +++ /dev/null @@ -1,11 +0,0 @@ -锘縰sing Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Messages.Authentication -{ - /// - /// Represents "none" SSH_MSG_USERAUTH_REQUEST message. - /// - public class RequestMessageNoneTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessagePasswordTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessagePasswordTest.cs deleted file mode 100644 index 47ca635d1..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessagePasswordTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Messages.Authentication -{ - /// - /// Represents "password" SSH_MSG_USERAUTH_REQUEST message. - /// - [TestClass] - public class RequestMessagePasswordTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessagePublicKeyTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessagePublicKeyTest.cs deleted file mode 100644 index fb4e36af1..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/RequestMessagePublicKeyTest.cs +++ /dev/null @@ -1,82 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages; -using Renci.SshNet.Messages.Authentication; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Messages.Authentication -{ - /// - ///This is a test class for RequestMessagePublicKeyTest and is intended - ///to contain all RequestMessagePublicKeyTest Unit Tests - /// - [TestClass()] - public class RequestMessagePublicKeyTest : TestBase - { - /// - ///A test for RequestMessagePublicKey Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void RequestMessagePublicKeyConstructorTest() - { - var serviceName = new ServiceName(); // TODO: Initialize to an appropriate value - var username = string.Empty; // TODO: Initialize to an appropriate value - var keyAlgorithmName = string.Empty; // TODO: Initialize to an appropriate value - byte[] keyData = null; // TODO: Initialize to an appropriate value - var target = new RequestMessagePublicKey(serviceName, username, keyAlgorithmName, keyData); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for RequestMessagePublicKey Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void RequestMessagePublicKeyConstructorTest1() - { - var serviceName = new ServiceName(); // TODO: Initialize to an appropriate value - var username = string.Empty; // TODO: Initialize to an appropriate value - var keyAlgorithmName = string.Empty; // TODO: Initialize to an appropriate value - byte[] keyData = null; // TODO: Initialize to an appropriate value - byte[] signature = null; // TODO: Initialize to an appropriate value - var target = new RequestMessagePublicKey(serviceName, username, keyAlgorithmName, keyData, signature); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for MethodName - /// - [TestMethod] - [Ignore] // placeholder - public void MethodNameTest() - { - var serviceName = new ServiceName(); // TODO: Initialize to an appropriate value - var username = string.Empty; // TODO: Initialize to an appropriate value - var keyAlgorithmName = string.Empty; // TODO: Initialize to an appropriate value - byte[] keyData = null; // TODO: Initialize to an appropriate value - var target = new RequestMessagePublicKey(serviceName, username, keyAlgorithmName, keyData); // TODO: Initialize to an appropriate value - var actual = target.MethodName; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Signature - /// - [TestMethod] - [Ignore] // placeholder - public void SignatureTest() - { - var serviceName = new ServiceName(); // TODO: Initialize to an appropriate value - var username = string.Empty; // TODO: Initialize to an appropriate value - var keyAlgorithmName = string.Empty; // TODO: Initialize to an appropriate value - byte[] keyData = null; // TODO: Initialize to an appropriate value - var target = new RequestMessagePublicKey(serviceName, username, keyAlgorithmName, keyData); // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - target.Signature = expected; - var actual = target.Signature; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/SuccessMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Authentication/SuccessMessageTest.cs deleted file mode 100644 index 24cdbe3c3..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Authentication/SuccessMessageTest.cs +++ /dev/null @@ -1,25 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Messages.Authentication; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Authentication -{ - /// - ///This is a test class for SuccessMessageTest and is intended - ///to contain all SuccessMessageTest Unit Tests - /// - [TestClass()] - public class SuccessMessageTest : TestBase - { - /// - ///A test for SuccessMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void SuccessMessageConstructorTest() - { - SuccessMessage target = new SuccessMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelCloseMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelCloseMessageTest.cs deleted file mode 100644 index 995981a60..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelCloseMessageTest.cs +++ /dev/null @@ -1,37 +0,0 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for ChannelCloseMessageTest and is intended - ///to contain all ChannelCloseMessageTest Unit Tests - /// - [TestClass] - public class ChannelCloseMessageTest : TestBase - { - /// - ///A test for ChannelCloseMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelCloseMessageConstructorTest() - { - var target = new ChannelCloseMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ChannelCloseMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelCloseMessageConstructorTest1() - { - uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - var target = new ChannelCloseMessage(localChannelNumber); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelEofMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelEofMessageTest.cs deleted file mode 100644 index ad2becd89..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelEofMessageTest.cs +++ /dev/null @@ -1,37 +0,0 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for ChannelEofMessageTest and is intended - ///to contain all ChannelEofMessageTest Unit Tests - /// - [TestClass] - public class ChannelEofMessageTest : TestBase - { - /// - ///A test for ChannelEofMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelEofMessageConstructorTest() - { - var target = new ChannelEofMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ChannelEofMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelEofMessageConstructorTest1() - { - uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - var target = new ChannelEofMessage(localChannelNumber); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelExtendedDataMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelExtendedDataMessageTest.cs deleted file mode 100644 index 65e3dbcc7..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelExtendedDataMessageTest.cs +++ /dev/null @@ -1,38 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for ChannelExtendedDataMessageTest and is intended - ///to contain all ChannelExtendedDataMessageTest Unit Tests - /// - [TestClass] - public class ChannelExtendedDataMessageTest : TestBase - { - /// - ///A test for ChannelExtendedDataMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelExtendedDataMessageConstructorTest() - { - var target = new ChannelExtendedDataMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ChannelExtendedDataMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelExtendedDataMessageConstructorTest1() - { - //uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - //ChannelExtendedDataMessage target = new ChannelExtendedDataMessage(localChannelNumber, null, null); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelFailureMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelFailureMessageTest.cs deleted file mode 100644 index 070df2a68..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelFailureMessageTest.cs +++ /dev/null @@ -1,38 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for ChannelFailureMessageTest and is intended - ///to contain all ChannelFailureMessageTest Unit Tests - /// - [TestClass] - public class ChannelFailureMessageTest : TestBase - { - /// - ///A test for ChannelFailureMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelFailureMessageConstructorTest() - { - var target = new ChannelFailureMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ChannelFailureMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelFailureMessageConstructorTest1() - { - uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - var target = new ChannelFailureMessage(localChannelNumber); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelMessageTest.cs deleted file mode 100644 index 53c56cf7f..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelMessageTest.cs +++ /dev/null @@ -1,36 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for ChannelMessageTest and is intended - ///to contain all ChannelMessageTest Unit Tests - /// - [TestClass] - [Ignore] // placeholders only - public class ChannelMessageTest : TestBase - { - internal virtual ChannelMessage CreateChannelMessage() - { - // TODO: Instantiate an appropriate concrete class. - ChannelMessage target = null; - return target; - } - - /// - ///A test for ToString - /// - [TestMethod()] - public void ToStringTest() - { - var target = CreateChannelMessage(); // TODO: Initialize to an appropriate value - var expected = string.Empty; // TODO: Initialize to an appropriate value - var actual = target.ToString(); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/DirectTcpipChannelInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/DirectTcpipChannelInfoTest.cs deleted file mode 100644 index 8cda173bd..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/DirectTcpipChannelInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Used to open "direct-tcpip" channel type - /// - [TestClass] - public class DirectTcpipChannelInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfoTest.cs deleted file mode 100644 index df38576a6..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Used to open "forwarded-tcpip" channel type - /// - [TestClass] - public class ForwardedTcpipChannelInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/SessionChannelOpenInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/SessionChannelOpenInfoTest.cs deleted file mode 100644 index f647ed5ce..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/SessionChannelOpenInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Used to open "session" channel type - /// - [TestClass] - public class SessionChannelOpenInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/X11ChannelOpenInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/X11ChannelOpenInfoTest.cs deleted file mode 100644 index 44f348292..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/X11ChannelOpenInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Used to open "x11" channel type - /// - [TestClass] - public class X11ChannelOpenInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenConfirmationMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenConfirmationMessageTest.cs deleted file mode 100644 index 3ad44b48f..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenConfirmationMessageTest.cs +++ /dev/null @@ -1,41 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for ChannelOpenConfirmationMessageTest and is intended - ///to contain all ChannelOpenConfirmationMessageTest Unit Tests - /// - [TestClass] - public class ChannelOpenConfirmationMessageTest : TestBase - { - /// - ///A test for ChannelOpenConfirmationMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelOpenConfirmationMessageConstructorTest() - { - var target = new ChannelOpenConfirmationMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ChannelOpenConfirmationMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelOpenConfirmationMessageConstructorTest1() - { - uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - uint initialWindowSize = 0; // TODO: Initialize to an appropriate value - uint maximumPacketSize = 0; // TODO: Initialize to an appropriate value - uint remoteChannelNumber = 0; // TODO: Initialize to an appropriate value - var target = new ChannelOpenConfirmationMessage(localChannelNumber, initialWindowSize, maximumPacketSize, remoteChannelNumber); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenFailureMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenFailureMessageTest.cs deleted file mode 100644 index 848f81eda..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenFailureMessageTest.cs +++ /dev/null @@ -1,40 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for ChannelOpenFailureMessageTest and is intended - ///to contain all ChannelOpenFailureMessageTest Unit Tests - /// - [TestClass] - public class ChannelOpenFailureMessageTest : TestBase - { - /// - ///A test for ChannelOpenFailureMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelOpenFailureMessageConstructorTest() - { - var target = new ChannelOpenFailureMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ChannelOpenFailureMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelOpenFailureMessageConstructorTest1() - { - uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - var description = string.Empty; // TODO: Initialize to an appropriate value - uint reasonCode = 0; // TODO: Initialize to an appropriate value - var target = new ChannelOpenFailureMessage(localChannelNumber, description, reasonCode); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenInfoTest.cs deleted file mode 100644 index a28e17ed8..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpenInfoTest.cs +++ /dev/null @@ -1,34 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for ChannelOpenInfoTest and is intended - ///to contain all ChannelOpenInfoTest Unit Tests - /// - [TestClass] - [Ignore] // placeholders only - public class ChannelOpenInfoTest : TestBase - { - internal virtual ChannelOpenInfo CreateChannelOpenInfo() - { - // TODO: Instantiate an appropriate concrete class. - ChannelOpenInfo target = null; - return target; - } - - /// - ///A test for ChannelType - /// - [TestMethod()] - public void ChannelTypeTest() - { - var target = CreateChannelOpenInfo(); // TODO: Initialize to an appropriate value - var actual = target.ChannelType; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/BreakRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/BreakRequestInfoTest.cs deleted file mode 100644 index dd8d7b287..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/BreakRequestInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Represents "break" type channel request information - /// - [TestClass] - public class BreakRequestInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ChannelRequestMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ChannelRequestMessageTest.cs deleted file mode 100644 index 0c5599975..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ChannelRequestMessageTest.cs +++ /dev/null @@ -1,36 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Represents SSH_MSG_CHANNEL_REQUEST message. - /// - [TestClass] - [Ignore] // placeholders only - public class ChannelRequestMessageTest : TestBase - { - /// - ///A test for ChannelRequestMessage Constructor - /// - [TestMethod()] - public void ChannelRequestMessageConstructorTest() - { - ChannelRequestMessage target = new ChannelRequestMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ChannelRequestMessage Constructor - /// - [TestMethod()] - public void ChannelRequestMessageConstructorTest1() - { - uint localChannelName = 0; // TODO: Initialize to an appropriate value - RequestInfo info = null; // TODO: Initialize to an appropriate value - ChannelRequestMessage target = new ChannelRequestMessage(localChannelName, info); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/EndOfWriteRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/EndOfWriteRequestInfoTest.cs deleted file mode 100644 index 0573bade7..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/EndOfWriteRequestInfoTest.cs +++ /dev/null @@ -1,39 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for EndOfWriteRequestInfoTest and is intended - ///to contain all EndOfWriteRequestInfoTest Unit Tests - /// - [TestClass] - public class EndOfWriteRequestInfoTest : TestBase - { - /// - ///A test for EndOfWriteRequestInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void EndOfWriteRequestInfoConstructorTest() - { - var target = new EndOfWriteRequestInfo(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for RequestName - /// - [TestMethod] - [Ignore] // placeholder - public void RequestNameTest() - { - var target = new EndOfWriteRequestInfo(); // TODO: Initialize to an appropriate value - - var actual = target.RequestName; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfoTest.cs deleted file mode 100644 index 78899d9d2..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Represents "env" type channel request information - /// - [TestClass] - public class EnvironmentVariableRequestInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ExecRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ExecRequestInfoTest.cs deleted file mode 100644 index ed030011b..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ExecRequestInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Represents "exec" type channel request information - /// - [TestClass] - public class ExecRequestInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ExitSignalRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ExitSignalRequestInfoTest.cs deleted file mode 100644 index 81c00444e..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ExitSignalRequestInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Represents "exit-signal" type channel request information - /// - [TestClass] - public class ExitSignalRequestInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ExitStatusRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ExitStatusRequestInfoTest.cs deleted file mode 100644 index dd17e684d..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ExitStatusRequestInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Represents "exit-status" type channel request information - /// - [TestClass] - public class ExitStatusRequestInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/KeepAliveRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/KeepAliveRequestInfoTest.cs deleted file mode 100644 index 77b8cc927..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/KeepAliveRequestInfoTest.cs +++ /dev/null @@ -1,38 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for KeepAliveRequestInfoTest and is intended - ///to contain all KeepAliveRequestInfoTest Unit Tests - /// - [TestClass] - public class KeepAliveRequestInfoTest : TestBase - { - /// - ///A test for KeepAliveRequestInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void KeepAliveRequestInfoConstructorTest() - { - var target = new KeepAliveRequestInfo(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for RequestName - /// - [TestMethod] - [Ignore] // placeholder - public void RequestNameTest() - { - var target = new KeepAliveRequestInfo(); // TODO: Initialize to an appropriate value - var actual = target.RequestName; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ShellRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ShellRequestInfoTest.cs deleted file mode 100644 index 26ef2e97f..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/ShellRequestInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Represents "shell" type channel request information - /// - [TestClass] - public class ShellRequestInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/SignalRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/SignalRequestInfoTest.cs deleted file mode 100644 index 31df73591..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/SignalRequestInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Represents "signal" type channel request information - /// - [TestClass] - public class SignalRequestInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/SubsystemRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/SubsystemRequestInfoTest.cs deleted file mode 100644 index 5beaa074f..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/SubsystemRequestInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Represents "subsystem" type channel request information - /// - [TestClass] - public class SubsystemRequestInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/WindowChangeRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/WindowChangeRequestInfoTest.cs deleted file mode 100644 index 15cd2d339..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/WindowChangeRequestInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Represents "window-change" type channel request information - /// - [TestClass] - public class WindowChangeRequestInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/X11ForwardingRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/X11ForwardingRequestInfoTest.cs deleted file mode 100644 index c5fab8a12..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/X11ForwardingRequestInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Represents "x11-req" type channel request information - /// - [TestClass] - public class X11ForwardingRequestInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/XonXoffRequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/XonXoffRequestInfoTest.cs deleted file mode 100644 index f6ef5fc56..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/XonXoffRequestInfoTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - /// Represents "xon-xoff" type channel request information - /// - [TestClass] - public class XonXoffRequestInfoTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelSuccessMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelSuccessMessageTest.cs deleted file mode 100644 index 68efa44c4..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelSuccessMessageTest.cs +++ /dev/null @@ -1,38 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for ChannelSuccessMessageTest and is intended - ///to contain all ChannelSuccessMessageTest Unit Tests - /// - [TestClass] - public class ChannelSuccessMessageTest : TestBase - { - /// - ///A test for ChannelSuccessMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelSuccessMessageConstructorTest() - { - var target = new ChannelSuccessMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ChannelSuccessMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelSuccessMessageConstructorTest1() - { - uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - var target = new ChannelSuccessMessage(localChannelNumber); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelWindowAdjustMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelWindowAdjustMessageTest.cs deleted file mode 100644 index 12d19a61c..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelWindowAdjustMessageTest.cs +++ /dev/null @@ -1,39 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for ChannelWindowAdjustMessageTest and is intended - ///to contain all ChannelWindowAdjustMessageTest Unit Tests - /// - [TestClass] - public class ChannelWindowAdjustMessageTest : TestBase - { - /// - ///A test for ChannelWindowAdjustMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelWindowAdjustMessageConstructorTest() - { - ChannelWindowAdjustMessage target = new ChannelWindowAdjustMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ChannelWindowAdjustMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ChannelWindowAdjustMessageConstructorTest1() - { - uint localChannelNumber = 0; // TODO: Initialize to an appropriate value - uint bytesToAdd = 0; // TODO: Initialize to an appropriate value - ChannelWindowAdjustMessage target = new ChannelWindowAdjustMessage(localChannelNumber, bytesToAdd); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestFailureMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestFailureMessageTest.cs deleted file mode 100644 index b482ac0ab..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestFailureMessageTest.cs +++ /dev/null @@ -1,25 +0,0 @@ -锘縰sing Renci.SshNet.Messages.Connection; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for RequestFailureMessageTest and is intended - ///to contain all RequestFailureMessageTest Unit Tests - /// - [TestClass] - public class RequestFailureMessageTest : TestBase - { - /// - ///A test for RequestFailureMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void RequestFailureMessageConstructorTest() - { - RequestFailureMessage target = new RequestFailureMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestInfoTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestInfoTest.cs deleted file mode 100644 index f37ecc183..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestInfoTest.cs +++ /dev/null @@ -1,34 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for RequestInfoTest and is intended - ///to contain all RequestInfoTest Unit Tests - /// - [TestClass] - [Ignore] // placeholders only - public class RequestInfoTest : TestBase - { - internal virtual RequestInfo CreateRequestInfo() - { - // TODO: Instantiate an appropriate concrete class. - RequestInfo target = null; - return target; - } - - /// - ///A test for RequestName - /// - [TestMethod()] - public void RequestNameTest() - { - var target = CreateRequestInfo(); // TODO: Initialize to an appropriate value - var actual = target.RequestName; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestSuccessMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestSuccessMessageTest.cs deleted file mode 100644 index fba922456..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Connection/RequestSuccessMessageTest.cs +++ /dev/null @@ -1,38 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Connection; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Connection -{ - /// - ///This is a test class for RequestSuccessMessageTest and is intended - ///to contain all RequestSuccessMessageTest Unit Tests - /// - [TestClass] - public class RequestSuccessMessageTest : TestBase - { - /// - ///A test for RequestSuccessMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void RequestSuccessMessageConstructorTest() - { - var target = new RequestSuccessMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for RequestSuccessMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void RequestSuccessMessageConstructorTest1() - { - uint boundPort = 0; // TODO: Initialize to an appropriate value - var target = new RequestSuccessMessage(boundPort); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/MessageAttributeTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/MessageAttributeTest.cs deleted file mode 100644 index eb6118d61..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/MessageAttributeTest.cs +++ /dev/null @@ -1,62 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages -{ - /// - ///This is a test class for MessageAttributeTest and is intended - ///to contain all MessageAttributeTest Unit Tests - /// - [TestClass()] - public class MessageAttributeTest : TestBase - { - /// - ///A test for MessageAttribute Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void MessageAttributeConstructorTest() - { - var name = string.Empty; // TODO: Initialize to an appropriate value - byte number = 0; // TODO: Initialize to an appropriate value - var target = new MessageAttribute(name, number); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for Name - /// - [TestMethod] - [Ignore] // placeholder - public void NameTest() - { - var name = string.Empty; // TODO: Initialize to an appropriate value - byte number = 0; // TODO: Initialize to an appropriate value - var target = new MessageAttribute(name, number); // TODO: Initialize to an appropriate value - var expected = string.Empty; // TODO: Initialize to an appropriate value - target.Name = expected; - var actual = target.Name; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Number - /// - [TestMethod] - [Ignore] // placeholder - public void NumberTest() - { - var name = string.Empty; // TODO: Initialize to an appropriate value - byte number = 0; // TODO: Initialize to an appropriate value - var target = new MessageAttribute(name, number); // TODO: Initialize to an appropriate value - byte expected = 0; // TODO: Initialize to an appropriate value - target.Number = expected; - var actual = target.Number; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/MessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/MessageTest.cs deleted file mode 100644 index d3290f1f9..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/MessageTest.cs +++ /dev/null @@ -1,49 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages -{ - /// - ///This is a test class for MessageTest and is intended - ///to contain all MessageTest Unit Tests - /// - [TestClass] - [Ignore] // placeholders only - public class MessageTest : TestBase - { - internal virtual Message CreateMessage() - { - // TODO: Instantiate an appropriate concrete class. - Message target = null; - return target; - } - - /// - ///A test for GetBytes - /// - [TestMethod] - public void GetBytesTest() - { - var target = CreateMessage(); // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - var actual = target.GetBytes(); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ToString - /// - [TestMethod] - public void ToStringTest() - { - var target = CreateMessage(); // TODO: Initialize to an appropriate value - var expected = string.Empty; // TODO: Initialize to an appropriate value - var actual = target.ToString(); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/DebugMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/DebugMessageTest.cs deleted file mode 100644 index 25f07de37..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/DebugMessageTest.cs +++ /dev/null @@ -1,25 +0,0 @@ -锘縰sing Renci.SshNet.Messages.Transport; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Transport -{ - /// - ///This is a test class for DebugMessageTest and is intended - ///to contain all DebugMessageTest Unit Tests - /// - [TestClass] - public class DebugMessageTest : TestBase - { - /// - ///A test for DebugMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void DebugMessageConstructorTest() - { - DebugMessage target = new DebugMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/DisconnectMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/DisconnectMessageTest.cs deleted file mode 100644 index 853653826..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/DisconnectMessageTest.cs +++ /dev/null @@ -1,39 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Transport; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Transport -{ - /// - ///This is a test class for DisconnectMessageTest and is intended - ///to contain all DisconnectMessageTest Unit Tests - /// - [TestClass] - public class DisconnectMessageTest : TestBase - { - /// - ///A test for DisconnectMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void DisconnectMessageConstructorTest() - { - var target = new DisconnectMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for DisconnectMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void DisconnectMessageConstructorTest1() - { - var reasonCode = new DisconnectReason(); // TODO: Initialize to an appropriate value - var message = string.Empty; // TODO: Initialize to an appropriate value - var target = new DisconnectMessage(reasonCode, message); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupTest.cs deleted file mode 100644 index b5a56f48c..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupTest.cs +++ /dev/null @@ -1,26 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Transport; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Transport -{ - /// - ///This is a test class for KeyExchangeDhGroupExchangeGroupTest and is intended - ///to contain all KeyExchangeDhGroupExchangeGroupTest Unit Tests - /// - [TestClass] - public class KeyExchangeDhGroupExchangeGroupTest : TestBase - { - /// - ///A test for KeyExchangeDhGroupExchangeGroup Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void KeyExchangeDhGroupExchangeGroupConstructorTest() - { - var target = new KeyExchangeDhGroupExchangeGroup(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhInitMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhInitMessageTest.cs deleted file mode 100644 index 01fd55151..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhInitMessageTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Transport -{ - /// - /// Represents SSH_MSG_KEXDH_INIT message. - /// - [TestClass] - public class KeyExchangeDhInitMessageTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhReplyMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhReplyMessageTest.cs deleted file mode 100644 index a0d0d2f13..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhReplyMessageTest.cs +++ /dev/null @@ -1,26 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Transport; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Transport -{ - /// - ///This is a test class for KeyExchangeDhReplyMessageTest and is intended - ///to contain all KeyExchangeDhReplyMessageTest Unit Tests - /// - [TestClass] - public class KeyExchangeDhReplyMessageTest : TestBase - { - /// - ///A test for KeyExchangeDhReplyMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void KeyExchangeDhReplyMessageConstructorTest() - { - var target = new KeyExchangeDhReplyMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeInitMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeInitMessageTest.cs index 0ad95267f..e7116dc85 100644 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeInitMessageTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeInitMessageTest.cs @@ -64,196 +64,5 @@ public void Test_KeyExchangeInitMessage_GetBytes() Assert.IsTrue(input.Skip(17).SequenceEqual(output.Skip(17))); } - - /// - ///A test for KeyExchangeInitMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void KeyExchangeInitMessageConstructorTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for CompressionAlgorithmsClientToServer - /// - [TestMethod] - [Ignore] // placeholder - public void CompressionAlgorithmsClientToServerTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - target.CompressionAlgorithmsClientToServer = expected; - var actual = target.CompressionAlgorithmsClientToServer; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CompressionAlgorithmsServerToClient - /// - [TestMethod] - [Ignore] // placeholder - public void CompressionAlgorithmsServerToClientTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - target.CompressionAlgorithmsServerToClient = expected; - var actual = target.CompressionAlgorithmsServerToClient; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EncryptionAlgorithmsClientToServer - /// - [TestMethod] - [Ignore] // placeholder - public void EncryptionAlgorithmsClientToServerTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - target.EncryptionAlgorithmsClientToServer = expected; - var actual = target.EncryptionAlgorithmsClientToServer; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EncryptionAlgorithmsServerToClient - /// - [TestMethod] - [Ignore] // placeholder - public void EncryptionAlgorithmsServerToClientTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - target.EncryptionAlgorithmsServerToClient = expected; - var actual = target.EncryptionAlgorithmsServerToClient; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for FirstKexPacketFollows - /// - [TestMethod] - [Ignore] // placeholder - public void FirstKexPacketFollowsTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - target.FirstKexPacketFollows = expected; - var actual = target.FirstKexPacketFollows; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for KeyExchangeAlgorithms - /// - [TestMethod] - [Ignore] // placeholder - public void KeyExchangeAlgorithmsTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - target.KeyExchangeAlgorithms = expected; - var actual = target.KeyExchangeAlgorithms; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for LanguagesClientToServer - /// - [TestMethod] - [Ignore] // placeholder - public void LanguagesClientToServerTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - target.LanguagesClientToServer = expected; - var actual = target.LanguagesClientToServer; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for LanguagesServerToClient - /// - [TestMethod] - [Ignore] // placeholder - public void LanguagesServerToClientTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - target.LanguagesServerToClient = expected; - var actual = target.LanguagesServerToClient; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for MacAlgorithmsClientToServer - /// - [TestMethod] - [Ignore] // placeholder - public void MacAlgorithmsClientToServerTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - target.MacAlgorithmsClientToServer = expected; - var actual = target.MacAlgorithmsClientToServer; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for MacAlgorithmsServerToClient - /// - [TestMethod] - [Ignore] // placeholder - public void MacAlgorithmsServerToClientTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - target.MacAlgorithmsServerToClient = expected; - var actual = target.MacAlgorithmsServerToClient; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Reserved - /// - [TestMethod] - [Ignore] // placeholder - public void ReservedTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); // TODO: Initialize to an appropriate value - uint expected = 0; // TODO: Initialize to an appropriate value - target.Reserved = expected; - var actual = target.Reserved; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ServerHostKeyAlgorithms - /// - [TestMethod] - [Ignore] // placeholder - public void ServerHostKeyAlgorithmsTest() - { - KeyExchangeInitMessage target = new KeyExchangeInitMessage(); // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - target.ServerHostKeyAlgorithms = expected; - var actual = target.ServerHostKeyAlgorithms; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/NewKeysMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/NewKeysMessageTest.cs deleted file mode 100644 index 430c2151f..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/NewKeysMessageTest.cs +++ /dev/null @@ -1,26 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Transport; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Transport -{ - /// - ///This is a test class for NewKeysMessageTest and is intended - ///to contain all NewKeysMessageTest Unit Tests - /// - [TestClass] - public class NewKeysMessageTest : TestBase - { - /// - ///A test for NewKeysMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void NewKeysMessageConstructorTest() - { - var target = new NewKeysMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceAcceptMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceAcceptMessageTest.cs deleted file mode 100644 index 143cd7003..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceAcceptMessageTest.cs +++ /dev/null @@ -1,25 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Transport; - -namespace Renci.SshNet.Tests.Classes.Messages.Transport -{ - /// - ///This is a test class for ServiceAcceptMessageTest and is intended - ///to contain all ServiceAcceptMessageTest Unit Tests - /// - [TestClass] - public class ServiceAcceptMessageTest - { - /// - ///A test for ServiceAcceptMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ServiceAcceptMessageConstructorTest() - { - var target = new ServiceAcceptMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceRequestMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceRequestMessageTest.cs deleted file mode 100644 index 9806fb862..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/ServiceRequestMessageTest.cs +++ /dev/null @@ -1,27 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Messages.Transport; -using Renci.SshNet.Messages; - -namespace Renci.SshNet.Tests.Classes.Messages.Transport -{ - /// - ///This is a test class for ServiceRequestMessageTest and is intended - ///to contain all ServiceRequestMessageTest Unit Tests - /// - [TestClass] - public class ServiceRequestMessageTest - { - /// - ///A test for ServiceRequestMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void ServiceRequestMessageConstructorTest() - { - var serviceName = new ServiceName(); // TODO: Initialize to an appropriate value - var target = new ServiceRequestMessage(serviceName); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/UnimplementedMessageTest.cs b/src/Renci.SshNet.Tests/Classes/Messages/Transport/UnimplementedMessageTest.cs deleted file mode 100644 index 5e8d53add..000000000 --- a/src/Renci.SshNet.Tests/Classes/Messages/Transport/UnimplementedMessageTest.cs +++ /dev/null @@ -1,25 +0,0 @@ -锘縰sing Renci.SshNet.Messages.Transport; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Messages.Transport -{ - /// - ///This is a test class for UnimplementedMessageTest and is intended - ///to contain all UnimplementedMessageTest Unit Tests - /// - [TestClass] - public class UnimplementedMessageTest : TestBase - { - /// - ///A test for UnimplementedMessage Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void UnimplementedMessageConstructorTest() - { - var target = new UnimplementedMessage(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs b/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs index 0a76674be..d86ca2e37 100644 --- a/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs @@ -1,7 +1,6 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Tests.Common; using System; -using System.Xml; namespace Renci.SshNet.Tests.Classes { @@ -109,170 +108,5 @@ public void OperationTimeout_GreaterThanLowerLimit() Assert.AreEqual("value", ex.ParamName); } } - - /// - ///A test for NetConfClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void NetConfClientConstructorTest() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - NetConfClient target = new NetConfClient(host, username, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for NetConfClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void NetConfClientConstructorTest1() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - NetConfClient target = new NetConfClient(host, port, username, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for NetConfClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void NetConfClientConstructorTest2() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - NetConfClient target = new NetConfClient(host, username, password); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for NetConfClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void NetConfClientConstructorTest3() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - NetConfClient target = new NetConfClient(host, port, username, password); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for NetConfClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void NetConfClientConstructorTest4() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - NetConfClient target = new NetConfClient(connectionInfo); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SendReceiveRpc - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SendReceiveRpcTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - NetConfClient target = new NetConfClient(connectionInfo); // TODO: Initialize to an appropriate value - string xml = string.Empty; // TODO: Initialize to an appropriate value - XmlDocument expected = null; // TODO: Initialize to an appropriate value - XmlDocument actual; - actual = target.SendReceiveRpc(xml); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for SendReceiveRpc - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SendReceiveRpcTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - NetConfClient target = new NetConfClient(connectionInfo); // TODO: Initialize to an appropriate value - XmlDocument rpc = null; // TODO: Initialize to an appropriate value - XmlDocument expected = null; // TODO: Initialize to an appropriate value - XmlDocument actual; - actual = target.SendReceiveRpc(rpc); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for SendCloseRpc - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SendCloseRpcTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - NetConfClient target = new NetConfClient(connectionInfo); // TODO: Initialize to an appropriate value - XmlDocument expected = null; // TODO: Initialize to an appropriate value - XmlDocument actual; - actual = target.SendCloseRpc(); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ServerCapabilities - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ServerCapabilitiesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - NetConfClient target = new NetConfClient(connectionInfo); // TODO: Initialize to an appropriate value - XmlDocument actual; - actual = target.ServerCapabilities; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ClientCapabilities - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ClientCapabilitiesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - NetConfClient target = new NetConfClient(connectionInfo); // TODO: Initialize to an appropriate value - XmlDocument actual; - actual = target.ClientCapabilities; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for AutomaticMessageIdHandling - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AutomaticMessageIdHandlingTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - NetConfClient target = new NetConfClient(connectionInfo); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.AutomaticMessageIdHandling = expected; - actual = target.AutomaticMessageIdHandling; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/NoneAuthenticationMethodTest.cs b/src/Renci.SshNet.Tests/Classes/NoneAuthenticationMethodTest.cs index 3dc69e319..377ff89a5 100644 --- a/src/Renci.SshNet.Tests/Classes/NoneAuthenticationMethodTest.cs +++ b/src/Renci.SshNet.Tests/Classes/NoneAuthenticationMethodTest.cs @@ -48,47 +48,5 @@ public void Username() Assert.AreSame(username, target.Username); } - - /// - ///A test for Dispose - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DisposeTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - NoneAuthenticationMethod target = new NoneAuthenticationMethod(username); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Authenticate - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AuthenticateTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - NoneAuthenticationMethod target = new NoneAuthenticationMethod(username); // TODO: Initialize to an appropriate value - Session session = null; // TODO: Initialize to an appropriate value - AuthenticationResult expected = new AuthenticationResult(); // TODO: Initialize to an appropriate value - AuthenticationResult actual; - actual = target.Authenticate(session); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for NoneAuthenticationMethod Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void NoneAuthenticationMethodConstructorTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - NoneAuthenticationMethod target = new NoneAuthenticationMethod(username); - Assert.Inconclusive("TODO: Implement code to verify target"); - } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs b/src/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs index 951314d1c..7ad141adf 100644 --- a/src/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs @@ -57,78 +57,5 @@ public void Password_Test_Pass_Valid() { new PasswordAuthenticationMethod("valid", string.Empty); } - - /// - ///A test for Name - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void NameTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - PasswordAuthenticationMethod target = new PasswordAuthenticationMethod(username, password); // TODO: Initialize to an appropriate value - string actual; - actual = target.Name; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Dispose - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DisposeTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - PasswordAuthenticationMethod target = new PasswordAuthenticationMethod(username, password); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Authenticate - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AuthenticateTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - PasswordAuthenticationMethod target = new PasswordAuthenticationMethod(username, password); // TODO: Initialize to an appropriate value - Session session = null; // TODO: Initialize to an appropriate value - AuthenticationResult expected = new AuthenticationResult(); // TODO: Initialize to an appropriate value - AuthenticationResult actual; - actual = target.Authenticate(session); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for PasswordAuthenticationMethod Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordAuthenticationMethodConstructorTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - PasswordAuthenticationMethod target = new PasswordAuthenticationMethod(username, password); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordAuthenticationMethod Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordAuthenticationMethodConstructorTest1() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - PasswordAuthenticationMethod target = new PasswordAuthenticationMethod(username, password); - Assert.Inconclusive("TODO: Implement code to verify target"); - } } } diff --git a/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs b/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs index 56a510140..dbaa340f8 100644 --- a/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs @@ -69,281 +69,5 @@ public void Test_ConnectionInfo_BigPortNumber() { _ = new PasswordConnectionInfo(Resources.HOST, IPEndPoint.MaxPort + 1, Resources.USERNAME, Resources.PASSWORD); } - - /// - ///A test for Dispose - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DisposeTest() - { - var host = string.Empty; // TODO: Initialize to an appropriate value - var username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - var target = new PasswordConnectionInfo(host, username, password); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - string proxyPassword = string.Empty; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, port, username, password, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest1() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - string proxyPassword = string.Empty; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, username, password, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest2() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, username, password, proxyType, proxyHost, proxyPort, proxyUsername); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest3() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, username, password, proxyType, proxyHost, proxyPort); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest4() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, port, username, password, proxyType, proxyHost, proxyPort, proxyUsername); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest5() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, port, username, password, proxyType, proxyHost, proxyPort); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest6() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, port, username, password); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest7() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - byte[] password = null; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, username, password); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest8() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - string proxyPassword = string.Empty; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, username, password, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest9() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, username, password, proxyType, proxyHost, proxyPort, proxyUsername); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest10() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, username, password, proxyType, proxyHost, proxyPort); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest11() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, port, username, password, proxyType, proxyHost, proxyPort, proxyUsername); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest12() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, port, username, password, proxyType, proxyHost, proxyPort); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest13() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, port, username, password); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PasswordConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PasswordConnectionInfoConstructorTest14() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - PasswordConnectionInfo target = new PasswordConnectionInfo(host, username, password); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } } diff --git a/src/Renci.SshNet.Tests/Classes/PrivateKeyAuthenticationMethodTest.cs b/src/Renci.SshNet.Tests/Classes/PrivateKeyAuthenticationMethodTest.cs index 6ea7a33ff..aa713dc96 100644 --- a/src/Renci.SshNet.Tests/Classes/PrivateKeyAuthenticationMethodTest.cs +++ b/src/Renci.SshNet.Tests/Classes/PrivateKeyAuthenticationMethodTest.cs @@ -42,65 +42,5 @@ public void PrivateKey_Test_Pass_Whitespace() { new PrivateKeyAuthenticationMethod(string.Empty, null); } - - /// - ///A test for Name - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void NameTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyAuthenticationMethod target = new PrivateKeyAuthenticationMethod(username, keyFiles); // TODO: Initialize to an appropriate value - string actual; - actual = target.Name; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Dispose - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DisposeTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyAuthenticationMethod target = new PrivateKeyAuthenticationMethod(username, keyFiles); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Authenticate - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AuthenticateTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyAuthenticationMethod target = new PrivateKeyAuthenticationMethod(username, keyFiles); // TODO: Initialize to an appropriate value - Session session = null; // TODO: Initialize to an appropriate value - AuthenticationResult expected = new AuthenticationResult(); // TODO: Initialize to an appropriate value - AuthenticationResult actual; - actual = target.Authenticate(session); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for PrivateKeyAuthenticationMethod Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PrivateKeyAuthenticationMethodConstructorTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyAuthenticationMethod target = new PrivateKeyAuthenticationMethod(username, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet.Tests/Classes/PrivateKeyConnectionInfoTest.cs b/src/Renci.SshNet.Tests/Classes/PrivateKeyConnectionInfoTest.cs deleted file mode 100644 index 40a781174..000000000 --- a/src/Renci.SshNet.Tests/Classes/PrivateKeyConnectionInfoTest.cs +++ /dev/null @@ -1,167 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes -{ - /// - /// Provides connection information when private key authentication method is used - /// - [TestClass] - public class PrivateKeyConnectionInfoTest : TestBase - { - /// - ///A test for Dispose - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DisposeTest() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyConnectionInfo target = new PrivateKeyConnectionInfo(host, username, keyFiles); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for PrivateKeyConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PrivateKeyConnectionInfoConstructorTest() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - string proxyPassword = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyConnectionInfo target = new PrivateKeyConnectionInfo(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PrivateKeyConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PrivateKeyConnectionInfoConstructorTest1() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - string proxyPassword = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyConnectionInfo target = new PrivateKeyConnectionInfo(host, username, proxyType, proxyHost, proxyPort, proxyUsername, proxyPassword, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PrivateKeyConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PrivateKeyConnectionInfoConstructorTest2() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyConnectionInfo target = new PrivateKeyConnectionInfo(host, username, proxyType, proxyHost, proxyPort, proxyUsername, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PrivateKeyConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PrivateKeyConnectionInfoConstructorTest3() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyConnectionInfo target = new PrivateKeyConnectionInfo(host, username, proxyType, proxyHost, proxyPort, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PrivateKeyConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PrivateKeyConnectionInfoConstructorTest4() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - string proxyUsername = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyConnectionInfo target = new PrivateKeyConnectionInfo(host, port, username, proxyType, proxyHost, proxyPort, proxyUsername, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PrivateKeyConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PrivateKeyConnectionInfoConstructorTest5() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - ProxyTypes proxyType = new ProxyTypes(); // TODO: Initialize to an appropriate value - string proxyHost = string.Empty; // TODO: Initialize to an appropriate value - int proxyPort = 0; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyConnectionInfo target = new PrivateKeyConnectionInfo(host, port, username, proxyType, proxyHost, proxyPort, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PrivateKeyConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PrivateKeyConnectionInfoConstructorTest6() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyConnectionInfo target = new PrivateKeyConnectionInfo(host, port, username, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for PrivateKeyConnectionInfo Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PrivateKeyConnectionInfoConstructorTest7() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - PrivateKeyConnectionInfo target = new PrivateKeyConnectionInfo(host, username, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs b/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs index bcdf93966..786e408d4 100644 --- a/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs @@ -1,5 +1,4 @@ 锘縰sing System; -using System.IO; using System.Text; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -215,129 +214,6 @@ public void RemotePathTransformation_Value_Null() Assert.AreSame(RemotePathTransformation.ShellQuote, client.RemotePathTransformation); } - /// - ///A test for OperationTimeout - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OperationTimeoutTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value - var expected = new TimeSpan(); // TODO: Initialize to an appropriate value - target.OperationTimeout = expected; - var actual = target.OperationTimeout; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for BufferSize - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void BufferSizeTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value - uint expected = 0; // TODO: Initialize to an appropriate value - uint actual; - target.BufferSize = expected; - actual = target.BufferSize; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Upload - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void UploadTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value - DirectoryInfo directoryInfo = null; // TODO: Initialize to an appropriate value - var filename = string.Empty; // TODO: Initialize to an appropriate value - target.Upload(directoryInfo, filename); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Upload - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void UploadTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value - FileInfo fileInfo = null; // TODO: Initialize to an appropriate value - var filename = string.Empty; // TODO: Initialize to an appropriate value - target.Upload(fileInfo, filename); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Upload - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void UploadTest2() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value - Stream source = null; // TODO: Initialize to an appropriate value - var filename = string.Empty; // TODO: Initialize to an appropriate value - target.Upload(source, filename); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Download - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DownloadTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value - var directoryName = string.Empty; // TODO: Initialize to an appropriate value - DirectoryInfo directoryInfo = null; // TODO: Initialize to an appropriate value - target.Download(directoryName, directoryInfo); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Download - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DownloadTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value - var filename = string.Empty; // TODO: Initialize to an appropriate value - FileInfo fileInfo = null; // TODO: Initialize to an appropriate value - target.Download(filename, fileInfo); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Download - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DownloadTest2() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - var target = new ScpClient(connectionInfo); // TODO: Initialize to an appropriate value - var filename = string.Empty; // TODO: Initialize to an appropriate value - Stream destination = null; // TODO: Initialize to an appropriate value - target.Download(filename, destination); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - private PrivateKeyFile GetRsaKey() { using (var stream = GetData("Key.RSA.txt")) diff --git a/src/Renci.SshNet.Tests/Classes/Security/AlgorithmTest.cs b/src/Renci.SshNet.Tests/Classes/Security/AlgorithmTest.cs deleted file mode 100644 index 00c9d5d24..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/AlgorithmTest.cs +++ /dev/null @@ -1,34 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - /// - ///This is a test class for AlgorithmTest and is intended - ///to contain all AlgorithmTest Unit Tests - /// - [TestClass()] - public class AlgorithmTest : TestBase - { - internal virtual Algorithm CreateAlgorithm() - { - // TODO: Instantiate an appropriate concrete class. - Algorithm target = null; - return target; - } - - /// - ///A test for Name - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void NameTest() - { - Algorithm target = CreateAlgorithm(); // TODO: Initialize to an appropriate value - string actual; - actual = target.Name; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/CertificateHostAlgorithmTest.cs b/src/Renci.SshNet.Tests/Classes/Security/CertificateHostAlgorithmTest.cs deleted file mode 100644 index 31beb9f27..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/CertificateHostAlgorithmTest.cs +++ /dev/null @@ -1,75 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - /// - ///This is a test class for CertificateHostAlgorithmTest and is intended - ///to contain all CertificateHostAlgorithmTest Unit Tests - /// - [TestClass()] - public class CertificateHostAlgorithmTest : TestBase - { - /// - ///A test for CertificateHostAlgorithm Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void CertificateHostAlgorithmConstructorTest() - { - string name = string.Empty; // TODO: Initialize to an appropriate value - CertificateHostAlgorithm target = new CertificateHostAlgorithm(name); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for Sign - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SignTest() - { - string name = string.Empty; // TODO: Initialize to an appropriate value - CertificateHostAlgorithm target = new CertificateHostAlgorithm(name); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Sign(data); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for VerifySignature - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void VerifySignatureTest() - { - string name = string.Empty; // TODO: Initialize to an appropriate value - CertificateHostAlgorithm target = new CertificateHostAlgorithm(name); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - byte[] signature = null; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - actual = target.VerifySignature(data, signature); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Data - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DataTest() - { - string name = string.Empty; // TODO: Initialize to an appropriate value - CertificateHostAlgorithm target = new CertificateHostAlgorithm(name); // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Data; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/CipherDigitalSignatureTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/CipherDigitalSignatureTest.cs deleted file mode 100644 index 2bdce8e15..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/CipherDigitalSignatureTest.cs +++ /dev/null @@ -1,54 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security.Cryptography; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography -{ - /// - ///This is a test class for CipherDigitalSignatureTest and is intended - ///to contain all CipherDigitalSignatureTest Unit Tests - /// - [TestClass()] - public class CipherDigitalSignatureTest : TestBase - { - internal virtual CipherDigitalSignature CreateCipherDigitalSignature() - { - // TODO: Instantiate an appropriate concrete class. - CipherDigitalSignature target = null; - return target; - } - - /// - ///A test for Sign - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SignTest() - { - CipherDigitalSignature target = CreateCipherDigitalSignature(); // TODO: Initialize to an appropriate value - byte[] input = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Sign(input); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Verify - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void VerifyTest() - { - CipherDigitalSignature target = CreateCipherDigitalSignature(); // TODO: Initialize to an appropriate value - byte[] input = null; // TODO: Initialize to an appropriate value - byte[] signature = null; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - actual = target.Verify(input, signature); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/CipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/CipherTest.cs deleted file mode 100644 index 8af4f653c..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/CipherTest.cs +++ /dev/null @@ -1,53 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security.Cryptography; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography -{ - /// - ///This is a test class for CipherTest and is intended - ///to contain all CipherTest Unit Tests - /// - [TestClass()] - public class CipherTest : TestBase - { - internal virtual Cipher CreateCipher() - { - // TODO: Instantiate an appropriate concrete class. - Cipher target = null; - return target; - } - - /// - ///A test for Decrypt - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptTest() - { - Cipher target = CreateCipher(); // TODO: Initialize to an appropriate value - byte[] input = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Decrypt(input); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Encrypt - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptTest() - { - Cipher target = CreateCipher(); // TODO: Initialize to an appropriate value - byte[] input = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Encrypt(input); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs index 03a2e34e9..b439b67a4 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs @@ -82,65 +82,5 @@ public void Decrypt_InputAndOffsetAndLength_128_CTR() Assert.IsTrue(expected.IsEqualTo(actual)); } - - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - AesCipher target = new AesCipher(key, mode, padding); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for AesCipher Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AesCipherConstructorTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - AesCipher target = new AesCipher(key, mode, padding); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - AesCipher target = new AesCipher(key, mode, padding); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } } } diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs index 5b972021b..144524ed7 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs @@ -12,18 +12,6 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers [TestClass] public class Arc4CipherTest : TestBase { - /// - ///A test for Arc4Cipher Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void Arc4CipherConstructorTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - Arc4Cipher target = new Arc4Cipher(key, true); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - [TestMethod] public void Decrypt_DischargeFirstBytes_False1() { @@ -66,27 +54,6 @@ public void Decrypt_InputAndOffsetAndLength() Assert.AreEqual(expectedPlainText, encoding.GetString(actualPlainText)); } - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - Arc4Cipher target = new Arc4Cipher(key, true); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - [TestMethod] public void Encrypt_DischargeFirstBytes_False1() { @@ -134,26 +101,5 @@ public void Encrypt_InputAndOffsetAndLength() Assert.IsTrue(plainTextBytes.IsEqualTo(encoding.GetBytes(plainText))); } - - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - Arc4Cipher target = new Arc4Cipher(key, true); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } } } diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs index 168b1eaf8..bb31dbc98 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs @@ -28,64 +28,5 @@ public void Test_Cipher_Blowfish_128_CBC() Assert.Fail("Invalid encryption"); } } - - /// - ///A test for BlowfishCipher Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void BlowfishCipherConstructorTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - var target = new BlowfishCipher(key, mode, padding); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - var target = new BlowfishCipher(key, mode, padding); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - var inputOffset = 0; // TODO: Initialize to an appropriate value - var inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - var outputOffset = 0; // TODO: Initialize to an appropriate value - var expected = 0; // TODO: Initialize to an appropriate value - var actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - var target = new BlowfishCipher(key, mode, padding); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - var inputOffset = 0; // TODO: Initialize to an appropriate value - var inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - var outputOffset = 0; // TODO: Initialize to an appropriate value - var expected = 0; // TODO: Initialize to an appropriate value - var actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } } diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs index a04c5f2db..74aaec9be 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs @@ -38,65 +38,5 @@ public void Decrypt_128_CBC() Assert.IsTrue(r.SequenceEqual(input)); } - - /// - ///A test for CastCipher Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CastCipherConstructorTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - CastCipher target = new CastCipher(key, mode, padding); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - CastCipher target = new CastCipher(key, mode, padding); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - CastCipher target = new CastCipher(key, mode, padding); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } } } diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CipherModeTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CipherModeTest.cs deleted file mode 100644 index d3b4c0adb..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CipherModeTest.cs +++ /dev/null @@ -1,61 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers -{ - /// - ///This is a test class for CipherModeTest and is intended - ///to contain all CipherModeTest Unit Tests - /// - [TestClass()] - public class CipherModeTest : TestBase - { - internal virtual CipherMode CreateCipherMode() - { - // TODO: Instantiate an appropriate concrete class. - CipherMode target = null; - return target; - } - - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - CipherMode target = CreateCipherMode(); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - CipherMode target = CreateCipherMode(); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CipherPaddingTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CipherPaddingTest.cs deleted file mode 100644 index c923584a0..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CipherPaddingTest.cs +++ /dev/null @@ -1,38 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers -{ - /// - ///This is a test class for CipherPaddingTest and is intended - ///to contain all CipherPaddingTest Unit Tests - /// - [TestClass()] - public class CipherPaddingTest : TestBase - { - internal virtual CipherPadding CreateCipherPadding() - { - // TODO: Instantiate an appropriate concrete class. - CipherPadding target = null; - return target; - } - - /// - ///A test for Pad - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PadTest() - { - CipherPadding target = CreateCipherPadding(); // TODO: Initialize to an appropriate value - int blockSize = 0; // TODO: Initialize to an appropriate value - byte[] input = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Pad(blockSize, input); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/CbcCipherModeTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/CbcCipherModeTest.cs deleted file mode 100644 index c43191c28..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/CbcCipherModeTest.cs +++ /dev/null @@ -1,67 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers.Modes -{ - /// - ///This is a test class for CbcCipherModeTest and is intended - ///to contain all CbcCipherModeTest Unit Tests - /// - [TestClass()] - public class CbcCipherModeTest : TestBase - { - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - byte[] iv = null; // TODO: Initialize to an appropriate value - CbcCipherMode target = new CbcCipherMode(iv); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - byte[] iv = null; // TODO: Initialize to an appropriate value - CbcCipherMode target = new CbcCipherMode(iv); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CbcCipherMode Constructor - /// - [TestMethod()] - public void CbcCipherModeConstructorTest() - { - byte[] iv = null; // TODO: Initialize to an appropriate value - CbcCipherMode target = new CbcCipherMode(iv); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/CfbCipherModeTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/CfbCipherModeTest.cs deleted file mode 100644 index f7dd046d6..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/CfbCipherModeTest.cs +++ /dev/null @@ -1,68 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers.Modes -{ - /// - ///This is a test class for CfbCipherModeTest and is intended - ///to contain all CfbCipherModeTest Unit Tests - /// - [TestClass()] - public class CfbCipherModeTest : TestBase - { - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - byte[] iv = null; // TODO: Initialize to an appropriate value - CfbCipherMode target = new CfbCipherMode(iv); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - byte[] iv = null; // TODO: Initialize to an appropriate value - CfbCipherMode target = new CfbCipherMode(iv); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CfbCipherMode Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CfbCipherModeConstructorTest() - { - byte[] iv = null; // TODO: Initialize to an appropriate value - CfbCipherMode target = new CfbCipherMode(iv); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/CtrCipherModeTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/CtrCipherModeTest.cs deleted file mode 100644 index 23e0391e2..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/CtrCipherModeTest.cs +++ /dev/null @@ -1,68 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers.Modes -{ - /// - ///This is a test class for CtrCipherModeTest and is intended - ///to contain all CtrCipherModeTest Unit Tests - /// - [TestClass()] - public class CtrCipherModeTest : TestBase - { - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - byte[] iv = null; // TODO: Initialize to an appropriate value - CtrCipherMode target = new CtrCipherMode(iv); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - byte[] iv = null; // TODO: Initialize to an appropriate value - CtrCipherMode target = new CtrCipherMode(iv); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CtrCipherMode Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CtrCipherModeConstructorTest() - { - byte[] iv = null; // TODO: Initialize to an appropriate value - CtrCipherMode target = new CtrCipherMode(iv); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/OfbCipherModeTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/OfbCipherModeTest.cs deleted file mode 100644 index d4719e256..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Modes/OfbCipherModeTest.cs +++ /dev/null @@ -1,68 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers.Modes -{ - /// - ///This is a test class for OfbCipherModeTest and is intended - ///to contain all OfbCipherModeTest Unit Tests - /// - [TestClass()] - public class OfbCipherModeTest : TestBase - { - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - byte[] iv = null; // TODO: Initialize to an appropriate value - OfbCipherMode target = new OfbCipherMode(iv); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - byte[] iv = null; // TODO: Initialize to an appropriate value - OfbCipherMode target = new OfbCipherMode(iv); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OfbCipherMode Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OfbCipherModeConstructorTest() - { - byte[] iv = null; // TODO: Initialize to an appropriate value - OfbCipherMode target = new OfbCipherMode(iv); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/RsaCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/RsaCipherTest.cs deleted file mode 100644 index 2de87cdde..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/RsaCipherTest.cs +++ /dev/null @@ -1,60 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security; -using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers -{ - /// - /// Implements RSA cipher algorithm. - /// - [TestClass] - public class RsaCipherTest : TestBase - { - /// - ///A test for RsaCipher Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void RsaCipherConstructorTest() - { - RsaKey key = null; // TODO: Initialize to an appropriate value - RsaCipher target = new RsaCipher(key); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for Decrypt - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptTest() - { - RsaKey key = null; // TODO: Initialize to an appropriate value - RsaCipher target = new RsaCipher(key); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Decrypt(data); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Encrypt - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptTest() - { - RsaKey key = null; // TODO: Initialize to an appropriate value - RsaCipher target = new RsaCipher(key); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Encrypt(data); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/SerpentCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/SerpentCipherTest.cs deleted file mode 100644 index f604f5dc9..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/SerpentCipherTest.cs +++ /dev/null @@ -1,73 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers -{ - /// - /// Implements Serpent cipher algorithm. - /// - [TestClass] - public class SerpentCipherTest : TestBase - { - /// - ///A test for SerpentCipher Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SerpentCipherConstructorTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - SerpentCipher target = new SerpentCipher(key, mode, padding); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - SerpentCipher target = new SerpentCipher(key, mode, padding); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - SerpentCipher target = new SerpentCipher(key, mode, padding); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs index 9dc6a2b65..da340cd9d 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs @@ -29,65 +29,5 @@ public void Test_Cipher_3DES_CBC() Assert.Fail("Invalid encryption"); } } - - /// - ///A test for TripleDesCipher Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void TripleDesCipherConstructorTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - TripleDesCipher target = new TripleDesCipher(key, mode, padding); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - TripleDesCipher target = new TripleDesCipher(key, mode, padding); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - TripleDesCipher target = new TripleDesCipher(key, mode, padding); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } } } diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TwofishCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TwofishCipherTest.cs deleted file mode 100644 index e0693e971..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TwofishCipherTest.cs +++ /dev/null @@ -1,73 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers -{ - /// - /// Implements Twofish cipher algorithm - /// - [TestClass] - public class TwofishCipherTest : TestBase - { - /// - ///A test for TwofishCipher Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void TwofishCipherConstructorTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - TwofishCipher target = new TwofishCipher(key, mode, padding); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - TwofishCipher target = new TwofishCipher(key, mode, padding); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - byte[] key = null; // TODO: Initialize to an appropriate value - CipherMode mode = null; // TODO: Initialize to an appropriate value - CipherPadding padding = null; // TODO: Initialize to an appropriate value - TwofishCipher target = new TwofishCipher(key, mode, padding); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - int inputOffset = 0; // TODO: Initialize to an appropriate value - int inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - int outputOffset = 0; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DigitalSignatureTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DigitalSignatureTest.cs deleted file mode 100644 index efe45c9ca..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DigitalSignatureTest.cs +++ /dev/null @@ -1,54 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security.Cryptography; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography -{ - /// - ///This is a test class for DigitalSignatureTest and is intended - ///to contain all DigitalSignatureTest Unit Tests - /// - [TestClass()] - public class DigitalSignatureTest : TestBase - { - internal virtual DigitalSignature CreateDigitalSignature() - { - // TODO: Instantiate an appropriate concrete class. - DigitalSignature target = null; - return target; - } - - /// - ///A test for Sign - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SignTest() - { - DigitalSignature target = CreateDigitalSignature(); // TODO: Initialize to an appropriate value - byte[] input = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Sign(input); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Verify - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void VerifyTest() - { - DigitalSignature target = CreateDigitalSignature(); // TODO: Initialize to an appropriate value - byte[] input = null; // TODO: Initialize to an appropriate value - byte[] signature = null; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - actual = target.Verify(input, signature); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DsaDigitalSignatureTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DsaDigitalSignatureTest.cs deleted file mode 100644 index 947ec9c76..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DsaDigitalSignatureTest.cs +++ /dev/null @@ -1,72 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security; -using Renci.SshNet.Security.Cryptography; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography -{ - /// - /// Implements DSA digital signature algorithm. - /// - [TestClass] - public class DsaDigitalSignatureTest : TestBase - { - /// - ///A test for DsaDigitalSignature Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DsaDigitalSignatureConstructorTest() - { - DsaKey key = null; // TODO: Initialize to an appropriate value - var target = new DsaDigitalSignature(key); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for Dispose - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DisposeTest() - { - DsaKey key = null; // TODO: Initialize to an appropriate value - var target = new DsaDigitalSignature(key); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Sign - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SignTest() - { - DsaKey key = null; // TODO: Initialize to an appropriate value - var target = new DsaDigitalSignature(key); // TODO: Initialize to an appropriate value - byte[] input = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - var actual = target.Sign(input); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Verify - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void VerifyTest() - { - DsaKey key = null; // TODO: Initialize to an appropriate value - var target = new DsaDigitalSignature(key); // TODO: Initialize to an appropriate value - byte[] input = null; // TODO: Initialize to an appropriate value - byte[] signature = null; // TODO: Initialize to an appropriate value - var expected = false; // TODO: Initialize to an appropriate value - var actual = target.Verify(input, signature); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DsaKeyTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DsaKeyTest.cs deleted file mode 100644 index 57fe73f5d..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/DsaKeyTest.cs +++ /dev/null @@ -1,160 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security.Cryptography -{ - /// - ///This is a test class for DsaKeyTest and is intended - ///to contain all DsaKeyTest Unit Tests - /// - [TestClass] - public class DsaKeyTest : TestBase - { - /// - ///A test for DsaKey Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DsaKeyConstructorTest() - { - DsaKey target = new DsaKey(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for DsaKey Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DsaKeyConstructorTest1() - { - byte[] data = null; // TODO: Initialize to an appropriate value - DsaKey target = new DsaKey(data); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for DsaKey Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DsaKeyConstructorTest2() - { - BigInteger p = new BigInteger(); // TODO: Initialize to an appropriate value - BigInteger q = new BigInteger(); // TODO: Initialize to an appropriate value - BigInteger g = new BigInteger(); // TODO: Initialize to an appropriate value - BigInteger y = new BigInteger(); // TODO: Initialize to an appropriate value - BigInteger x = new BigInteger(); // TODO: Initialize to an appropriate value - DsaKey target = new DsaKey(p, q, g, y, x); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for Dispose - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DisposeTest() - { - DsaKey target = new DsaKey(); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for G - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GTest() - { - DsaKey target = new DsaKey(); // TODO: Initialize to an appropriate value - BigInteger actual; - actual = target.G; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for KeyLength - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyLengthTest() - { - DsaKey target = new DsaKey(); // TODO: Initialize to an appropriate value - int actual; - actual = target.KeyLength; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for P - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PTest() - { - DsaKey target = new DsaKey(); // TODO: Initialize to an appropriate value - BigInteger actual; - actual = target.P; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Public - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PublicTest() - { - DsaKey target = new DsaKey(); // TODO: Initialize to an appropriate value - BigInteger[] expected = null; // TODO: Initialize to an appropriate value - BigInteger[] actual; - target.Public = expected; - actual = target.Public; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Q - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void QTest() - { - DsaKey target = new DsaKey(); // TODO: Initialize to an appropriate value - BigInteger actual; - actual = target.Q; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for X - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void XTest() - { - DsaKey target = new DsaKey(); // TODO: Initialize to an appropriate value - BigInteger actual; - actual = target.X; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Y - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void YTest() - { - DsaKey target = new DsaKey(); // TODO: Initialize to an appropriate value - BigInteger actual; - actual = target.Y; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs index 4691fef27..d7558c2c4 100644 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs +++ b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs @@ -167,18 +167,5 @@ private static RsaKey GetRsaKey() return (RsaKey) new PrivateKeyFile(stream).Key; } } - - /// - ///A test for Dispose - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DisposeTest() - { - RsaKey rsaKey = null; // TODO: Initialize to an appropriate value - RsaDigitalSignature target = new RsaDigitalSignature(rsaKey); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } } } diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaKeyTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaKeyTest.cs deleted file mode 100644 index 89323337a..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaKeyTest.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - /// - /// Contains RSA private and public key - /// - [TestClass] - public class RsaKeyTest : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/SymmetricCipherTest.cs b/src/Renci.SshNet.Tests/Classes/Security/Cryptography/SymmetricCipherTest.cs deleted file mode 100644 index 92f9da374..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/SymmetricCipherTest.cs +++ /dev/null @@ -1,60 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Security.Cryptography; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests -{ - /// - ///This is a test class for SymmetricCipherTest and is intended - ///to contain all SymmetricCipherTest Unit Tests - /// - [TestClass()] - public class SymmetricCipherTest : TestBase - { - internal virtual SymmetricCipher CreateSymmetricCipher() - { - // TODO: Instantiate an appropriate concrete class. - SymmetricCipher target = null; - return target; - } - - /// - ///A test for DecryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DecryptBlockTest() - { - var target = CreateSymmetricCipher(); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - var inputOffset = 0; // TODO: Initialize to an appropriate value - var inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - var outputOffset = 0; // TODO: Initialize to an appropriate value - var expected = 0; // TODO: Initialize to an appropriate value - var actual = target.DecryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EncryptBlock - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EncryptBlockTest() - { - var target = CreateSymmetricCipher(); // TODO: Initialize to an appropriate value - byte[] inputBuffer = null; // TODO: Initialize to an appropriate value - var inputOffset = 0; // TODO: Initialize to an appropriate value - var inputCount = 0; // TODO: Initialize to an appropriate value - byte[] outputBuffer = null; // TODO: Initialize to an appropriate value - var outputOffset = 0; // TODO: Initialize to an appropriate value - var expected = 0; // TODO: Initialize to an appropriate value - var actual = target.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/HostAlgorithmTest.cs b/src/Renci.SshNet.Tests/Classes/Security/HostAlgorithmTest.cs deleted file mode 100644 index a9547a54b..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/HostAlgorithmTest.cs +++ /dev/null @@ -1,67 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - /// - ///This is a test class for HostAlgorithmTest and is intended - ///to contain all HostAlgorithmTest Unit Tests - /// - [TestClass()] - public class HostAlgorithmTest : TestBase - { - internal virtual HostAlgorithm CreateHostAlgorithm() - { - // TODO: Instantiate an appropriate concrete class. - HostAlgorithm target = null; - return target; - } - - /// - ///A test for Sign - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SignTest() - { - HostAlgorithm target = CreateHostAlgorithm(); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Sign(data); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for VerifySignature - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void VerifySignatureTest() - { - HostAlgorithm target = CreateHostAlgorithm(); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - byte[] signature = null; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - actual = target.VerifySignature(data, signature); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Data - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DataTest() - { - HostAlgorithm target = CreateHostAlgorithm(); // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Data; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupExchangeSha1Test.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupExchangeSha1Test.cs deleted file mode 100644 index 980733e09..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupExchangeSha1Test.cs +++ /dev/null @@ -1,13 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - /// - /// Represents "diffie-hellman-group-exchange-sha1" algorithm implementation. - /// - [TestClass] - public class KeyExchangeDiffieHellmanGroupExchangeSha1Test : TestBase - { - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupExchangeSha256Test.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupExchangeSha256Test.cs deleted file mode 100644 index 5a0baf353..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupExchangeSha256Test.cs +++ /dev/null @@ -1,65 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Messages.Transport; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - /// - ///This is a test class for KeyExchangeDiffieHellmanGroupExchangeSha256Test and is intended - ///to contain all KeyExchangeDiffieHellmanGroupExchangeSha256Test Unit Tests - /// - [TestClass] - public class KeyExchangeDiffieHellmanGroupExchangeSha256Test : TestBase - { - /// - ///A test for KeyExchangeDiffieHellmanGroupExchangeSha256 Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyExchangeDiffieHellmanGroupExchangeSha256ConstructorTest() - { - KeyExchangeDiffieHellmanGroupExchangeSha256 target = new KeyExchangeDiffieHellmanGroupExchangeSha256(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for Finish - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void FinishTest() - { - KeyExchangeDiffieHellmanGroupExchangeSha256 target = new KeyExchangeDiffieHellmanGroupExchangeSha256(); // TODO: Initialize to an appropriate value - target.Finish(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Start - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void StartTest() - { - KeyExchangeDiffieHellmanGroupExchangeSha256 target = new KeyExchangeDiffieHellmanGroupExchangeSha256(); // TODO: Initialize to an appropriate value - Session session = null; // TODO: Initialize to an appropriate value - KeyExchangeInitMessage message = null; // TODO: Initialize to an appropriate value - target.Start(session, message); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Name - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void NameTest() - { - KeyExchangeDiffieHellmanGroupExchangeSha256 target = new KeyExchangeDiffieHellmanGroupExchangeSha256(); // TODO: Initialize to an appropriate value - string actual; - actual = target.Name; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupSha1Test.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupSha1Test.cs deleted file mode 100644 index 40d6b3b80..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroupSha1Test.cs +++ /dev/null @@ -1,62 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Messages.Transport; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - /// - ///This is a test class for KeyExchangeDiffieHellmanGroupSha1Test and is intended - ///to contain all KeyExchangeDiffieHellmanGroupSha1Test Unit Tests - /// - [TestClass()] - public class KeyExchangeDiffieHellmanGroupSha1Test : TestBase - { - internal virtual KeyExchangeDiffieHellmanGroupSha1 CreateKeyExchangeDiffieHellmanGroupSha1() - { - // TODO: Instantiate an appropriate concrete class. - KeyExchangeDiffieHellmanGroupSha1 target = null; - return target; - } - - /// - ///A test for Finish - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void FinishTest() - { - KeyExchangeDiffieHellmanGroupSha1 target = CreateKeyExchangeDiffieHellmanGroupSha1(); // TODO: Initialize to an appropriate value - target.Finish(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Start - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void StartTest() - { - KeyExchangeDiffieHellmanGroupSha1 target = CreateKeyExchangeDiffieHellmanGroupSha1(); // TODO: Initialize to an appropriate value - Session session = null; // TODO: Initialize to an appropriate value - KeyExchangeInitMessage message = null; // TODO: Initialize to an appropriate value - target.Start(session, message); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for GroupPrime - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GroupPrimeTest() - { - KeyExchangeDiffieHellmanGroupSha1 target = CreateKeyExchangeDiffieHellmanGroupSha1(); // TODO: Initialize to an appropriate value - BigInteger actual; - actual = target.GroupPrime; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanTest.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanTest.cs deleted file mode 100644 index 98b738588..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanTest.cs +++ /dev/null @@ -1,36 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Messages.Transport; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - /// - ///This is a test class for KeyExchangeDiffieHellmanTest and is intended - ///to contain all KeyExchangeDiffieHellmanTest Unit Tests - /// - [TestClass()] - public class KeyExchangeDiffieHellmanTest : TestBase - { - internal virtual KeyExchangeDiffieHellman CreateKeyExchangeDiffieHellman() - { - // TODO: Instantiate an appropriate concrete class. - KeyExchangeDiffieHellman target = null; - return target; - } - - /// - ///A test for Start - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void StartTest() - { - KeyExchangeDiffieHellman target = CreateKeyExchangeDiffieHellman(); // TODO: Initialize to an appropriate value - Session session = null; // TODO: Initialize to an appropriate value - KeyExchangeInitMessage message = null; // TODO: Initialize to an appropriate value - target.Start(session, message); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeTest.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeTest.cs deleted file mode 100644 index a288292ee..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeTest.cs +++ /dev/null @@ -1,16 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests -{ - /// - ///This is a test class for KeyExchangeTest and is intended - ///to contain all KeyExchangeTest Unit Tests - /// - [TestClass()] - public class KeyExchangeTest : TestBase - { - - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyTest.cs b/src/Renci.SshNet.Tests/Classes/Security/KeyTest.cs deleted file mode 100644 index bbbbacff1..000000000 --- a/src/Renci.SshNet.Tests/Classes/Security/KeyTest.cs +++ /dev/null @@ -1,84 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Security; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Security -{ - /// - ///This is a test class for KeyTest and is intended - ///to contain all KeyTest Unit Tests - /// - [TestClass()] - public class KeyTest : TestBase - { - internal virtual Key CreateKey() - { - // TODO: Instantiate an appropriate concrete class. - Key target = null; - return target; - } - - /// - ///A test for Sign - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SignTest() - { - Key target = CreateKey(); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.Sign(data); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for VerifySignature - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void VerifySignatureTest() - { - Key target = CreateKey(); // TODO: Initialize to an appropriate value - byte[] data = null; // TODO: Initialize to an appropriate value - byte[] signature = null; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - actual = target.VerifySignature(data, signature); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for KeyLength - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void KeyLengthTest() - { - Key target = CreateKey(); // TODO: Initialize to an appropriate value - int actual; - actual = target.KeyLength; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Public - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void PublicTest() - { - Key target = CreateKey(); // TODO: Initialize to an appropriate value - BigInteger[] expected = null; // TODO: Initialize to an appropriate value - BigInteger[] actual; - target.Public = expected; - actual = target.Public; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileAttributesTest.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileAttributesTest.cs deleted file mode 100644 index db54be81b..000000000 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileAttributesTest.cs +++ /dev/null @@ -1,238 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Sftp; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Sftp -{ - /// - ///This is a test class for SftpFileAttributesTest and is intended - ///to contain all SftpFileAttributesTest Unit Tests - /// - [TestClass] - [Ignore] // placeholders only - public class SftpFileAttributesTest : TestBase - { - /// - ///A test for SetPermissions - /// - [TestMethod()] - public void SetPermissionsTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - short mode = 0; // TODO: Initialize to an appropriate value - target.SetPermissions(mode); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for GroupCanExecute - /// - [TestMethod()] - public void GroupCanExecuteTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.GroupCanExecute = expected; - actual = target.GroupCanExecute; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for GroupCanRead - /// - [TestMethod()] - public void GroupCanReadTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.GroupCanRead = expected; - actual = target.GroupCanRead; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for GroupCanWrite - /// - [TestMethod()] - public void GroupCanWriteTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.GroupCanWrite = expected; - actual = target.GroupCanWrite; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for GroupId - /// - [TestMethod()] - public void GroupIdTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - target.GroupId = expected; - actual = target.GroupId; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for LastAccessTime - /// - [TestMethod()] - public void LastAccessTimeTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - DateTime expected = new DateTime(); // TODO: Initialize to an appropriate value - DateTime actual; - target.LastAccessTime = expected; - actual = target.LastAccessTime; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for LastWriteTime - /// - [TestMethod()] - public void LastWriteTimeTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - DateTime expected = new DateTime(); // TODO: Initialize to an appropriate value - DateTime actual; - target.LastWriteTime = expected; - actual = target.LastWriteTime; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OthersCanExecute - /// - [TestMethod()] - public void OthersCanExecuteTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.OthersCanExecute = expected; - actual = target.OthersCanExecute; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OthersCanRead - /// - [TestMethod()] - public void OthersCanReadTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.OthersCanRead = expected; - actual = target.OthersCanRead; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OthersCanWrite - /// - [TestMethod()] - public void OthersCanWriteTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.OthersCanWrite = expected; - actual = target.OthersCanWrite; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OwnerCanExecute - /// - [TestMethod()] - public void OwnerCanExecuteTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.OwnerCanExecute = expected; - actual = target.OwnerCanExecute; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OwnerCanRead - /// - [TestMethod()] - public void OwnerCanReadTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.OwnerCanRead = expected; - actual = target.OwnerCanRead; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OwnerCanWrite - /// - [TestMethod()] - public void OwnerCanWriteTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.OwnerCanWrite = expected; - actual = target.OwnerCanWrite; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Size - /// - [TestMethod()] - public void SizeTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - long expected = 0; // TODO: Initialize to an appropriate value - long actual; - target.Size = expected; - actual = target.Size; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for UserId - /// - [TestMethod()] - public void UserIdTest() - { - SftpFileAttributes target = SftpFileAttributes.Empty; // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - target.UserId = expected; - actual = target.UserId; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering.cs index 29b683375..87a7df9ad 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering.cs @@ -7,7 +7,6 @@ namespace Renci.SshNet.Tests.Classes.Sftp { [TestClass] - //[Ignore] public class SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering : SftpFileStreamTestBase { private Random _random; diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs index c5efd3ad8..3e4702e17 100644 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs +++ b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs @@ -8,7 +8,6 @@ namespace Renci.SshNet.Tests.Classes.Sftp { [TestClass] - //[Ignore] public class SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer : SftpFileStreamTestBase { private Random _random; diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileSystemInformationTest.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileSystemInformationTest.cs deleted file mode 100644 index 22262af79..000000000 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileSystemInformationTest.cs +++ /dev/null @@ -1,62 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Sftp; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Sftp -{ - /// - ///This is a test class for SftpFileSytemInformationTest and is intended - ///to contain all SftpFileSytemInformationTest Unit Tests - /// - [TestClass] - public class SftpFileSystemInformationTest : TestBase - { - /// - ///A test for IsReadOnly - /// - [TestMethod] - [Ignore] // placeholder - public void IsReadOnlyTest() - { - ulong bsize = 0; // TODO: Initialize to an appropriate value - ulong frsize = 0; // TODO: Initialize to an appropriate value - ulong blocks = 0; // TODO: Initialize to an appropriate value - ulong bfree = 0; // TODO: Initialize to an appropriate value - ulong bavail = 0; // TODO: Initialize to an appropriate value - ulong files = 0; // TODO: Initialize to an appropriate value - ulong ffree = 0; // TODO: Initialize to an appropriate value - ulong favail = 0; // TODO: Initialize to an appropriate value - ulong sid = 0; // TODO: Initialize to an appropriate value - ulong flag = 0; // TODO: Initialize to an appropriate value - ulong namemax = 0; // TODO: Initialize to an appropriate value - SftpFileSytemInformation target = new SftpFileSytemInformation(bsize, frsize, blocks, bfree, bavail, files, ffree, favail, sid, flag, namemax); // TODO: Initialize to an appropriate value - bool actual; - actual = target.IsReadOnly; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for SupportsSetUid - /// - [TestMethod] - [Ignore] // placeholder - public void SupportsSetUidTest() - { - ulong bsize = 0; // TODO: Initialize to an appropriate value - ulong frsize = 0; // TODO: Initialize to an appropriate value - ulong blocks = 0; // TODO: Initialize to an appropriate value - ulong bfree = 0; // TODO: Initialize to an appropriate value - ulong bavail = 0; // TODO: Initialize to an appropriate value - ulong files = 0; // TODO: Initialize to an appropriate value - ulong ffree = 0; // TODO: Initialize to an appropriate value - ulong favail = 0; // TODO: Initialize to an appropriate value - ulong sid = 0; // TODO: Initialize to an appropriate value - ulong flag = 0; // TODO: Initialize to an appropriate value - ulong namemax = 0; // TODO: Initialize to an appropriate value - SftpFileSytemInformation target = new SftpFileSytemInformation(bsize, frsize, blocks, bfree, bavail, files, ffree, favail, sid, flag, namemax); // TODO: Initialize to an appropriate value - bool actual; - actual = target.SupportsSetUid; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileTest.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileTest.cs deleted file mode 100644 index 285d4aa51..000000000 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileTest.cs +++ /dev/null @@ -1,510 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Sftp; -using Renci.SshNet.Tests.Common; - -using System; - -namespace Renci.SshNet.Tests.Classes.Sftp -{ - /// - /// Represents SFTP file information - /// - [TestClass] - public class SftpFileTest : TestBase - { - /// - ///A test for Delete - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DeleteTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - target.Delete(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for MoveTo - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void MoveToTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - string destFileName = string.Empty; // TODO: Initialize to an appropriate value - target.MoveTo(destFileName); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for SetPermissions - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SetPermissionsTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - short mode = 0; // TODO: Initialize to an appropriate value - target.SetPermissions(mode); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for ToString - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ToStringTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - string expected = string.Empty; // TODO: Initialize to an appropriate value - string actual; - actual = target.ToString(); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for UpdateStatus - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void UpdateStatusTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - target.UpdateStatus(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for GroupCanExecute - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GroupCanExecuteTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.GroupCanExecute = expected; - actual = target.GroupCanExecute; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for GroupCanRead - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GroupCanReadTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.GroupCanRead = expected; - actual = target.GroupCanRead; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for GroupCanWrite - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GroupCanWriteTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.GroupCanWrite = expected; - actual = target.GroupCanWrite; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for GroupId - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GroupIdTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - target.GroupId = expected; - actual = target.GroupId; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for IsBlockDevice - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void IsBlockDeviceTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool actual; - actual = target.IsBlockDevice; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for IsCharacterDevice - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void IsCharacterDeviceTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool actual; - actual = target.IsCharacterDevice; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for IsDirectory - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void IsDirectoryTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool actual; - actual = target.IsDirectory; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for IsNamedPipe - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void IsNamedPipeTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool actual; - actual = target.IsNamedPipe; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for IsRegularFile - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void IsRegularFileTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool actual; - actual = target.IsRegularFile; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for IsSocket - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void IsSocketTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool actual; - actual = target.IsSocket; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for IsSymbolicLink - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void IsSymbolicLinkTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool actual; - actual = target.IsSymbolicLink; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for LastAccessTime - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void LastAccessTimeTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - DateTime expected = new DateTime(); // TODO: Initialize to an appropriate value - DateTime actual; - target.LastAccessTime = expected; - actual = target.LastAccessTime; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for LastAccessTimeUtc - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void LastAccessTimeUtcTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - DateTime expected = new DateTime(); // TODO: Initialize to an appropriate value - DateTime actual; - target.LastAccessTimeUtc = expected; - actual = target.LastAccessTimeUtc; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for LastWriteTime - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void LastWriteTimeTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - DateTime expected = new DateTime(); // TODO: Initialize to an appropriate value - DateTime actual; - target.LastWriteTime = expected; - actual = target.LastWriteTime; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for LastWriteTimeUtc - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void LastWriteTimeUtcTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - DateTime expected = new DateTime(); // TODO: Initialize to an appropriate value - DateTime actual; - target.LastWriteTimeUtc = expected; - actual = target.LastWriteTimeUtc; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Length - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void LengthTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - long actual; - actual = target.Length; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OthersCanExecute - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OthersCanExecuteTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.OthersCanExecute = expected; - actual = target.OthersCanExecute; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OthersCanRead - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OthersCanReadTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.OthersCanRead = expected; - actual = target.OthersCanRead; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OthersCanWrite - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OthersCanWriteTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.OthersCanWrite = expected; - actual = target.OthersCanWrite; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OwnerCanExecute - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OwnerCanExecuteTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.OwnerCanExecute = expected; - actual = target.OwnerCanExecute; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OwnerCanRead - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OwnerCanReadTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.OwnerCanRead = expected; - actual = target.OwnerCanRead; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OwnerCanWrite - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OwnerCanWriteTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - target.OwnerCanWrite = expected; - actual = target.OwnerCanWrite; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for UserId - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void UserIdTest() - { - SftpSession sftpSession = null; // TODO: Initialize to an appropriate value - string fullName = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes attributes = null; // TODO: Initialize to an appropriate value - SftpFile target = new SftpFile(sftpSession, fullName, attributes); // TODO: Initialize to an appropriate value - int expected = 0; // TODO: Initialize to an appropriate value - int actual; - target.UserId = expected; - actual = target.UserId; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpListDirectoryAsyncResultTest.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpListDirectoryAsyncResultTest.cs deleted file mode 100644 index 8195330a9..000000000 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpListDirectoryAsyncResultTest.cs +++ /dev/null @@ -1,28 +0,0 @@ -锘縰sing Renci.SshNet.Sftp; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests -{ - /// - ///This is a test class for SftpListDirectoryAsyncResultTest and is intended - ///to contain all SftpListDirectoryAsyncResultTest Unit Tests - /// - [TestClass] - public class SftpListDirectoryAsyncResultTest : TestBase - { - /// - ///A test for SftpListDirectoryAsyncResult Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void SftpListDirectoryAsyncResultConstructorTest() - { - AsyncCallback asyncCallback = null; // TODO: Initialize to an appropriate value - object state = null; // TODO: Initialize to an appropriate value - SftpListDirectoryAsyncResult target = new SftpListDirectoryAsyncResult(asyncCallback, state); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpSynchronizeDirectoriesAsyncResultTest.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpSynchronizeDirectoriesAsyncResultTest.cs deleted file mode 100644 index a2230ea05..000000000 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpSynchronizeDirectoriesAsyncResultTest.cs +++ /dev/null @@ -1,28 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Sftp; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Sftp -{ - /// - ///This is a test class for SftpSynchronizeDirectoriesAsyncResultTest and is intended - ///to contain all SftpSynchronizeDirectoriesAsyncResultTest Unit Tests - /// - [TestClass] - public class SftpSynchronizeDirectoriesAsyncResultTest : TestBase - { - /// - ///A test for SftpSynchronizeDirectoriesAsyncResult Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void SftpSynchronizeDirectoriesAsyncResultConstructorTest() - { - AsyncCallback asyncCallback = null; // TODO: Initialize to an appropriate value - object state = null; // TODO: Initialize to an appropriate value - SftpSynchronizeDirectoriesAsyncResult target = new SftpSynchronizeDirectoriesAsyncResult(asyncCallback, state); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpUploadAsyncResultTest.cs b/src/Renci.SshNet.Tests/Classes/Sftp/SftpUploadAsyncResultTest.cs deleted file mode 100644 index 20cd7dc89..000000000 --- a/src/Renci.SshNet.Tests/Classes/Sftp/SftpUploadAsyncResultTest.cs +++ /dev/null @@ -1,28 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Sftp; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Sftp -{ - /// - ///This is a test class for SftpUploadAsyncResultTest and is intended - ///to contain all SftpUploadAsyncResultTest Unit Tests - /// - [TestClass] - public class SftpUploadAsyncResultTest : TestBase - { - /// - ///A test for SftpUploadAsyncResult Constructor - /// - [TestMethod] - [Ignore] // placeholder - public void SftpUploadAsyncResultConstructorTest() - { - AsyncCallback asyncCallback = null; // TODO: Initialize to an appropriate value - object state = null; // TODO: Initialize to an appropriate value - SftpUploadAsyncResult target = new SftpUploadAsyncResult(asyncCallback, state); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs index 9e1c1f3c7..25624dcc7 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs @@ -1,10 +1,6 @@ 锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Sftp; using Renci.SshNet.Tests.Common; using System; -using System.Collections.Generic; -using System.IO; -using System.Text; namespace Renci.SshNet.Tests.Classes { @@ -147,1211 +143,5 @@ public void OperationTimeout_Disposed() Assert.AreEqual(typeof(SftpClient).FullName, ex.ObjectName); } } - - /// - ///A test for SftpClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SftpClientConstructorTest() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(host, username, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SftpClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SftpClientConstructorTest1() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(host, port, username, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SftpClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SftpClientConstructorTest2() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(host, username, password); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SftpClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SftpClientConstructorTest3() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(host, port, username, password); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SftpClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SftpClientConstructorTest4() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ChangePermissions - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ChangePermissionsTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - short mode = 0; // TODO: Initialize to an appropriate value - target.ChangePermissions(path, mode); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for ChangeDirectory - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ChangeDirectoryTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - target.ChangeDirectory(path); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for BeginUploadFile - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void BeginUploadFileTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - Stream input = null; // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - AsyncCallback asyncCallback = null; // TODO: Initialize to an appropriate value - object state = null; // TODO: Initialize to an appropriate value - Action uploadCallback = null; // TODO: Initialize to an appropriate value - IAsyncResult expected = null; // TODO: Initialize to an appropriate value - IAsyncResult actual; - actual = target.BeginUploadFile(input, path, asyncCallback, state, uploadCallback); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for BeginUploadFile - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void BeginUploadFileTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - Stream input = null; // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - bool canOverride = false; // TODO: Initialize to an appropriate value - AsyncCallback asyncCallback = null; // TODO: Initialize to an appropriate value - object state = null; // TODO: Initialize to an appropriate value - Action uploadCallback = null; // TODO: Initialize to an appropriate value - IAsyncResult expected = null; // TODO: Initialize to an appropriate value - IAsyncResult actual; - actual = target.BeginUploadFile(input, path, canOverride, asyncCallback, state, uploadCallback); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for BeginSynchronizeDirectories - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void BeginSynchronizeDirectoriesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string sourcePath = string.Empty; // TODO: Initialize to an appropriate value - string destinationPath = string.Empty; // TODO: Initialize to an appropriate value - string searchPattern = string.Empty; // TODO: Initialize to an appropriate value - AsyncCallback asyncCallback = null; // TODO: Initialize to an appropriate value - object state = null; // TODO: Initialize to an appropriate value - IAsyncResult expected = null; // TODO: Initialize to an appropriate value - IAsyncResult actual; - actual = target.BeginSynchronizeDirectories(sourcePath, destinationPath, searchPattern, asyncCallback, state); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for BeginListDirectory - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void BeginListDirectoryTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - AsyncCallback asyncCallback = null; // TODO: Initialize to an appropriate value - object state = null; // TODO: Initialize to an appropriate value - Action listCallback = null; // TODO: Initialize to an appropriate value - IAsyncResult expected = null; // TODO: Initialize to an appropriate value - IAsyncResult actual; - actual = target.BeginListDirectory(path, asyncCallback, state, listCallback); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for BeginDownloadFile - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void BeginDownloadFileTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - Stream output = null; // TODO: Initialize to an appropriate value - AsyncCallback asyncCallback = null; // TODO: Initialize to an appropriate value - object state = null; // TODO: Initialize to an appropriate value - Action downloadCallback = null; // TODO: Initialize to an appropriate value - IAsyncResult expected = null; // TODO: Initialize to an appropriate value - IAsyncResult actual; - actual = target.BeginDownloadFile(path, output, asyncCallback, state, downloadCallback); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for AppendText - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AppendTextTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - StreamWriter expected = null; // TODO: Initialize to an appropriate value - StreamWriter actual; - actual = target.AppendText(path, encoding); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for AppendText - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AppendTextTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - StreamWriter expected = null; // TODO: Initialize to an appropriate value - StreamWriter actual; - actual = target.AppendText(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for AppendAllText - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AppendAllTextTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - string contents = string.Empty; // TODO: Initialize to an appropriate value - target.AppendAllText(path, contents); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for AppendAllText - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AppendAllTextTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - string contents = string.Empty; // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - target.AppendAllText(path, contents, encoding); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for AppendAllLines - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AppendAllLinesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - IEnumerable contents = null; // TODO: Initialize to an appropriate value - target.AppendAllLines(path, contents); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for AppendAllLines - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AppendAllLinesTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - IEnumerable contents = null; // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - target.AppendAllLines(path, contents, encoding); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for CreateText - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateTextTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - StreamWriter expected = null; // TODO: Initialize to an appropriate value - StreamWriter actual; - actual = target.CreateText(path, encoding); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CreateText - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateTextTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - StreamWriter expected = null; // TODO: Initialize to an appropriate value - StreamWriter actual; - actual = target.CreateText(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CreateDirectory - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateDirectoryTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - target.CreateDirectory(path); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Create - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - int bufferSize = 0; // TODO: Initialize to an appropriate value - SftpFileStream expected = null; // TODO: Initialize to an appropriate value - SftpFileStream actual; - actual = target.Create(path, bufferSize); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Create - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - SftpFileStream expected = null; // TODO: Initialize to an appropriate value - SftpFileStream actual; - actual = target.Create(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EndSynchronizeDirectories - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EndSynchronizeDirectoriesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - IAsyncResult asyncResult = null; // TODO: Initialize to an appropriate value - IEnumerable expected = null; // TODO: Initialize to an appropriate value - IEnumerable actual; - actual = target.EndSynchronizeDirectories(asyncResult); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EndListDirectory - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EndListDirectoryTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - IAsyncResult asyncResult = null; // TODO: Initialize to an appropriate value - IEnumerable expected = null; // TODO: Initialize to an appropriate value - IEnumerable actual; - actual = target.EndListDirectory(asyncResult); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EndDownloadFile - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EndDownloadFileTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - IAsyncResult asyncResult = null; // TODO: Initialize to an appropriate value - target.EndDownloadFile(asyncResult); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for DownloadFile - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DownloadFileTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - Stream output = null; // TODO: Initialize to an appropriate value - Action downloadCallback = null; // TODO: Initialize to an appropriate value - target.DownloadFile(path, output, downloadCallback); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for DeleteFile - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DeleteFileTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - target.DeleteFile(path); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for DeleteDirectory - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DeleteDirectoryTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - target.DeleteDirectory(path); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Delete - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void DeleteTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - target.Delete(path); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for GetLastAccessTimeUtc - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GetLastAccessTimeUtcTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - DateTime expected = new DateTime(); // TODO: Initialize to an appropriate value - DateTime actual; - actual = target.GetLastAccessTimeUtc(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for GetLastAccessTime - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GetLastAccessTimeTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - DateTime expected = new DateTime(); // TODO: Initialize to an appropriate value - DateTime actual; - actual = target.GetLastAccessTime(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for GetAttributes - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GetAttributesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes expected = null; // TODO: Initialize to an appropriate value - SftpFileAttributes actual; - actual = target.GetAttributes(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Get - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GetTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - ISftpFile expected = null; // TODO: Initialize to an appropriate value - ISftpFile actual; - actual = target.Get(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Exists - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ExistsTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - bool expected = false; // TODO: Initialize to an appropriate value - bool actual; - actual = target.Exists(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for EndUploadFile - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void EndUploadFileTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - IAsyncResult asyncResult = null; // TODO: Initialize to an appropriate value - target.EndUploadFile(asyncResult); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for GetLastWriteTimeUtc - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GetLastWriteTimeUtcTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - DateTime expected = new DateTime(); // TODO: Initialize to an appropriate value - DateTime actual; - actual = target.GetLastWriteTimeUtc(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for GetLastWriteTime - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GetLastWriteTimeTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - DateTime expected = new DateTime(); // TODO: Initialize to an appropriate value - DateTime actual; - actual = target.GetLastWriteTime(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for GetStatus - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void GetStatusTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - SftpFileSytemInformation expected = null; // TODO: Initialize to an appropriate value - SftpFileSytemInformation actual; - actual = target.GetStatus(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ListDirectory - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ListDirectoryTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - Action listCallback = null; // TODO: Initialize to an appropriate value - IEnumerable expected = null; // TODO: Initialize to an appropriate value - IEnumerable actual; - actual = target.ListDirectory(path, listCallback); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Open - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OpenTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - FileMode mode = new FileMode(); // TODO: Initialize to an appropriate value - SftpFileStream expected = null; // TODO: Initialize to an appropriate value - SftpFileStream actual; - actual = target.Open(path, mode); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Open - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OpenTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - FileMode mode = new FileMode(); // TODO: Initialize to an appropriate value - FileAccess access = new FileAccess(); // TODO: Initialize to an appropriate value - SftpFileStream expected = null; // TODO: Initialize to an appropriate value - SftpFileStream actual; - actual = target.Open(path, mode, access); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OpenRead - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OpenReadTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - SftpFileStream expected = null; // TODO: Initialize to an appropriate value - SftpFileStream actual; - actual = target.OpenRead(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OpenText - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OpenTextTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - StreamReader expected = null; // TODO: Initialize to an appropriate value - StreamReader actual; - actual = target.OpenText(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OpenWrite - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OpenWriteTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - SftpFileStream expected = null; // TODO: Initialize to an appropriate value - SftpFileStream actual; - actual = target.OpenWrite(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ReadAllBytes - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ReadAllBytesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - actual = target.ReadAllBytes(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ReadAllLines - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ReadAllLinesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - string[] actual; - actual = target.ReadAllLines(path, encoding); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ReadAllLines - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ReadAllLinesTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - string[] expected = null; // TODO: Initialize to an appropriate value - string[] actual; - actual = target.ReadAllLines(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ReadAllText - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ReadAllTextTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - string expected = string.Empty; // TODO: Initialize to an appropriate value - string actual; - actual = target.ReadAllText(path, encoding); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ReadAllText - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ReadAllTextTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - string expected = string.Empty; // TODO: Initialize to an appropriate value - string actual; - actual = target.ReadAllText(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ReadLines - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ReadLinesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - IEnumerable expected = null; // TODO: Initialize to an appropriate value - IEnumerable actual; - actual = target.ReadLines(path); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ReadLines - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ReadLinesTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - IEnumerable expected = null; // TODO: Initialize to an appropriate value - IEnumerable actual; - actual = target.ReadLines(path, encoding); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for RenameFile - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void RenameFileTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string oldPath = string.Empty; // TODO: Initialize to an appropriate value - string newPath = string.Empty; // TODO: Initialize to an appropriate value - target.RenameFile(oldPath, newPath); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for RenameFile - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void RenameFileTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string oldPath = string.Empty; // TODO: Initialize to an appropriate value - string newPath = string.Empty; // TODO: Initialize to an appropriate value - bool isPosix = false; // TODO: Initialize to an appropriate value - target.RenameFile(oldPath, newPath, isPosix); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for SetAttributes - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SetAttributesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - SftpFileAttributes fileAttributes = null; // TODO: Initialize to an appropriate value - target.SetAttributes(path, fileAttributes); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for SetLastAccessTime - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SetLastAccessTimeTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - DateTime lastAccessTime = new DateTime(); // TODO: Initialize to an appropriate value -#pragma warning disable CS0618 // Type or member is obsolete - target.SetLastAccessTime(path, lastAccessTime); -#pragma warning restore CS0618 // Type or member is obsolete - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for SetLastAccessTimeUtc - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SetLastAccessTimeUtcTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - DateTime lastAccessTimeUtc = new DateTime(); // TODO: Initialize to an appropriate value -#pragma warning disable CS0618 // Type or member is obsolete - target.SetLastAccessTimeUtc(path, lastAccessTimeUtc); -#pragma warning restore CS0618 // Type or member is obsolete - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for SetLastWriteTime - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SetLastWriteTimeTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - DateTime lastWriteTime = new DateTime(); // TODO: Initialize to an appropriate value -#pragma warning disable CS0618 // Type or member is obsolete - target.SetLastWriteTime(path, lastWriteTime); -#pragma warning restore CS0618 // Type or member is obsolete - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for SetLastWriteTimeUtc - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SetLastWriteTimeUtcTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - DateTime lastWriteTimeUtc = new DateTime(); // TODO: Initialize to an appropriate value -#pragma warning disable CS0618 // Type or member is obsolete - target.SetLastWriteTimeUtc(path, lastWriteTimeUtc); -#pragma warning restore CS0618 // Type or member is obsolete - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for SymbolicLink - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SymbolicLinkTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - string linkPath = string.Empty; // TODO: Initialize to an appropriate value - target.SymbolicLink(path, linkPath); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for SynchronizeDirectories - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SynchronizeDirectoriesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string sourcePath = string.Empty; // TODO: Initialize to an appropriate value - string destinationPath = string.Empty; // TODO: Initialize to an appropriate value - string searchPattern = string.Empty; // TODO: Initialize to an appropriate value - IEnumerable expected = null; // TODO: Initialize to an appropriate value - IEnumerable actual; - actual = target.SynchronizeDirectories(sourcePath, destinationPath, searchPattern); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for UploadFile - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void UploadFileTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - Stream input = null; // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - Action uploadCallback = null; // TODO: Initialize to an appropriate value - target.UploadFile(input, path, uploadCallback); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for UploadFile - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void UploadFileTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - Stream input = null; // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - bool canOverride = false; // TODO: Initialize to an appropriate value - Action uploadCallback = null; // TODO: Initialize to an appropriate value - target.UploadFile(input, path, canOverride, uploadCallback); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for WriteAllBytes - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void WriteAllBytesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - byte[] bytes = null; // TODO: Initialize to an appropriate value - target.WriteAllBytes(path, bytes); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for WriteAllLines - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void WriteAllLinesTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - IEnumerable contents = null; // TODO: Initialize to an appropriate value - target.WriteAllLines(path, contents); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for WriteAllLines - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void WriteAllLinesTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - string[] contents = null; // TODO: Initialize to an appropriate value - target.WriteAllLines(path, contents); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for WriteAllLines - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void WriteAllLinesTest2() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - IEnumerable contents = null; // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - target.WriteAllLines(path, contents, encoding); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for WriteAllLines - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void WriteAllLinesTest3() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - string[] contents = null; // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - target.WriteAllLines(path, contents, encoding); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for WriteAllText - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void WriteAllTextTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - string contents = string.Empty; // TODO: Initialize to an appropriate value - target.WriteAllText(path, contents); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for WriteAllText - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void WriteAllTextTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string path = string.Empty; // TODO: Initialize to an appropriate value - string contents = string.Empty; // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - target.WriteAllText(path, contents, encoding); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for BufferSize - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void BufferSizeTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - uint expected = 0; // TODO: Initialize to an appropriate value - uint actual; - target.BufferSize = expected; - actual = target.BufferSize; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for OperationTimeout - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void OperationTimeoutTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - TimeSpan expected = new TimeSpan(); // TODO: Initialize to an appropriate value - TimeSpan actual; - target.OperationTimeout = expected; - actual = target.OperationTimeout; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for WorkingDirectory - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void WorkingDirectoryTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SftpClient target = new SftpClient(connectionInfo); // TODO: Initialize to an appropriate value - string actual; - actual = target.WorkingDirectory; - Assert.Inconclusive("Verify the correctness of this test method."); - } } } diff --git a/src/Renci.SshNet.Tests/Classes/ShellTestTest.cs b/src/Renci.SshNet.Tests/Classes/ShellTestTest.cs deleted file mode 100644 index c7eceb1e6..000000000 --- a/src/Renci.SshNet.Tests/Classes/ShellTestTest.cs +++ /dev/null @@ -1,82 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; -using System.Collections.Generic; -using System.IO; - -namespace Renci.SshNet.Tests.Classes -{ - /// - /// Represents instance of the SSH shell object - /// - [TestClass] - [Ignore] // class contains just for unit tests - public partial class ShellTestTest : TestBase - { - /// - ///A test for Dispose - /// - [TestMethod()] - public void DisposeTest() - { - Session session = null; // TODO: Initialize to an appropriate value - Stream input = null; // TODO: Initialize to an appropriate value - Stream output = null; // TODO: Initialize to an appropriate value - Stream extendedOutput = null; // TODO: Initialize to an appropriate value - string terminalName = string.Empty; // TODO: Initialize to an appropriate value - uint columns = 0; // TODO: Initialize to an appropriate value - uint rows = 0; // TODO: Initialize to an appropriate value - uint width = 0; // TODO: Initialize to an appropriate value - uint height = 0; // TODO: Initialize to an appropriate value - IDictionary terminalModes = null; // TODO: Initialize to an appropriate value - int bufferSize = 0; // TODO: Initialize to an appropriate value - Shell target = new Shell(session, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize); // TODO: Initialize to an appropriate value - target.Dispose(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Start - /// - [TestMethod()] - public void StartTest() - { - Session session = null; // TODO: Initialize to an appropriate value - Stream input = null; // TODO: Initialize to an appropriate value - Stream output = null; // TODO: Initialize to an appropriate value - Stream extendedOutput = null; // TODO: Initialize to an appropriate value - string terminalName = string.Empty; // TODO: Initialize to an appropriate value - uint columns = 0; // TODO: Initialize to an appropriate value - uint rows = 0; // TODO: Initialize to an appropriate value - uint width = 0; // TODO: Initialize to an appropriate value - uint height = 0; // TODO: Initialize to an appropriate value - IDictionary terminalModes = null; // TODO: Initialize to an appropriate value - int bufferSize = 0; // TODO: Initialize to an appropriate value - Shell target = new Shell(session, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize); // TODO: Initialize to an appropriate value - target.Start(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for Stop - /// - [TestMethod()] - public void StopTest() - { - Session session = null; // TODO: Initialize to an appropriate value - Stream input = null; // TODO: Initialize to an appropriate value - Stream output = null; // TODO: Initialize to an appropriate value - Stream extendedOutput = null; // TODO: Initialize to an appropriate value - string terminalName = string.Empty; // TODO: Initialize to an appropriate value - uint columns = 0; // TODO: Initialize to an appropriate value - uint rows = 0; // TODO: Initialize to an appropriate value - uint width = 0; // TODO: Initialize to an appropriate value - uint height = 0; // TODO: Initialize to an appropriate value - IDictionary terminalModes = null; // TODO: Initialize to an appropriate value - int bufferSize = 0; // TODO: Initialize to an appropriate value - Shell target = new Shell(session, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize); // TODO: Initialize to an appropriate value - target.Stop(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - } -} \ No newline at end of file diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest.cs b/src/Renci.SshNet.Tests/Classes/SshClientTest.cs index 8ee74c2ca..e0012d7bd 100644 --- a/src/Renci.SshNet.Tests/Classes/SshClientTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SshClientTest.cs @@ -66,51 +66,6 @@ public void CreateShellStream2_NeverConnected() } } - /// - ///A test for CreateShellStream - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateShellStreamTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - string terminalName = string.Empty; // TODO: Initialize to an appropriate value - uint columns = 0; // TODO: Initialize to an appropriate value - uint rows = 0; // TODO: Initialize to an appropriate value - uint width = 0; // TODO: Initialize to an appropriate value - uint height = 0; // TODO: Initialize to an appropriate value - int bufferSize = 0; // TODO: Initialize to an appropriate value - IDictionary terminalModeValues = null; // TODO: Initialize to an appropriate value - ShellStream expected = null; // TODO: Initialize to an appropriate value - ShellStream actual; - actual = target.CreateShellStream(terminalName, columns, rows, width, height, bufferSize, terminalModeValues); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CreateShellStream - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateShellStreamTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - string terminalName = string.Empty; // TODO: Initialize to an appropriate value - uint columns = 0; // TODO: Initialize to an appropriate value - uint rows = 0; // TODO: Initialize to an appropriate value - uint width = 0; // TODO: Initialize to an appropriate value - uint height = 0; // TODO: Initialize to an appropriate value - int bufferSize = 0; // TODO: Initialize to an appropriate value - ShellStream expected = null; // TODO: Initialize to an appropriate value - ShellStream actual; - actual = target.CreateShellStream(terminalName, columns, rows, width, height, bufferSize); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - [TestMethod] public void CreateShell1_NeverConnected() { @@ -316,149 +271,6 @@ public void CreateShell6_NeverConnected() } } - /// - ///A test for CreateShell - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateShellTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - string input = string.Empty; // TODO: Initialize to an appropriate value - Stream output = null; // TODO: Initialize to an appropriate value - Stream extendedOutput = null; // TODO: Initialize to an appropriate value - Shell expected = null; // TODO: Initialize to an appropriate value - Shell actual; - actual = target.CreateShell(encoding, input, output, extendedOutput); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CreateShell - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateShellTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - string input = string.Empty; // TODO: Initialize to an appropriate value - Stream output = null; // TODO: Initialize to an appropriate value - Stream extendedOutput = null; // TODO: Initialize to an appropriate value - string terminalName = string.Empty; // TODO: Initialize to an appropriate value - uint columns = 0; // TODO: Initialize to an appropriate value - uint rows = 0; // TODO: Initialize to an appropriate value - uint width = 0; // TODO: Initialize to an appropriate value - uint height = 0; // TODO: Initialize to an appropriate value - IDictionary terminalModes = null; // TODO: Initialize to an appropriate value - Shell expected = null; // TODO: Initialize to an appropriate value - Shell actual; - actual = target.CreateShell(encoding, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CreateShell - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateShellTest2() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - string input = string.Empty; // TODO: Initialize to an appropriate value - Stream output = null; // TODO: Initialize to an appropriate value - Stream extendedOutput = null; // TODO: Initialize to an appropriate value - string terminalName = string.Empty; // TODO: Initialize to an appropriate value - uint columns = 0; // TODO: Initialize to an appropriate value - uint rows = 0; // TODO: Initialize to an appropriate value - uint width = 0; // TODO: Initialize to an appropriate value - uint height = 0; // TODO: Initialize to an appropriate value - IDictionary terminalModes = null; // TODO: Initialize to an appropriate value - int bufferSize = 0; // TODO: Initialize to an appropriate value - Shell expected = null; // TODO: Initialize to an appropriate value - Shell actual; - actual = target.CreateShell(encoding, input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CreateShell - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateShellTest3() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - Stream input = null; // TODO: Initialize to an appropriate value - Stream output = null; // TODO: Initialize to an appropriate value - Stream extendedOutput = null; // TODO: Initialize to an appropriate value - Shell expected = null; // TODO: Initialize to an appropriate value - Shell actual; - actual = target.CreateShell(input, output, extendedOutput); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CreateShell - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateShellTest4() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - Stream input = null; // TODO: Initialize to an appropriate value - Stream output = null; // TODO: Initialize to an appropriate value - Stream extendedOutput = null; // TODO: Initialize to an appropriate value - string terminalName = string.Empty; // TODO: Initialize to an appropriate value - uint columns = 0; // TODO: Initialize to an appropriate value - uint rows = 0; // TODO: Initialize to an appropriate value - uint width = 0; // TODO: Initialize to an appropriate value - uint height = 0; // TODO: Initialize to an appropriate value - IDictionary terminalModes = null; // TODO: Initialize to an appropriate value - Shell expected = null; // TODO: Initialize to an appropriate value - Shell actual; - actual = target.CreateShell(input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CreateShell - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateShellTest5() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - Stream input = null; // TODO: Initialize to an appropriate value - Stream output = null; // TODO: Initialize to an appropriate value - Stream extendedOutput = null; // TODO: Initialize to an appropriate value - string terminalName = string.Empty; // TODO: Initialize to an appropriate value - uint columns = 0; // TODO: Initialize to an appropriate value - uint rows = 0; // TODO: Initialize to an appropriate value - uint width = 0; // TODO: Initialize to an appropriate value - uint height = 0; // TODO: Initialize to an appropriate value - IDictionary terminalModes = null; // TODO: Initialize to an appropriate value - int bufferSize = 0; // TODO: Initialize to an appropriate value - Shell expected = null; // TODO: Initialize to an appropriate value - Shell actual; - actual = target.CreateShell(input, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - [TestMethod] public void CreateCommand_CommandText_NeverConnected() { @@ -495,42 +307,6 @@ public void CreateCommand_CommandTextAndEncoding_NeverConnected() } } - /// - ///A test for CreateCommand - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateCommandTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - string commandText = string.Empty; // TODO: Initialize to an appropriate value - Encoding encoding = null; // TODO: Initialize to an appropriate value - SshCommand expected = null; // TODO: Initialize to an appropriate value - SshCommand actual; - actual = target.CreateCommand(commandText, encoding); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CreateCommand - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CreateCommandTest1() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - string commandText = string.Empty; // TODO: Initialize to an appropriate value - SshCommand expected = null; // TODO: Initialize to an appropriate value - SshCommand actual; - actual = target.CreateCommand(commandText); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - [TestMethod] public void AddForwardedPort_NeverConnected() { @@ -551,105 +327,6 @@ public void AddForwardedPort_NeverConnected() } } - - /// - ///A test for AddForwardedPort - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void AddForwardedPortTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - ForwardedPort port = null; // TODO: Initialize to an appropriate value - target.AddForwardedPort(port); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - /// - ///A test for SshClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SshClientConstructorTest() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(host, username, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SshClientConstructorTest1() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - PrivateKeyFile[] keyFiles = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(host, port, username, keyFiles); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SshClientConstructorTest2() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(host, username, password); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SshClientConstructorTest3() - { - string host = string.Empty; // TODO: Initialize to an appropriate value - int port = 0; // TODO: Initialize to an appropriate value - string username = string.Empty; // TODO: Initialize to an appropriate value - string password = string.Empty; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(host, port, username, password); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshClient Constructor - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void SshClientConstructorTest4() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for RemoveForwardedPort - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void RemoveForwardedPortTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - ForwardedPort port = null; // TODO: Initialize to an appropriate value - target.RemoveForwardedPort(port); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - [TestMethod] public void RunCommand_CommandText_NeverConnected() { @@ -667,37 +344,5 @@ public void RunCommand_CommandText_NeverConnected() } } } - - /// - ///A test for RunCommand - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void RunCommandTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - string commandText = string.Empty; // TODO: Initialize to an appropriate value - SshCommand expected = null; // TODO: Initialize to an appropriate value - SshCommand actual; - actual = target.RunCommand(commandText); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for ForwardedPorts - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ForwardedPortsTest() - { - ConnectionInfo connectionInfo = null; // TODO: Initialize to an appropriate value - SshClient target = new SshClient(connectionInfo); // TODO: Initialize to an appropriate value - IEnumerable actual; - actual = target.ForwardedPorts; - Assert.Inconclusive("Verify the correctness of this test method."); - } - } } diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs b/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs index 3f5450952..13419a0da 100644 --- a/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs +++ b/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs @@ -3,7 +3,6 @@ using Renci.SshNet.Tests.Common; using Renci.SshNet.Tests.Properties; using System; -using System.Text; namespace Renci.SshNet.Tests.Classes { @@ -25,131 +24,6 @@ public void Test_Execute_SingleCommand_Without_Connecting() } } - /// - ///A test for BeginExecute - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void BeginExecuteTest1() - { - Session session = null; // TODO: Initialize to an appropriate value - string commandText = string.Empty; // TODO: Initialize to an appropriate value - var encoding = Encoding.UTF8; - SshCommand target = new SshCommand(session, commandText, encoding); // TODO: Initialize to an appropriate value - string commandText1 = string.Empty; // TODO: Initialize to an appropriate value - AsyncCallback callback = null; // TODO: Initialize to an appropriate value - object state = null; // TODO: Initialize to an appropriate value - IAsyncResult expected = null; // TODO: Initialize to an appropriate value - IAsyncResult actual; - actual = target.BeginExecute(commandText1, callback, state); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CancelAsync - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CancelAsyncTest() - { - Session session = null; // TODO: Initialize to an appropriate value - string commandText = string.Empty; // TODO: Initialize to an appropriate value - var encoding = Encoding.UTF8; - SshCommand target = new SshCommand(session, commandText, encoding); // TODO: Initialize to an appropriate value - target.CancelAsync(); - Assert.Inconclusive("A method that does not return a value cannot be verified."); - } - - - /// - ///A test for Execute - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ExecuteTest() - { - Session session = null; // TODO: Initialize to an appropriate value - string commandText = string.Empty; // TODO: Initialize to an appropriate value - var encoding = Encoding.UTF8; - SshCommand target = new SshCommand(session, commandText, encoding); // TODO: Initialize to an appropriate value - string expected = string.Empty; // TODO: Initialize to an appropriate value - string actual; - actual = target.Execute(); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Execute - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ExecuteTest1() - { - Session session = null; // TODO: Initialize to an appropriate value - string commandText = string.Empty; // TODO: Initialize to an appropriate value - var encoding = Encoding.UTF8; - SshCommand target = new SshCommand(session, commandText, encoding); // TODO: Initialize to an appropriate value - string commandText1 = string.Empty; // TODO: Initialize to an appropriate value - string expected = string.Empty; // TODO: Initialize to an appropriate value - string actual; - actual = target.Execute(commandText1); - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for CommandTimeout - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void CommandTimeoutTest() - { - Session session = null; // TODO: Initialize to an appropriate value - string commandText = string.Empty; // TODO: Initialize to an appropriate value - var encoding = Encoding.UTF8; - SshCommand target = new SshCommand(session, commandText, encoding); // TODO: Initialize to an appropriate value - TimeSpan expected = new TimeSpan(); // TODO: Initialize to an appropriate value - TimeSpan actual; - target.CommandTimeout = expected; - actual = target.CommandTimeout; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Error - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ErrorTest() - { - Session session = null; // TODO: Initialize to an appropriate value - string commandText = string.Empty; // TODO: Initialize to an appropriate value - var encoding = Encoding.UTF8; - SshCommand target = new SshCommand(session, commandText, encoding); // TODO: Initialize to an appropriate value - string actual; - actual = target.Error; - Assert.Inconclusive("Verify the correctness of this test method."); - } - - /// - ///A test for Result - /// - [TestMethod] - [Ignore] // placeholder for actual test - public void ResultTest() - { - Session session = null; // TODO: Initialize to an appropriate value - string commandText = string.Empty; // TODO: Initialize to an appropriate value - var encoding = Encoding.UTF8; - SshCommand target = new SshCommand(session, commandText, encoding); // TODO: Initialize to an appropriate value - string actual; - actual = target.Result; - Assert.Inconclusive("Verify the correctness of this test method."); - } - private static bool ExecuteTestCommand(SshClient s) { var testValue = Guid.NewGuid().ToString(); diff --git a/src/Renci.SshNet/Properties/AssemblyInfo.cs b/src/Renci.SshNet/Properties/AssemblyInfo.cs index 07f66e5fe..fe5eac0d1 100644 --- a/src/Renci.SshNet/Properties/AssemblyInfo.cs +++ b/src/Renci.SshNet/Properties/AssemblyInfo.cs @@ -6,4 +6,5 @@ [assembly: Guid("ad816c5e-6f13-4589-9f3e-59523f8b77a4")] [assembly: InternalsVisibleTo("Renci.SshNet.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f9194e1eb66b7e2575aaee115ee1d27bc100920e7150e43992d6f668f9737de8b9c7ae892b62b8a36dd1d57929ff1541665d101dc476d6e02390846efae7e5186eec409710fdb596e3f83740afef0d4443055937649bc5a773175b61c57615dac0f0fd10f52b52fedf76c17474cc567b3f7a79de95dde842509fb39aaf69c6c2")] [assembly: InternalsVisibleTo("Renci.SshNet.IntegrationTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f9194e1eb66b7e2575aaee115ee1d27bc100920e7150e43992d6f668f9737de8b9c7ae892b62b8a36dd1d57929ff1541665d101dc476d6e02390846efae7e5186eec409710fdb596e3f83740afef0d4443055937649bc5a773175b61c57615dac0f0fd10f52b52fedf76c17474cc567b3f7a79de95dde842509fb39aaf69c6c2")] +[assembly: InternalsVisibleTo("Renci.SshNet.Benchmarks, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f9194e1eb66b7e2575aaee115ee1d27bc100920e7150e43992d6f668f9737de8b9c7ae892b62b8a36dd1d57929ff1541665d101dc476d6e02390846efae7e5186eec409710fdb596e3f83740afef0d4443055937649bc5a773175b61c57615dac0f0fd10f52b52fedf76c17474cc567b3f7a79de95dde842509fb39aaf69c6c2")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] From f1297dec75fb2abe6f278a9b06b26e0c14277ef1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Sat, 14 Oct 2023 22:16:11 +0200 Subject: [PATCH 51/96] Move test projects (#1212) * Move test projects to test folder. Move global.json to root of repo. Update solution items in solution. * Move test projects to test folder. Move global.json to root of repo. Update solution items in solution. Update appveyor configuration/ * Attempt to have appveyor use the correct .NET SDK. * Update .NET SDK to version 7.0.402. * Move Data folder below Renci.SshNet.Tests. * Make csinst less chatty. * Move Data folder directly below test folder as it's used by multiple test projects. * Remove CS1591 nowarn from concrete test projects as this is already defined in the Directory.Build.props that is in the test folder. * Fix integration test after moving test projects --------- Co-authored-by: drieseng --- .gitignore | 2 +- Directory.Build.props | 2 +- Renci.SshNet.sln | 222 ++++++++++++++++++ src/Renci.SshNet.snk => Renci.SshNet.snk | Bin appveyor.yml | 11 +- global.json | 6 + .../Renci.SshNet.Benchmarks.csproj | 31 --- .../Renci.SshNet.TestTools.OpenSSH.csproj | 21 -- src/Renci.SshNet.sln | 174 -------------- {src => test}/Data/Key.ECDSA.Encrypted.txt | 0 {src => test}/Data/Key.ECDSA.txt | 0 {src => test}/Data/Key.ECDSA384.Encrypted.txt | 0 {src => test}/Data/Key.ECDSA384.txt | 0 {src => test}/Data/Key.ECDSA521.Encrypted.txt | 0 {src => test}/Data/Key.ECDSA521.txt | 0 .../Data/Key.OPENSSH.ECDSA.Encrypted.txt | 0 {src => test}/Data/Key.OPENSSH.ECDSA.txt | 0 .../Data/Key.OPENSSH.ECDSA384.Encrypted.txt | 0 {src => test}/Data/Key.OPENSSH.ECDSA384.txt | 0 .../Data/Key.OPENSSH.ECDSA521.Encrypted.txt | 0 {src => test}/Data/Key.OPENSSH.ECDSA521.txt | 0 .../Data/Key.OPENSSH.ED25519.Encrypted.txt | 0 {src => test}/Data/Key.OPENSSH.ED25519.txt | 0 .../Data/Key.OPENSSH.RSA.Encrypted.txt | 0 {src => test}/Data/Key.OPENSSH.RSA.txt | 0 .../Key.RSA.Encrypted.Aes.128.CBC.12345.txt | 0 .../Key.RSA.Encrypted.Aes.192.CBC.12345.txt | 0 .../Key.RSA.Encrypted.Aes.256.CBC.12345.txt | 0 .../Data/Key.RSA.Encrypted.Des.CBC.12345.txt | 0 .../Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt | 0 ....RSA.Encrypted.Des.Ede3.CFB.1234567890.txt | 0 {src => test}/Data/Key.RSA.txt | 0 .../Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt | 0 {src => test}/Data/Key.SSH2.DSA.txt | 0 .../Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt | 0 {src => test}/Data/Key.SSH2.RSA.txt | 0 .../Common/ExtensionsBenchmarks.cs | 0 .../Common/HostKeyEventArgsBenchmarks.cs | 0 .../Renci.SshNet.Benchmarks/Program.cs | 0 .../Renci.SshNet.Benchmarks.csproj | 20 ++ .../Ciphers/AesCipherBenchmarks.cs | 0 .../Ciphers/RsaCipherBenchmarks.cs | 0 .../ED25519DigitalSignatureBenchmarks.cs | 0 .../.editorconfig | 0 .../Renci.SshNet.IntegrationTests/.gitignore | 0 .../Renci.SshNet.IntegrationTests/App.config | 0 .../AuthenticationMethodFactory.cs | 0 .../AuthenticationTests.cs | 0 .../CipherTests.cs | 0 .../Common/ArrayBuilder.cs | 0 .../Common/AsyncSocketListener.cs | 0 .../Common/DateTimeAssert.cs | 0 .../Common/DateTimeExtensions.cs | 0 .../Common/RemoteSshdConfigExtensions.cs | 0 .../Common/Socks5Handler.cs | 0 .../ConnectivityTests.cs | 0 .../Credential.cs | 0 .../Renci.SshNet.IntegrationTests/Dockerfile | 0 .../HmacTests.cs | 0 .../HostConfig.cs | 0 .../HostKeyAlgorithmTests.cs | 0 .../HostKeyFile.cs | 0 .../IConnectionInfoFactory.cs | 0 .../KeyExchangeAlgorithmTests.cs | 0 .../LinuxAdminConnectionFactory.cs | 0 .../LinuxVMConnectionFactory.cs | 0 .../ForwardedPortLocalTest.cs | 0 .../OldIntegrationTests/ScpClientTest.cs | 0 .../SftpClientTest.ChangeDirectory.cs | 0 .../SftpClientTest.CreateDirectory.cs | 0 .../SftpClientTest.DeleteDirectory.cs | 0 .../SftpClientTest.Download.cs | 0 .../SftpClientTest.ListDirectory.cs | 0 .../SftpClientTest.RenameFile.cs | 0 .../SftpClientTest.RenameFileAsync.cs | 0 .../SftpClientTest.SynchronizeDirectories.cs | 0 .../SftpClientTest.Upload.cs | 0 .../OldIntegrationTests/SftpClientTest.cs | 0 .../OldIntegrationTests/SftpFileTest.cs | 0 .../OldIntegrationTests/SshCommandTest.cs | 0 .../PrivateKeyAuthenticationTests.cs | 0 .../Renci.SshNet.IntegrationTests/Program.cs | 0 .../RemoteSshd.cs | 0 .../Renci.SshNet.IntegrationTests.csproj | 18 +- .../ScpClientTests.cs | 0 .../Renci.SshNet.IntegrationTests/ScpTests.cs | 0 .../SftpClientTests.cs | 0 .../SftpTests.cs | 0 .../SshClientTests.cs | 0 .../SshConnectionDisruptor.cs | 0 .../SshConnectionRestorer.cs | 0 .../Renci.SshNet.IntegrationTests/SshTests.cs | 0 .../Renci.SshNet.IntegrationTests/TestBase.cs | 0 .../TestInitializer.cs | 0 .../TestsFixtures/InfrastructureFixture.cs | 2 +- .../TestsFixtures/IntegrationTestBase.cs | 0 .../TestsFixtures/SshUser.cs | 0 .../Renci.SshNet.IntegrationTests/Users.cs | 0 .../Renci.SshNet.IntegrationTests/Usings.cs | 0 .../resources/client/id_dsa | 0 .../resources/client/id_dsa.ppk | 0 .../resources/client/id_noaccess.rsa | 0 .../resources/client/id_rsa | 0 .../resources/client/id_rsa.pub | 0 .../resources/client/id_rsa_with_pass | 0 .../resources/client/key_ecdsa_256_openssh | 0 .../client/key_ecdsa_256_openssh.pub | 0 .../resources/client/key_ecdsa_384_openssh | 0 .../client/key_ecdsa_384_openssh.pub | 0 .../resources/client/key_ecdsa_521_openssh | 0 .../client/key_ecdsa_521_openssh.pub | 0 .../resources/client/key_ed25519_openssh | 0 .../resources/issue #70.png | Bin .../server/script/start.sh | 0 .../server/ssh/ssh_host_dsa_key | 0 .../server/ssh/ssh_host_ecdsa_key | 0 .../server/ssh/ssh_host_ed25519_key | 0 .../server/ssh/ssh_host_rsa_key | 0 .../user/sshnet/authorized_keys | 0 .../Renci.SshNet.TestTools.OpenSSH/Cipher.cs | 0 .../Formatters/BooleanFormatter.cs | 0 .../Formatters/Int32Formatter.cs | 0 .../Formatters/LogLevelFormatter.cs | 0 .../Formatters/MatchFormatter.cs | 0 .../Formatters/SubsystemFormatter.cs | 0 .../HostKeyAlgorithm.cs | 0 .../KeyExchangeAlgorithm.cs | 0 .../LogLevel.cs | 0 .../Renci.SshNet.TestTools.OpenSSH/Match.cs | 0 .../MessageAuthenticationCodeAlgorithm.cs | 0 .../PublicKeyAlgorithm.cs | 0 .../Renci.SshNet.TestTools.OpenSSH.csproj | 13 + .../SshdConfig.cs | 0 .../Subsystem.cs | 0 .../Renci.SshNet.Tests/.editorconfig | 0 .../Classes/BaseClientTestBase.cs | 0 ...Test_Connect_OnConnectedThrowsException.cs | 0 ...Connected_KeepAliveInterval_NegativeOne.cs | 0 ...nected_KeepAliveInterval_NotNegativeOne.cs | 0 ...Connected_KeepAlivesNotSentConcurrently.cs | 0 .../BaseClientTest_Disconnected_Connect.cs | 0 ...nected_KeepAliveInterval_NotNegativeOne.cs | 0 ...nected_KeepAliveInterval_NotNegativeOne.cs | 0 .../Channels/ChannelDirectTcpipTest.cs | 0 ...pose_SessionIsConnectedAndChannelIsOpen.cs | 0 ...pose_SessionIsConnectedAndChannelIsOpen.cs | 0 .../Channels/ChannelSessionTestBase.cs | 0 .../ChannelSessionTest_Dispose_Disposed.cs | 0 ...hannelEofReceived_DisposeInEventHandler.cs | 0 ...Received_SendChannelCloseMessageFailure.cs | 0 ...Received_SendChannelCloseMessageSuccess.cs | 0 ...Received_SendChannelCloseMessageFailure.cs | 0 ...Received_SendChannelCloseMessageSuccess.cs | 0 ...Received_SendChannelCloseMessageFailure.cs | 0 ...Received_SendChannelCloseMessageSuccess.cs | 0 ...Open_NoChannelCloseOrChannelEofReceived.cs | 0 ...ofReceived_SendChannelEofMessageFailure.cs | 0 ...sOpen_ChannelCloseAndChannelEofReceived.cs | 0 ...edAndChannelIsOpen_ChannelCloseReceived.cs | 0 ...Open_NoChannelCloseOrChannelEofReceived.cs | 0 .../ChannelSessionTest_Disposed_Closed.cs | 0 ...ived_SessionIsConnectedAndChannelIsOpen.cs | 0 ...Open_ExceptionWaitingOnOpenConfirmation.cs | 0 ...nOpenFailureReceived_NoRetriesAvailable.cs | 0 ...n_OnOpenFailureReceived_RetriesAvalable.cs | 0 .../Classes/Channels/ChannelStub.cs | 0 .../Classes/Channels/ChannelTestBase.cs | 0 ...e_SessionIsConnectedAndChannelIsNotOpen.cs | 0 ...onnectedAndChannelIsOpen_EofNotReceived.cs | 0 ...nelIsOpen_EofNotReceived_SendEofInvoked.cs | 0 ...IsConnectedAndChannelIsOpen_EofReceived.cs | 0 ...DisconnectWaitingForChannelCloseMessage.cs | 0 ...ed_TimeoutWaitingForChannelCloseMessage.cs | 0 ...essionIsNotConnectedAndChannelIsNotOpen.cs | 0 ...e_SessionIsNotConnectedAndChannelIsOpen.cs | 0 ...nChannelCloseReceived_OnClose_Exception.cs | 0 ...Open_DisposeChannelInClosedEventHandler.cs | 0 ...onnectedAndChannelIsOpen_EofNotReceived.cs | 0 ...IsConnectedAndChannelIsOpen_EofReceived.cs | 0 ...ionChannelDataReceived_OnData_Exception.cs | 0 ...ssionChannelEofReceived_OnEof_Exception.cs | 0 ...edDataReceived_OnExtendedData_Exception.cs | 0 ...nnelFailureReceived_OnFailure_Exception.cs | 0 ...nnelRequestReceived_OnRequest_Exception.cs | 0 ...nnelSuccessReceived_OnSuccess_Exception.cs | 0 ...AdjustReceived_OnWindowAdjust_Exception.cs | 0 ...onDisconnected_OnDisconnected_Exception.cs | 0 ...cted_SessionIsConnectedAndChannelIsOpen.cs | 0 ...ErrorOccurred_OnErrorOccurred_Exception.cs | 0 .../ChannelTest_SendEof_ChannelIsNotOpen.cs | 0 .../ChannelTest_SendEof_ChannelIsOpen.cs | 0 .../Classes/Channels/ClientChannelStub.cs | 0 ...onReceived_OnOpenConfirmation_Exception.cs | 0 ...FailureReceived_OnOpenFailure_Exception.cs | 0 .../Classes/ClientAuthenticationTest.cs | 0 .../Classes/ClientAuthenticationTestBase.cs | 0 ...ticationsHaveReachedPartialSuccessLimit.cs | 0 ...e_SingleList_AuthenticationMethodFailed.cs | 0 ...eList_AuthenticationMethodNotConfigured.cs | 0 ...lowedAuthenticationsAfterPartialSuccess.cs | 0 ...achedFollowedByFailureInAlternateBranch.cs | 0 ...chedFollowedByFailureInAlternateBranch2.cs | 0 ...mitReachedFollowedByFailureInSameBranch.cs | 0 ...achedFollowedBySuccessInAlternateBranch.cs | 0 ...mitReachedFollowedBySuccessInSameBranch.cs | 0 ...stponePartialAccessAuthenticationMethod.cs | 0 ...lowedAuthenticationsAfterPartialSuccess.cs | 0 ...ultiList_SkipFailedAuthenticationMethod.cs | 0 ...llowedAuthenticationAfterPartialSuccess.cs | 0 ...rtialSuccess_PartialSuccessLimitReached.cs | 0 .../Classes/CommandAsyncResultTest.cs | 0 .../AuthenticationBannerEventArgsTest.cs | 0 ...thenticationPasswordChangeEventArgsTest.cs | 0 .../AuthenticationPromptEventArgsTest.cs | 0 .../Common/AuthenticationPromptTest.cs | 0 .../Classes/Common/BigIntegerTest.cs | 0 .../Common/ChannelDataEventArgsTest.cs | 0 .../Classes/Common/ChannelEventArgsTest.cs | 0 .../Common/ChannelOpenFailedEventArgsTest.cs | 0 .../Common/ChannelRequestEventArgsTest.cs | 0 .../Classes/Common/CountdownEventTest.cs | 0 .../CountdownEventTest_Dispose_NotSet.cs | 0 .../Common/CountdownEventTest_Dispose_Set.cs | 0 .../Classes/Common/ExceptionEventArgsTest.cs | 0 .../Classes/Common/ExtensionsTest_Concat.cs | 0 .../ExtensionsTest_IsEqualTo_ByteArray.cs | 0 .../Classes/Common/ExtensionsTest_Pad.cs | 0 .../Classes/Common/ExtensionsTest_Reverse.cs | 0 .../Common/ExtensionsTest_Take_Count.cs | 0 .../ExtensionsTest_Take_OffsetAndCount.cs | 0 .../Common/ExtensionsTest_ToBigInteger2.cs | 0 .../Common/ExtensionsTest_TrimLeadingZeros.cs | 0 .../Classes/Common/HostKeyEventArgsTest.cs | 0 .../Common/NetConfServerExceptionTest.cs | 0 .../Classes/Common/ObjectIdentifierTest.cs | 0 .../Classes/Common/PackTest.cs | 0 .../Classes/Common/PacketDumpTest.cs | 0 .../Classes/Common/PipeStreamTest.cs | 0 .../Common/PipeStream_Close_BlockingRead.cs | 0 .../Common/PipeStream_Close_BlockingWrite.cs | 0 ...ipeStream_Flush_BytesRemainingAfterRead.cs | 0 ...eStream_Flush_NoBytesRemainingAfterRead.cs | 0 .../Common/PortForwardEventArgsTest.cs | 0 ...thTest_CreateAbsoluteOrRelativeFilePath.cs | 0 .../Common/PosixPathTest_GetDirectoryName.cs | 0 .../Common/PosixPathTest_GetFileName.cs | 0 .../Classes/Common/ProxyExceptionTest.cs | 0 .../Common/ScpDownloadEventArgsTest.cs | 0 .../Classes/Common/ScpExceptionTest.cs | 0 .../Classes/Common/ScpUploadEventArgsTest.cs | 0 .../Classes/Common/SemaphoreLightTest.cs | 0 .../Common/SftpPathNotFoundExceptionTest.cs | 0 .../SftpPermissionDeniedExceptionTest.cs | 0 .../Classes/Common/ShellDataEventArgsTest.cs | 0 .../Common/SshAuthenticationExceptionTest.cs | 0 .../Common/SshConnectionExceptionTest.cs | 0 .../Classes/Common/SshDataTest.cs | 0 .../Classes/Common/SshExceptionTest.cs | 0 .../SshOperationTimeoutExceptionTest.cs | 0 .../SshPassPhraseNullOrEmptyExceptionTest.cs | 0 .../Connection/DirectConnectorTestBase.cs | 0 ...rTest_Connect_ConnectionRefusedByServer.cs | 0 ...nnectorTest_Connect_ConnectionSucceeded.cs | 0 ...ctConnectorTest_Connect_HostNameInvalid.cs | 0 ...rTest_Connect_TimeoutConnectingToServer.cs | 0 .../Connection/HttpConnectorTestBase.cs | 0 ...orTest_Connect_ConnectionToProxyRefused.cs | 0 ...yClosesConnectionBeforeStatusLineIsSent.cs | 0 ...pConnectorTest_Connect_ProxyHostInvalid.cs | 0 ...nectorTest_Connect_ProxyPasswordIsEmpty.cs | 0 ...nnectorTest_Connect_ProxyPasswordIsNull.cs | 0 ...oxyResponseDoesNotContainHttpStatusLine.cs | 0 ...seStatusIs200_ExtraTextBeforeStatusLine.cs | 0 ...xyResponseStatusIs200_HeadersAndContent.cs | 0 ...ct_ProxyResponseStatusIs200_OnlyHeaders.cs | 0 ...est_Connect_ProxyResponseStatusIsNot200.cs | 0 ...nectorTest_Connect_ProxyUserNameIsEmpty.cs | 0 ...nnect_ProxyUserNameIsNotNullAndNotEmpty.cs | 0 ...nnectorTest_Connect_ProxyUserNameIsNull.cs | 0 ...orTest_Connect_TimeoutConnectingToProxy.cs | 0 ...rTest_Connect_TimeoutReadingHttpContent.cs | 0 ...orTest_Connect_TimeoutReadingStatusLine.cs | 0 ...ectionClosedByServer_NoDataSentByServer.cs | 0 ...est_ServerResponseContainsNullCharacter.cs | 0 ...entificationOnlyContainsProtocolVersion.cs | 0 ...changeTest_ServerResponseValid_Comments.cs | 0 ...angeTest_ServerResponseValid_NoComments.cs | 0 ...rminatedByLineFeedWithoutCarriageReturn.cs | 0 ...Test_TimeoutReadingIdentificationString.cs | 0 .../Connection/Socks4ConnectorTestBase.cs | 0 ...rTest_Connect_ConnectionRejectedByProxy.cs | 0 ...nnectorTest_Connect_ConnectionSucceeded.cs | 0 ...orTest_Connect_ConnectionToProxyRefused.cs | 0 ...orTest_Connect_TimeoutConnectingToProxy.cs | 0 ...onnect_TimeoutReadingDestinationAddress.cs | 0 ...torTest_Connect_TimeoutReadingReplyCode.cs | 0 ...Test_Connect_TimeoutReadingReplyVersion.cs | 0 .../Connection/Socks5ConnectorTestBase.cs | 0 ...orTest_Connect_ConnectionToProxyRefused.cs | 0 ...ct_NoAuthentication_ConnectionSucceeded.cs | 0 ...Connect_ProxySocksVersionIsNotSupported.cs | 0 ...orTest_Connect_TimeoutConnectingToProxy.cs | 0 ...wordAuthentication_AuthenticationFailed.cs | 0 ...swordAuthentication_ConnectionSucceeded.cs | 0 ...entication_PasswordExceedsMaximumLength.cs | 0 ...entication_UserNameExceedsMaximumLength.cs | 0 .../Connection/SshIdentificationTest.cs | 0 .../Classes/ConnectionInfoTest.cs | 0 ...ConnectionInfoTest_Authenticate_Failure.cs | 0 ...ConnectionInfoTest_Authenticate_Success.cs | 0 .../Classes/ExpectActionTest.cs | 0 .../Classes/ForwardedPortDynamicTest.cs | 0 ...dedPortDynamicTest_Dispose_PortDisposed.cs | 0 ...ortDynamicTest_Dispose_PortNeverStarted.cs | 0 ...icTest_Dispose_PortStarted_ChannelBound.cs | 0 ...est_Dispose_PortStarted_ChannelNotBound.cs | 0 ...rdedPortDynamicTest_Dispose_PortStopped.cs | 0 ...cTest_SessionErrorOccurred_ChannelBound.cs | 0 ...ardedPortDynamicTest_Start_PortDisposed.cs | 0 ...dPortDynamicTest_Start_PortNeverStarted.cs | 0 ...wardedPortDynamicTest_Start_PortStarted.cs | 0 ...wardedPortDynamicTest_Start_PortStopped.cs | 0 ...rtDynamicTest_Start_SessionNotConnected.cs | 0 ...wardedPortDynamicTest_Start_SessionNull.cs | 0 ...t_Started_SocketSendShutdownImmediately.cs | 0 ...cTest_Started_SocketVersionNotSupported.cs | 0 ...wardedPortDynamicTest_Stop_PortDisposed.cs | 0 ...edPortDynamicTest_Stop_PortNeverStarted.cs | 0 ...namicTest_Stop_PortStarted_ChannelBound.cs | 0 ...icTest_Stop_PortStarted_ChannelNotBound.cs | 0 ...rwardedPortDynamicTest_Stop_PortStopped.cs | 0 .../Classes/ForwardedPortLocalTest.cs | 0 ...ardedPortLocalTest_Dispose_PortDisposed.cs | 0 ...lTest_Dispose_PortDisposed_NeverStarted.cs | 0 ...dPortLocalTest_Dispose_PortNeverStarted.cs | 0 ...alTest_Dispose_PortStarted_ChannelBound.cs | 0 ...est_Dispose_PortStarted_ChannelNotBound.cs | 0 ...wardedPortLocalTest_Dispose_PortStopped.cs | 0 ...rwardedPortLocalTest_Start_PortDisposed.cs | 0 ...dedPortLocalTest_Start_PortNeverStarted.cs | 0 ...orwardedPortLocalTest_Start_PortStarted.cs | 0 ...orwardedPortLocalTest_Start_PortStopped.cs | 0 ...PortLocalTest_Start_SessionNotConnected.cs | 0 ...orwardedPortLocalTest_Start_SessionNull.cs | 0 ...orwardedPortLocalTest_Stop_PortDisposed.cs | 0 ...rdedPortLocalTest_Stop_PortNeverStarted.cs | 0 ...LocalTest_Stop_PortStarted_ChannelBound.cs | 0 ...alTest_Stop_PortStarted_ChannelNotBound.cs | 0 ...ForwardedPortLocalTest_Stop_PortStopped.cs | 0 .../Classes/ForwardedPortRemoteTest.cs | 0 ...rdedPortRemoteTest_Dispose_PortDisposed.cs | 0 ...PortRemoteTest_Dispose_PortNeverStarted.cs | 0 ...teTest_Dispose_PortStarted_ChannelBound.cs | 0 ...ardedPortRemoteTest_Dispose_PortStopped.cs | 0 ...wardedPortRemoteTest_Start_PortDisposed.cs | 0 ...edPortRemoteTest_Start_PortNeverStarted.cs | 0 ...rwardedPortRemoteTest_Start_PortStarted.cs | 0 ...rwardedPortRemoteTest_Start_PortStopped.cs | 0 ...ortRemoteTest_Start_SessionNotConnected.cs | 0 ...rwardedPortRemoteTest_Start_SessionNull.cs | 0 .../ForwardedPortRemoteTest_Started.cs | 0 ...rwardedPortRemoteTest_Stop_PortDisposed.cs | 0 ...dedPortRemoteTest_Stop_PortNeverStarted.cs | 0 ...emoteTest_Stop_PortStarted_ChannelBound.cs | 0 ...orwardedPortRemoteTest_Stop_PortStopped.cs | 0 ...oardInteractiveAuthenticationMethodTest.cs | 0 .../Connection/ChannelDataMessageTest.cs | 0 .../ChannelOpen/ChannelOpenMessageTest.cs | 0 .../ChannelRequest/PseudoTerminalInfoTest.cs | 0 .../Connection/GlobalRequestMessageTest.cs | 0 .../Messages/Transport/IgnoreMessageTest.cs | 0 .../KeyExchangeDhGroupExchangeGroupBuilder.cs | 0 .../KeyExchangeDhGroupExchangeInitTest.cs | 0 .../KeyExchangeDhGroupExchangeReplyBuilder.cs | 0 .../KeyExchangeDhGroupExchangeReplyTest.cs | 0 .../KeyExchangeDhGroupExchangeRequestTest.cs | 0 .../Transport/KeyExchangeInitMessageTest.cs | 0 .../Classes/NetConfClientTest.cs | 0 .../Classes/NetConfClientTestBase.cs | 0 ...st_Connect_NetConfSessionConnectFailure.cs | 0 .../NetConfClientTest_Dispose_Connected.cs | 0 .../NetConfClientTest_Dispose_Disconnected.cs | 0 .../NetConfClientTest_Dispose_Disposed.cs | 0 .../NetConfClientTest_Finalize_Connected.cs | 0 .../Classes/NoneAuthenticationMethodTest.cs | 0 .../PasswordAuthenticationMethodTest.cs | 0 .../Classes/PasswordConnectionInfoTest.cs | 0 .../Classes/PipeStreamTest_Dispose.cs | 0 .../PrivateKeyAuthenticationMethodTest.cs | 0 .../Classes/PrivateKeyFileTest.cs | 0 ...RemotePathDoubleQuoteTransformationTest.cs | 0 .../RemotePathShellQuoteTransformationTest.cs | 0 .../Classes/ScpClientTest.cs | 0 .../Classes/ScpClientTestBase.cs | 0 ...rectoryInfo_SendExecRequestReturnsFalse.cs | 0 ...AndFileInfo_SendExecRequestReturnsFalse.cs | 0 ...thAndStream_SendExecRequestReturnsFalse.cs | 0 ...InfoAndPath_SendExecRequestReturnsFalse.cs | 0 ...InfoAndPath_SendExecRequestReturnsFalse.cs | 0 ...ientTest_Upload_FileInfoAndPath_Success.cs | 0 ...reamAndPath_SendExecRequestReturnsFalse.cs | 0 .../Security/Cryptography/BlockCipherTest.cs | 0 .../Cryptography/Ciphers/AesCipherTest.cs | 0 .../Cryptography/Ciphers/Arc4CipherTest.cs | 0 .../Ciphers/BlowfishCipherTest.cs | 0 .../Cryptography/Ciphers/CastCipherTest.cs | 0 .../Cryptography/Ciphers/DesCipherTest.cs | 0 .../Ciphers/Paddings/PKCS5PaddingTest.cs | 0 .../Ciphers/Paddings/PKCS7PaddingTest.cs | 0 .../Ciphers/TripleDesCipherTest.cs | 0 .../Cryptography/RsaDigitalSignatureTest.cs | 0 .../Classes/Security/KeyAlgorithmTest.cs | 0 ...KeyExchangeDiffieHellmanGroup14Sha1Test.cs | 0 ...yExchangeDiffieHellmanGroup14Sha256Test.cs | 0 ...yExchangeDiffieHellmanGroup16Sha512Test.cs | 0 .../KeyExchangeDiffieHellmanGroup1Sha1Test.cs | 0 ...eFactoryTest_CreateClientAuthentication.cs | 0 .../ServiceFactoryTest_CreateConnector.cs | 0 ...tpFileReader_EndLStatThrowsSshException.cs | 0 ...izeIsAlmostSixTimesGreaterThanChunkSize.cs | 0 ...tpFileReader_FileSizeIsEqualToChunkSize.cs | 0 ...eIsExactlyFiveTimesGreaterThanChunkSize.cs | 0 ...pFileReader_FileSizeIsLessThanChunkSize.cs | 0 ...leMoreThanFiveTimesGreaterThanChunkSize.cs | 0 ...eIsMoreThanTenTimesGreaterThanChunkSize.cs | 0 ...est_CreateSftpFileReader_FileSizeIsZero.cs | 0 ...eShellStream_ChannelOpenThrowsException.cs | 0 ...m_SendPseudoTerminalRequestReturnsFalse.cs | 0 ...endPseudoTerminalRequestThrowsException.cs | 0 ...hellStream_SendShellRequestReturnsFalse.cs | 0 ...lStream_SendShellRequestThrowsException.cs | 0 ...ceFactoryTest_CreateShellStream_Success.cs | 0 .../Renci.SshNet.Tests/Classes/SessionTest.cs | 0 .../Classes/SessionTestBase.cs | 0 .../SessionTest_ConnectToServerFails.cs | 0 .../Classes/SessionTest_Connected.cs | 0 .../Classes/SessionTest_ConnectedBase.cs | 0 .../SessionTest_Connected_ConnectionReset.cs | 0 .../SessionTest_Connected_Disconnect.cs | 0 ...alRequestMessageAfterAuthenticationRace.cs | 0 ...Connected_ServerAndClientDisconnectRace.cs | 0 ...sionTest_Connected_ServerSendsBadPacket.cs | 0 ..._Connected_ServerSendsDisconnectMessage.cs | 0 ...endsDisconnectMessageAndShutsDownSocket.cs | 0 ...ected_ServerSendsUnsupportedMessageType.cs | 0 ...utsDownSendAfterSendingIncompletePacket.cs | 0 ...ionTest_Connected_ServerShutsDownSocket.cs | 0 .../Classes/SessionTest_NotConnected.cs | 0 ...est_SocketConnected_BadPacketAndDispose.cs | 0 .../ExtendedRequests/FStatVfsRequestTest.cs | 0 .../ExtendedRequests/HardLinkRequestTest.cs | 0 .../PosixRenameRequestTest.cs | 0 .../ExtendedRequests/StatVfsRequestTest.cs | 0 .../Sftp/Requests/SftpBlockRequestTest.cs | 0 .../Sftp/Requests/SftpCloseRequestTest.cs | 0 .../Sftp/Requests/SftpFSetStatRequestTest.cs | 0 .../Sftp/Requests/SftpFStatRequestTest.cs | 0 .../Sftp/Requests/SftpInitRequestTest.cs | 0 .../Sftp/Requests/SftpLStatRequestTest.cs | 0 .../Sftp/Requests/SftpLinkRequestTest.cs | 0 .../Sftp/Requests/SftpMkDirRequestTest.cs | 0 .../Sftp/Requests/SftpOpenDirRequestTest.cs | 0 .../Sftp/Requests/SftpOpenRequestTest.cs | 0 .../Sftp/Requests/SftpReadDirRequestTest.cs | 0 .../Sftp/Requests/SftpReadLinkRequestTest.cs | 0 .../Sftp/Requests/SftpReadRequestTest.cs | 0 .../Sftp/Requests/SftpRealPathRequestTest.cs | 0 .../Sftp/Requests/SftpRemoveRequestTest.cs | 0 .../Sftp/Requests/SftpRenameRequestTest.cs | 0 .../Sftp/Requests/SftpRmDirRequestTest.cs | 0 .../Sftp/Requests/SftpSetStatRequestTest.cs | 0 .../Sftp/Requests/SftpStatRequestTest.cs | 0 .../Sftp/Requests/SftpSymLinkRequestTest.cs | 0 .../Sftp/Requests/SftpUnblockRequestTest.cs | 0 .../Sftp/Requests/SftpWriteRequestTest.cs | 0 .../ExtendedReplies/StatVfsReplyInfoTest.cs | 0 .../Sftp/Responses/SftpAttrsResponseTest.cs | 0 .../Sftp/Responses/SftpDataResponseTest.cs | 0 .../SftpExtendedReplyResponseTest.cs | 0 .../Sftp/Responses/SftpHandleResponseTest.cs | 0 .../Sftp/Responses/SftpNameResponseTest.cs | 0 .../Sftp/Responses/SftpStatusResponseTest.cs | 0 .../Sftp/Responses/SftpVersionResponseTest.cs | 0 .../Classes/Sftp/SftpDataResponseBuilder.cs | 0 .../Sftp/SftpDownloadAsyncResultTest.cs | 0 .../Classes/Sftp/SftpFileReaderTestBase.cs | 0 ...st_DisposeShouldUnblockReadAndReadAhead.cs | 0 ...ReaderTest_Dispose_SftpSessionIsNotOpen.cs | 0 ...SessionIsOpen_BeginCloseThrowsException.cs | 0 ...tpSessionIsOpen_EndCloseThrowsException.cs | 0 ...ReaderTest_LastChunkBeforeEofIsComplete.cs | 0 ...eReaderTest_LastChunkBeforeEofIsPartial.cs | 0 ...iousChunkIsIncompleteAndEofIsNotReached.cs | 0 ...reviousChunkIsIncompleteAndEofIsReached.cs | 0 ...eReaderTest_ReadAheadBeginReadException.cs | 0 ...vokeException_DiscardsFurtherReadAheads.cs | 0 ...vokeException_PreventsFurtherReadAheads.cs | 0 ...leReaderTest_ReadBackBeginReadException.cs | 0 ...leReaderTest_ReadBackEndInvokeException.cs | 0 ...dExceptionInWaitOnHandle_ChunkAvailable.cs | 0 ...xceptionInWaitOnHandle_NoChunkAvailable.cs | 0 ...Test_Read_ReahAheadExceptionInBeginRead.cs | 0 .../Sftp/SftpFileStreamAsyncTestBase.cs | 0 .../Classes/Sftp/SftpFileStreamTestBase.cs | 0 ...treamTest_CanRead_Closed_FileAccessRead.cs | 0 ...Test_CanRead_Closed_FileAccessReadWrite.cs | 0 ...reamTest_CanRead_Closed_FileAccessWrite.cs | 0 ...eamTest_CanRead_Disposed_FileAccessRead.cs | 0 ...st_CanRead_Disposed_FileAccessReadWrite.cs | 0 ...amTest_CanRead_Disposed_FileAccessWrite.cs | 0 ...reamTest_CanWrite_Closed_FileAccessRead.cs | 0 ...est_CanWrite_Closed_FileAccessReadWrite.cs | 0 ...eamTest_CanWrite_Closed_FileAccessWrite.cs | 0 ...amTest_CanWrite_Disposed_FileAccessRead.cs | 0 ...t_CanWrite_Disposed_FileAccessReadWrite.cs | 0 ...mTest_CanWrite_Disposed_FileAccessWrite.cs | 0 .../Sftp/SftpFileStreamTest_Close_Closed.cs | 0 .../Sftp/SftpFileStreamTest_Close_Disposed.cs | 0 ...SftpFileStreamTest_Close_SessionNotOpen.cs | 0 .../SftpFileStreamTest_Close_SessionOpen.cs | 0 ...tpFileStreamTest_Ctor_FileAccessInvalid.cs | 0 ...Test_Ctor_FileModeAppend_FileAccessRead.cs | 0 ...Ctor_FileModeAppend_FileAccessReadWrite.cs | 0 ...est_Ctor_FileModeAppend_FileAccessWrite.cs | 0 ...t_Ctor_FileModeCreateNew_FileAccessRead.cs | 0 ...r_FileModeCreateNew_FileAccessReadWrite.cs | 0 ..._Ctor_FileModeCreateNew_FileAccessWrite.cs | 0 ...Test_Ctor_FileModeCreate_FileAccessRead.cs | 0 ...te_FileAccessReadWrite_FileDoesNotExist.cs | 0 ...deCreate_FileAccessReadWrite_FileExists.cs | 0 ...Create_FileAccessWrite_FileDoesNotExist.cs | 0 ...leModeCreate_FileAccessWrite_FileExists.cs | 0 ...SftpFileStreamTest_Ctor_FileModeInvalid.cs | 0 ...tor_FileModeOpenOrCreate_FileAccessRead.cs | 0 ...ileModeOpenOrCreate_FileAccessReadWrite.cs | 0 ...or_FileModeOpenOrCreate_FileAccessWrite.cs | 0 ...amTest_Ctor_FileModeOpen_FileAccessRead.cs | 0 ...t_Ctor_FileModeOpen_FileAccessReadWrite.cs | 0 ...mTest_Ctor_FileModeOpen_FileAccessWrite.cs | 0 ...st_Ctor_FileModeTruncate_FileAccessRead.cs | 0 ...or_FileModeTruncate_FileAccessReadWrite.cs | 0 ...t_Ctor_FileModeTruncate_FileAccessWrite.cs | 0 .../Sftp/SftpFileStreamTest_Dispose_Closed.cs | 0 .../SftpFileStreamTest_Dispose_Disposed.cs | 0 ...tpFileStreamTest_Dispose_SessionNotOpen.cs | 0 .../SftpFileStreamTest_Dispose_SessionOpen.cs | 0 ...SftpFileStreamTest_Finalize_SessionOpen.cs | 0 ...ReadMode_DataInBuffer_NotReadFromBuffer.cs | 0 ...sh_ReadMode_DataInBuffer_ReadFromBuffer.cs | 0 ...treamTest_Flush_ReadMode_NoDataInBuffer.cs | 0 ...SftpFileStreamTest_Flush_SessionNotOpen.cs | 0 ...StreamTest_Flush_WriteMode_DataInBuffer.cs | 0 ...reamTest_Flush_WriteMode_NoDataInBuffer.cs | 0 ...eStreamTest_OpenAsync_FileAccessInvalid.cs | 0 ...OpenAsync_FileModeAppend_FileAccessRead.cs | 0 ...sync_FileModeAppend_FileAccessReadWrite.cs | 0 ...penAsync_FileModeAppend_FileAccessWrite.cs | 0 ...nAsync_FileModeCreateNew_FileAccessRead.cs | 0 ...c_FileModeCreateNew_FileAccessReadWrite.cs | 0 ...Async_FileModeCreateNew_FileAccessWrite.cs | 0 ...OpenAsync_FileModeCreate_FileAccessRead.cs | 0 ...te_FileAccessReadWrite_FileDoesNotExist.cs | 0 ...deCreate_FileAccessReadWrite_FileExists.cs | 0 ...Create_FileAccessWrite_FileDoesNotExist.cs | 0 ...leModeCreate_FileAccessWrite_FileExists.cs | 0 ...ileStreamTest_OpenAsync_FileModeInvalid.cs | 0 ...ync_FileModeOpenOrCreate_FileAccessRead.cs | 0 ...ileModeOpenOrCreate_FileAccessReadWrite.cs | 0 ...nc_FileModeOpenOrCreate_FileAccessWrite.cs | 0 ...t_OpenAsync_FileModeOpen_FileAccessRead.cs | 0 ...nAsync_FileModeOpen_FileAccessReadWrite.cs | 0 ..._OpenAsync_FileModeOpen_FileAccessWrite.cs | 0 ...enAsync_FileModeTruncate_FileAccessRead.cs | 0 ...nc_FileModeTruncate_FileAccessReadWrite.cs | 0 ...nAsync_FileModeTruncate_FileAccessWrite.cs | 0 ...FromServerThanCountAndEqualToBufferSize.cs | 0 ...romServerThanCountAndLessThanBufferSize.cs | 0 ...fferAndReadMoreBytesFromServerThanCount.cs | 0 ...aInWriteBufferAndNoDataInReadBuffer_Eof.cs | 0 ...fer_LessDataThanReadBufferSizeAvailable.cs | 0 ...FromServerThanCountAndEqualToBufferSize.cs | 0 ...romServerThanCountAndLessThanBufferSize.cs | 0 ...fferAndReadMoreBytesFromServerThanCount.cs | 0 ...ngOfStream_OriginBeginAndOffsetNegative.cs | 0 ...ngOfStream_OriginBeginAndOffsetPositive.cs | 0 ...inningOfStream_OriginBeginAndOffsetZero.cs | 0 ...ningOfStream_OriginEndAndOffsetNegative.cs | 0 ...ningOfStream_OriginEndAndOffsetPositive.cs | 0 ...eginningOfStream_OriginEndAndOffsetZero.cs | 0 ...am_OriginBeginAndOffsetZero_NoBuffering.cs | 0 ...eam_OriginBeginAndOffsetZero_ReadBuffer.cs | 0 .../SftpFileStreamTest_SetLength_Closed.cs | 0 ...eadBuffer_NewLengthGreatherThanPosition.cs | 0 ...aInReadBuffer_NewLengthLessThanPosition.cs | 0 ...iteBuffer_NewLengthGreatherThanPosition.cs | 0 ...InWriteBuffer_NewLengthLessThanPosition.cs | 0 .../SftpFileStreamTest_SetLength_Disposed.cs | 0 ...FileStreamTest_SetLength_SessionNotOpen.cs | 0 ...st_SetLength_SessionOpen_FIleAccessRead.cs | 0 ...tLength_SessionOpen_FIleAccessReadWrite.cs | 0 ...t_SetLength_SessionOpen_FIleAccessWrite.cs | 0 ...tGreatherThanTwoTimesTheWriteBufferSize.cs | 0 ...tGreatherThanTwoTimesTheWriteBufferSize.cs | 0 .../Classes/Sftp/SftpHandleResponseBuilder.cs | 0 .../Classes/Sftp/SftpInitRequestBuilder.cs | 0 .../Classes/Sftp/SftpNameResponseBuilder.cs | 0 .../Classes/Sftp/SftpOpenRequestBuilder.cs | 0 .../Classes/Sftp/SftpReadRequestBuilder.cs | 0 .../Sftp/SftpRealPathRequestBuilder.cs | 0 .../SftpSessionTest_Connected_RequestRead.cs | 0 ...ftpSessionTest_Connected_RequestStatVfs.cs | 0 ...tipleSftpMessagesInSingleSshDataMessage.cs | 0 ...essagesSplitOverMultipleSshDataMessages.cs | 0 ...eived_SingleSftpMessageInSshDataMessage.cs | 0 .../Classes/Sftp/SftpStatVfsRequestBuilder.cs | 0 .../Sftp/SftpStatVfsResponseBuilder.cs | 0 .../Sftp/SftpVersionResponseBuilder.cs | 0 .../Classes/SftpClientTest.Connect.cs | 0 .../Classes/SftpClientTest.ConnectAsync.cs | 0 .../Classes/SftpClientTest.DeleteDirectory.cs | 0 .../Classes/SftpClientTest.DeleteFile.cs | 0 .../Classes/SftpClientTest.DeleteFileAsync.cs | 0 .../Classes/SftpClientTest.ListDirectory.cs | 0 .../SftpClientTest.ListDirectoryAsync.cs | 0 .../Classes/SftpClientTest.cs | 0 .../Classes/SftpClientTestBase.cs | 0 ...tTest_Connect_SftpSessionConnectFailure.cs | 8 +- .../SftpClientTest_Dispose_Connected.cs | 0 .../SftpClientTest_Dispose_Disconnected.cs | 0 .../SftpClientTest_Dispose_Disposed.cs | 0 .../SftpClientTest_Finalize_Connected.cs | 0 .../Classes/ShellStreamTest.cs | 0 ...ferEmptyAndWriteLessBytesThanBufferSize.cs | 0 ...ferEmptyAndWriteMoreBytesThanBufferSize.cs | 0 ...yAndWriteNumberOfBytesEqualToBufferSize.cs | 0 ...Write_WriteBufferEmptyAndWriteZeroBytes.cs | 0 ...fferFullAndWriteLessBytesThanBufferSize.cs | 0 ..._Write_WriteBufferFullAndWriteZeroBytes.cs | 0 ...tyAndWriteLessBytesThanBufferCanContain.cs | 0 ...tyAndWriteMoreBytesThanBufferCanContain.cs | 0 ...te_WriteBufferNotEmptyAndWriteZeroBytes.cs | 0 .../Classes/SshClientTest.cs | 0 ...AndBufferSizeAndTerminalModes_Connected.cs | 0 ...ndWidthAndHeightAndBufferSize_Connected.cs | 0 ...entTest_Disconnect_ForwardedPortStarted.cs | 0 .../SshClientTest_Dispose_Connected.cs | 0 .../SshClientTest_Dispose_Disconnected.cs | 0 .../Classes/SshClientTest_Dispose_Disposed.cs | 0 ...ClientTest_Dispose_ForwardedPortStarted.cs | 0 .../Classes/SshCommandTest.cs | 0 ...okedOnAsyncResultFromPreviousInvocation.cs | 0 ...okedOnAsyncResultFromPreviousInvocation.cs | 0 .../Classes/SshCommandTest_Dispose.cs | 0 .../Classes/SshCommandTest_EndExecute.cs | 0 ...EndExecute_AsyncResultFromOtherInstance.cs | 0 ...ommandTest_EndExecute_AsyncResultIsNull.cs | 0 .../SshCommandTest_EndExecute_ChannelOpen.cs | 0 .../Classes/SubsystemSessionStub.cs | 0 .../SubsystemSession_Connect_Connected.cs | 0 .../SubsystemSession_Connect_Disconnected.cs | 0 .../SubsystemSession_Connect_Disposed.cs | 0 ...SubsystemSession_Connect_NeverConnected.cs | 0 ...ssion_Connect_SendSubsystemRequestFails.cs | 0 .../SubsystemSession_Disconnect_Connected.cs | 0 .../SubsystemSession_Disconnect_Disposed.cs | 0 ...systemSession_Disconnect_NeverConnected.cs | 0 .../SubsystemSession_Dispose_Connected.cs | 0 .../SubsystemSession_Dispose_Disconnected.cs | 0 .../SubsystemSession_Dispose_Disposed.cs | 0 ...SubsystemSession_Dispose_NeverConnected.cs | 0 ...Session_OnChannelDataReceived_Connected.cs | 0 ...mSession_OnChannelDataReceived_Disposed.cs | 0 ...elDataReceived_OnDataReceived_Exception.cs | 0 ...temSession_OnChannelException_Connected.cs | 0 ...stemSession_OnChannelException_Disposed.cs | 0 ...Session_OnSessionDisconnected_Connected.cs | 0 ...mSession_OnSessionDisconnected_Disposed.cs | 0 ...ession_OnSessionErrorOccurred_Connected.cs | 0 ...Session_OnSessionErrorOccurred_Disposed.cs | 0 .../SubsystemSession_SendData_Connected.cs | 0 .../SubsystemSession_SendData_Disconnected.cs | 0 .../SubsystemSession_SendData_Disposed.cs | 0 ...ubsystemSession_SendData_NeverConnected.cs | 0 .../Common/ArgumentExceptionAssert.cs | 0 .../Renci.SshNet.Tests/Common/ArrayBuilder.cs | 0 .../Common/AsyncSocketListener.cs | 0 .../Common/DictionaryAssert.cs | 0 .../Renci.SshNet.Tests/Common/Extensions.cs | 0 .../Common/HttpProxyStub.cs | 0 .../Renci.SshNet.Tests/Common/HttpRequest.cs | 0 .../Common/SftpFileAttributesBuilder.cs | 0 .../Renci.SshNet.Tests/Common/TestBase.cs | 0 .../Common/TripleATestBase.cs | 0 .../Properties/Resources.Designer.cs | 0 .../Properties/Resources.resx | 0 .../Renci.SshNet.Tests.csproj | 18 +- 696 files changed, 283 insertions(+), 265 deletions(-) create mode 100644 Renci.SshNet.sln rename src/Renci.SshNet.snk => Renci.SshNet.snk (100%) create mode 100644 global.json delete mode 100644 src/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj delete mode 100644 src/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj delete mode 100644 src/Renci.SshNet.sln rename {src => test}/Data/Key.ECDSA.Encrypted.txt (100%) rename {src => test}/Data/Key.ECDSA.txt (100%) rename {src => test}/Data/Key.ECDSA384.Encrypted.txt (100%) rename {src => test}/Data/Key.ECDSA384.txt (100%) rename {src => test}/Data/Key.ECDSA521.Encrypted.txt (100%) rename {src => test}/Data/Key.ECDSA521.txt (100%) rename {src => test}/Data/Key.OPENSSH.ECDSA.Encrypted.txt (100%) rename {src => test}/Data/Key.OPENSSH.ECDSA.txt (100%) rename {src => test}/Data/Key.OPENSSH.ECDSA384.Encrypted.txt (100%) rename {src => test}/Data/Key.OPENSSH.ECDSA384.txt (100%) rename {src => test}/Data/Key.OPENSSH.ECDSA521.Encrypted.txt (100%) rename {src => test}/Data/Key.OPENSSH.ECDSA521.txt (100%) rename {src => test}/Data/Key.OPENSSH.ED25519.Encrypted.txt (100%) rename {src => test}/Data/Key.OPENSSH.ED25519.txt (100%) rename {src => test}/Data/Key.OPENSSH.RSA.Encrypted.txt (100%) rename {src => test}/Data/Key.OPENSSH.RSA.txt (100%) rename {src => test}/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt (100%) rename {src => test}/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt (100%) rename {src => test}/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt (100%) rename {src => test}/Data/Key.RSA.Encrypted.Des.CBC.12345.txt (100%) rename {src => test}/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt (100%) rename {src => test}/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt (100%) rename {src => test}/Data/Key.RSA.txt (100%) rename {src => test}/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt (100%) rename {src => test}/Data/Key.SSH2.DSA.txt (100%) rename {src => test}/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt (100%) rename {src => test}/Data/Key.SSH2.RSA.txt (100%) rename {src => test}/Renci.SshNet.Benchmarks/Common/ExtensionsBenchmarks.cs (100%) rename {src => test}/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs (100%) rename {src => test}/Renci.SshNet.Benchmarks/Program.cs (100%) create mode 100644 test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj rename {src => test}/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs (100%) rename {src => test}/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs (100%) rename {src => test}/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/.editorconfig (100%) rename {src => test}/Renci.SshNet.IntegrationTests/.gitignore (100%) rename {src => test}/Renci.SshNet.IntegrationTests/App.config (100%) rename {src => test}/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/AuthenticationTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/CipherTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/Common/ArrayBuilder.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/Common/AsyncSocketListener.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/Common/DateTimeAssert.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/Common/DateTimeExtensions.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/Common/Socks5Handler.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/ConnectivityTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/Credential.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/Dockerfile (100%) rename {src => test}/Renci.SshNet.IntegrationTests/HmacTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/HostConfig.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/HostKeyFile.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/IConnectionInfoFactory.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/LinuxAdminConnectionFactory.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/LinuxVMConnectionFactory.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/ScpClientTest.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ChangeDirectory.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.CreateDirectory.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.DeleteDirectory.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Download.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ListDirectory.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFile.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFileAsync.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.SynchronizeDirectories.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/Program.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/RemoteSshd.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj (77%) rename {src => test}/Renci.SshNet.IntegrationTests/ScpClientTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/ScpTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/SftpClientTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/SftpTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/SshClientTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/SshConnectionDisruptor.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/SshConnectionRestorer.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/SshTests.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/TestBase.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/TestInitializer.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs (96%) rename {src => test}/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/Users.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/Usings.cs (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/id_dsa (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/id_rsa (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh (100%) rename {src => test}/Renci.SshNet.IntegrationTests/resources/issue #70.png (100%) rename {src => test}/Renci.SshNet.IntegrationTests/server/script/start.sh (100%) rename {src => test}/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_dsa_key (100%) rename {src => test}/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ecdsa_key (100%) rename {src => test}/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ed25519_key (100%) rename {src => test}/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_rsa_key (100%) rename {src => test}/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/Cipher.cs (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/LogLevel.cs (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/Match.cs (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs (100%) create mode 100644 test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj rename {src => test}/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs (100%) rename {src => test}/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs (100%) rename {src => test}/Renci.SshNet.Tests/.editorconfig (100%) rename {src => test}/Renci.SshNet.Tests/Classes/BaseClientTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_Connect.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Disposed_Closed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelStub.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_DisconnectWaitingForChannelCloseMessage.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_TimeoutWaitingForChannelCloseMessage.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_DisposeChannelInClosedEventHandler.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofReceived.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionErrorOccurred_OnErrorOccurred_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsNotOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ClientChannelStub.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ClientChannelTest_OnSessionChannelOpenConfirmationReceived_OnOpenConfirmation_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Channels/ClientChannelTest_OnSessionChannelOpenFailureReceived_OnOpenFailure_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_MultiList_AllAllowedAuthenticationsHaveReachedPartialSuccessLimit.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_SingleList_AuthenticationMethodFailed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_SingleList_AuthenticationMethodNotConfigured.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_DifferentAllowedAuthenticationsAfterPartialSuccess.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch2.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInSameBranch.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInSameBranch.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PostponePartialAccessAuthenticationMethod.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_SameAllowedAuthenticationsAfterPartialSuccess.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_SkipFailedAuthenticationMethod.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess_PartialSuccessLimitReached.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/CommandAsyncResultTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/AuthenticationBannerEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ChannelDataEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ChannelEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ChannelOpenFailedEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ChannelRequestEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_NotSet.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_Set.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ExceptionEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Pad.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Reverse.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_Count.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_OffsetAndCount.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToBigInteger2.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_TrimLeadingZeros.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/NetConfServerExceptionTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ObjectIdentifierTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/PackTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/PortForwardEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetDirectoryName.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ScpDownloadEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ScpExceptionTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ScpUploadEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/SftpPathNotFoundExceptionTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/SftpPermissionDeniedExceptionTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/ShellDataEventArgsTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/SshAuthenticationExceptionTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/SshDataTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/SshOperationTimeoutExceptionTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Common/SshPassPhraseNullOrEmptyExceptionTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionRefusedByServer.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionSucceeded.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ConnectionToProxyRefused.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionToProxyRefused.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ConnectionToProxyRefused.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Connection/SshIdentificationTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ConnectionInfoTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ConnectionInfoTest_Authenticate_Failure.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ConnectionInfoTest_Authenticate_Success.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ExpectActionTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortDisposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortNeverStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelBound.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStopped.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_SessionErrorOccurred_ChannelBound.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortDisposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortNeverStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortStopped.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_SessionNotConnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_SessionNull.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketSendShutdownImmediately.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketVersionNotSupported.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortDisposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortNeverStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelBound.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStopped.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortDisposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortDisposed_NeverStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortNeverStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStarted_ChannelBound.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStarted_ChannelNotBound.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStopped.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortDisposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortNeverStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStopped.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_SessionNotConnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_SessionNull.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortDisposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortNeverStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStarted_ChannelBound.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStarted_ChannelNotBound.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStopped.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortDisposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortNeverStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortStarted_ChannelBound.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortStopped.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortDisposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortNeverStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStopped.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNotConnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNull.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Started.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortDisposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortNeverStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortStarted_ChannelBound.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortStopped.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/KeyboardInteractiveAuthenticationMethodTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/PseudoTerminalInfoTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Messages/Connection/GlobalRequestMessageTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeInitTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeInitMessageTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/NetConfClientTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/NetConfClientTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/NoneAuthenticationMethodTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/PipeStreamTest_Dispose.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/PrivateKeyAuthenticationMethodTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/RemotePathDoubleQuoteTransformationTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/RemotePathShellQuoteTransformationTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ScpClientTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ScpClientTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/Cryptography/BlockCipherTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS5PaddingTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS7PaddingTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha1Test.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup16Sha512Test.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup1Sha1Test.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateClientAuthentication.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateConnector.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsAlmostSixTimesGreaterThanChunkSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsEqualToChunkSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsExactlyFiveTimesGreaterThanChunkSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLessThanChunkSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLittleMoreThanFiveTimesGreaterThanChunkSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_ChannelOpenThrowsException.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestReturnsFalse.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestThrowsException.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestReturnsFalse.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestThrowsException.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_Success.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_ConnectToServerFails.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/FStatVfsRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/HardLinkRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/PosixRenameRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/StatVfsRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpBlockRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpCloseRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpFSetStatRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpFStatRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpInitRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpLStatRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpLinkRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpMkDirRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpOpenDirRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpOpenRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadDirRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadLinkRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRealPathRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRemoveRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRenameRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRmDirRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpSetStatRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpStatRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpSymLinkRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpUnblockRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpWriteRequestTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Responses/ExtendedReplies/StatVfsReplyInfoTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpAttrsResponseTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpDataResponseTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpExtendedReplyResponseTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpHandleResponseTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpNameResponseTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpStatusResponseTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpVersionResponseTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpDataResponseBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpDownloadAsyncResultTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsNotOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsPartial.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadBeginReadException.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_DiscardsFurtherReadAheads.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackBeginReadException.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackEndInvokeException.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_ChunkAvailable.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_NoChunkAvailable.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReahAheadExceptionInBeginRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamAsyncTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Closed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionNotOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileAccessInvalid.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileExists.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileExists.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeInvalid.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_SessionNotOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_NoDataInBuffer.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileAccessInvalid.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileExists.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeInvalid.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetNegative.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetPositive.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetZero.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetNegative.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetPositive.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetZero.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Closed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthGreatherThanPosition.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthGreatherThanPosition.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionNotOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpHandleResponseBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpInitRequestBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpNameResponseBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpOpenRequestBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpReadRequestBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpRealPathRequestBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestRead.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestStatVfs.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_MultipleSftpMessagesInSingleSshDataMessage.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_MultipleSftpMessagesSplitOverMultipleSshDataMessages.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_SingleSftpMessageInSshDataMessage.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsRequestBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/Sftp/SftpVersionResponseBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFile.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFileAsync.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectoryAsync.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs (93%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SftpClientTest_Finalize_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ShellStreamTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteNumberOfBytesEqualToBufferSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferFullAndWriteLessBytesThanBufferSize.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferFullAndWriteZeroBytes.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteLessBytesThanBufferCanContain.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteMoreBytesThanBufferCanContain.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteZeroBytes.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshClientTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshClientTest_Disconnect_ForwardedPortStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disconnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_ForwardedPortStarted.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshCommandTest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshCommandTest_BeginExecute_EndExecuteInvokedOnAsyncResultFromPreviousInvocation.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshCommandTest_BeginExecute_EndExecuteNotInvokedOnAsyncResultFromPreviousInvocation.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshCommandTest_Dispose.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultFromOtherInstance.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultIsNull.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_ChannelOpen.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSessionStub.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disconnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_NeverConnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_SendSubsystemRequestFails.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_NeverConnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disconnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_NeverConnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_OnDataReceived_Exception.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionErrorOccurred_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionErrorOccurred_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Connected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disconnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disposed.cs (100%) rename {src => test}/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_NeverConnected.cs (100%) rename {src => test}/Renci.SshNet.Tests/Common/ArgumentExceptionAssert.cs (100%) rename {src => test}/Renci.SshNet.Tests/Common/ArrayBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Common/AsyncSocketListener.cs (100%) rename {src => test}/Renci.SshNet.Tests/Common/DictionaryAssert.cs (100%) rename {src => test}/Renci.SshNet.Tests/Common/Extensions.cs (100%) rename {src => test}/Renci.SshNet.Tests/Common/HttpProxyStub.cs (100%) rename {src => test}/Renci.SshNet.Tests/Common/HttpRequest.cs (100%) rename {src => test}/Renci.SshNet.Tests/Common/SftpFileAttributesBuilder.cs (100%) rename {src => test}/Renci.SshNet.Tests/Common/TestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Common/TripleATestBase.cs (100%) rename {src => test}/Renci.SshNet.Tests/Properties/Resources.Designer.cs (100%) rename {src => test}/Renci.SshNet.Tests/Properties/Resources.resx (100%) rename {src => test}/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj (77%) diff --git a/.gitignore b/.gitignore index 37793444d..8348fa321 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,7 @@ src/TestResults/ packages/ # Visual Studio 2015 cache/options directory -src/.vs/ +.vs/ # Expanded/resolved project.json files project.lock.json diff --git a/Directory.Build.props b/Directory.Build.props index 0baf38f42..100efff95 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -6,7 +6,7 @@ --> true - $(MSBuildThisFileDirectory)src\Renci.SshNet.snk + $(MSBuildThisFileDirectory)Renci.SshNet.snk true latest 9999 diff --git a/Renci.SshNet.sln b/Renci.SshNet.sln new file mode 100644 index 000000000..0ca62c338 --- /dev/null +++ b/Renci.SshNet.sln @@ -0,0 +1,222 @@ +锘 +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33326.253 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{94EE3919-19FA-4D9B-8DA9-249050B15232}" + ProjectSection(SolutionItems) = preProject + build\nuget\SSH.NET.nuspec = build\nuget\SSH.NET.nuspec + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandcastle", "sandcastle", "{A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1}" + ProjectSection(SolutionItems) = preProject + build\sandcastle\SSH.NET.shfbproj = build\sandcastle\SSH.NET.shfbproj + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet", "src\Renci.SshNet\Renci.SshNet.csproj", "{2F5F8C90-0BD1-424F-997C-7BC6280919D1}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{04E8CC26-116E-4116-9558-7ED542548E70}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitattributes = .gitattributes + .gitignore = .gitignore + appveyor.yml = appveyor.yml + CODEOWNERS = CODEOWNERS + Directory.Build.props = Directory.Build.props + global.json = global.json + LICENSE = LICENSE + README.md = README.md + stylecop.json = stylecop.json + THIRD-PARTY-NOTICES.TXT = THIRD-PARTY-NOTICES.TXT + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D21A4D03-0AC2-4613-BB6D-74D2D16A72CC}" + ProjectSection(SolutionItems) = preProject + test\.editorconfig = test\.editorconfig + test\Directory.Build.props = test\Directory.Build.props + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.IntegrationTests", "test\Renci.SshNet.IntegrationTests\Renci.SshNet.IntegrationTests.csproj", "{F17A24ED-4DC3-450C-A2AF-820CCD169828}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.Tests", "test\Renci.SshNet.Tests\Renci.SshNet.Tests.csproj", "{86238589-CCDF-4423-A007-989987A783D6}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.TestTools.OpenSSH", "test\Renci.SshNet.TestTools.OpenSSH\Renci.SshNet.TestTools.OpenSSH.csproj", "{01AE231E-5D28-4743-A95E-81EE15A823D0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2F4155AA-750A-4D33-B2E6-ED06660016CE}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "References", "References", "{47CAF831-32E1-49AD-8E24-6A8732CC2F35}" + ProjectSection(SolutionItems) = preProject + src\References\How the SCP protocol works.pdf = src\References\How the SCP protocol works.pdf + src\References\X.690-0207.pdf = src\References\X.690-0207.pdf + src\References\X.690-0207.txt = src\References\X.690-0207.txt + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "images", "images", "{296365E4-2EC8-4762-9640-618867AE3F53}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "logo", "logo", "{1E46D4B6-EE87-4D29-8641-0AE8CD8ED0F0}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ai", "ai", "{19895BAF-F946-470D-8497-7034F9F2A8A7}" + ProjectSection(SolutionItems) = preProject + images\logo\ai\SS-NET-icon-white.ai = images\logo\ai\SS-NET-icon-white.ai + images\logo\ai\SS-NET-icon.ai = images\logo\ai\SS-NET-icon.ai + images\logo\ai\SS-NET-white.ai = images\logo\ai\SS-NET-white.ai + images\logo\ai\SS-NET.ai = images\logo\ai\SS-NET.ai + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "png", "png", "{3572019A-3A57-4578-B5A2-6280576EB508}" + ProjectSection(SolutionItems) = preProject + images\logo\png\SS-NET-1280x640.png = images\logo\png\SS-NET-1280x640.png + images\logo\png\SS-NET-h50.png = images\logo\png\SS-NET-h50.png + images\logo\png\SS-NET-h500.png = images\logo\png\SS-NET-h500.png + images\logo\png\SS-NET-icon-h50.png = images\logo\png\SS-NET-icon-h50.png + images\logo\png\SS-NET-icon-h500.png = images\logo\png\SS-NET-icon-h500.png + images\logo\png\SS-NET-icon-white-h50.png = images\logo\png\SS-NET-icon-white-h50.png + images\logo\png\SS-NET-icon-white-h500.png = images\logo\png\SS-NET-icon-white-h500.png + images\logo\png\SS-NET-white-h50.png = images\logo\png\SS-NET-white-h50.png + images\logo\png\SS-NET-white-h500.png = images\logo\png\SS-NET-white-h500.png + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "svg", "svg", "{92E7B1B8-4C70-4138-9970-433B2FC2E3EB}" + ProjectSection(SolutionItems) = preProject + images\logo\svg\SS-NET-icon-white.svg = images\logo\svg\SS-NET-icon-white.svg + images\logo\svg\SS-NET-icon.svg = images\logo\svg\SS-NET-icon.svg + images\logo\svg\SS-NET-white.svg = images\logo\svg\SS-NET-white.svg + images\logo\svg\SS-NET.svg = images\logo\svg\SS-NET.svg + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.Benchmarks", "test\Renci.SshNet.Benchmarks\Renci.SshNet.Benchmarks.csproj", "{CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|ARM = Debug|ARM + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|ARM = Release|ARM + Release|Mixed Platforms = Release|Mixed Platforms + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|ARM.ActiveCfg = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x64.ActiveCfg = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x86.ActiveCfg = Debug|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.Build.0 = Release|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|ARM.ActiveCfg = Release|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x64.ActiveCfg = Release|Any CPU + {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x86.ActiveCfg = Release|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Debug|ARM.ActiveCfg = Debug|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Debug|ARM.Build.0 = Debug|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Debug|x64.ActiveCfg = Debug|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Debug|x64.Build.0 = Debug|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Debug|x86.ActiveCfg = Debug|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Debug|x86.Build.0 = Debug|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Release|Any CPU.Build.0 = Release|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Release|ARM.ActiveCfg = Release|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Release|ARM.Build.0 = Release|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Release|x64.ActiveCfg = Release|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Release|x64.Build.0 = Release|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Release|x86.ActiveCfg = Release|Any CPU + {F17A24ED-4DC3-450C-A2AF-820CCD169828}.Release|x86.Build.0 = Release|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Debug|ARM.ActiveCfg = Debug|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Debug|ARM.Build.0 = Debug|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Debug|x64.ActiveCfg = Debug|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Debug|x64.Build.0 = Debug|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Debug|x86.ActiveCfg = Debug|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Debug|x86.Build.0 = Debug|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Release|Any CPU.Build.0 = Release|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Release|ARM.ActiveCfg = Release|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Release|ARM.Build.0 = Release|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Release|x64.ActiveCfg = Release|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Release|x64.Build.0 = Release|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Release|x86.ActiveCfg = Release|Any CPU + {86238589-CCDF-4423-A007-989987A783D6}.Release|x86.Build.0 = Release|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Debug|ARM.ActiveCfg = Debug|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Debug|ARM.Build.0 = Debug|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Debug|x64.ActiveCfg = Debug|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Debug|x64.Build.0 = Debug|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Debug|x86.ActiveCfg = Debug|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Debug|x86.Build.0 = Debug|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Release|Any CPU.Build.0 = Release|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Release|ARM.ActiveCfg = Release|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Release|ARM.Build.0 = Release|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Release|x64.ActiveCfg = Release|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Release|x64.Build.0 = Release|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Release|x86.ActiveCfg = Release|Any CPU + {01AE231E-5D28-4743-A95E-81EE15A823D0}.Release|x86.Build.0 = Release|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Debug|ARM.ActiveCfg = Debug|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Debug|ARM.Build.0 = Debug|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Debug|x64.ActiveCfg = Debug|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Debug|x64.Build.0 = Debug|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Debug|x86.ActiveCfg = Debug|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Debug|x86.Build.0 = Debug|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Release|Any CPU.Build.0 = Release|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Release|ARM.ActiveCfg = Release|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Release|ARM.Build.0 = Release|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Release|x64.ActiveCfg = Release|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Release|x64.Build.0 = Release|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Release|x86.ActiveCfg = Release|Any CPU + {CF6CA77F-E4B8-4522-B267-E3F555E2E7B1}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} = {04E8CC26-116E-4116-9558-7ED542548E70} + {94EE3919-19FA-4D9B-8DA9-249050B15232} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} + {A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} + {D21A4D03-0AC2-4613-BB6D-74D2D16A72CC} = {04E8CC26-116E-4116-9558-7ED542548E70} + {2F4155AA-750A-4D33-B2E6-ED06660016CE} = {04E8CC26-116E-4116-9558-7ED542548E70} + {47CAF831-32E1-49AD-8E24-6A8732CC2F35} = {2F4155AA-750A-4D33-B2E6-ED06660016CE} + {296365E4-2EC8-4762-9640-618867AE3F53} = {04E8CC26-116E-4116-9558-7ED542548E70} + {1E46D4B6-EE87-4D29-8641-0AE8CD8ED0F0} = {296365E4-2EC8-4762-9640-618867AE3F53} + {19895BAF-F946-470D-8497-7034F9F2A8A7} = {1E46D4B6-EE87-4D29-8641-0AE8CD8ED0F0} + {3572019A-3A57-4578-B5A2-6280576EB508} = {1E46D4B6-EE87-4D29-8641-0AE8CD8ED0F0} + {92E7B1B8-4C70-4138-9970-433B2FC2E3EB} = {1E46D4B6-EE87-4D29-8641-0AE8CD8ED0F0} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {BAD6019D-4AF7-4E15-99A0-8036E16FC0E5} + EndGlobalSection + GlobalSection(TestCaseManagementSettings) = postSolution + CategoryFile = Renci.SshNet1.vsmdi + EndGlobalSection +EndGlobal diff --git a/src/Renci.SshNet.snk b/Renci.SshNet.snk similarity index 100% rename from src/Renci.SshNet.snk rename to Renci.SshNet.snk diff --git a/appveyor.yml b/appveyor.yml index c9bb51683..66f10858d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,14 +1,17 @@ os: Visual Studio 2022 before_build: - - nuget restore src\Renci.SshNet.sln + - nuget restore Renci.SshNet.sln + +install: + - cinst dotnet-sdk --version=7.0.402 --limit-output build: - project: src\Renci.SshNet.sln + project: Renci.SshNet.sln verbosity: minimal test_script: - cmd: >- - vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net462\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration" --blame + vstest.console /logger:Appveyor test\Renci.SshNet.Tests\bin\Debug\net462\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration" --blame - vstest.console /logger:Appveyor src\Renci.SshNet.Tests\bin\Debug\net7.0\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration" --blame + vstest.console /logger:Appveyor test\Renci.SshNet.Tests\bin\Debug\net7.0\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration" --blame diff --git a/global.json b/global.json new file mode 100644 index 000000000..878faf6e3 --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "7.0.402", + "rollForward": "disable" + } +} diff --git a/src/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj b/src/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj deleted file mode 100644 index daf3f5095..000000000 --- a/src/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj +++ /dev/null @@ -1,31 +0,0 @@ - - - - Exe - net7.0 - enable - enable - - $(NoWarn);CS1591 - - - - - - - - - - - - - - - diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj b/src/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj deleted file mode 100644 index bd59aa4e5..000000000 --- a/src/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj +++ /dev/null @@ -1,21 +0,0 @@ -锘 - - net7.0 - enable - enable - - - $(NoWarn);CS1591;SYSLIB0021;SYSLIB1045 - - - - - \ No newline at end of file diff --git a/src/Renci.SshNet.sln b/src/Renci.SshNet.sln deleted file mode 100644 index 259ae16ed..000000000 --- a/src/Renci.SshNet.sln +++ /dev/null @@ -1,174 +0,0 @@ -锘 -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.33326.253 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D}" - ProjectSection(SolutionItems) = preProject - ..\build\build.cmd = ..\build\build.cmd - ..\build\build.proj = ..\build\build.proj - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nuget", "nuget", "{94EE3919-19FA-4D9B-8DA9-249050B15232}" - ProjectSection(SolutionItems) = preProject - ..\build\nuget\SSH.NET.nuspec = ..\build\nuget\SSH.NET.nuspec - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sandcastle", "sandcastle", "{A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1}" - ProjectSection(SolutionItems) = preProject - ..\build\sandcastle\SSH.NET.shfbproj = ..\build\sandcastle\SSH.NET.shfbproj - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet", "Renci.SshNet\Renci.SshNet.csproj", "{2F5F8C90-0BD1-424F-997C-7BC6280919D1}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.Tests", "Renci.SshNet.Tests\Renci.SshNet.Tests.csproj", "{C45379B9-17B1-4E89-BC2E-6D41726413E8}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{04E8CC26-116E-4116-9558-7ED542548E70}" - ProjectSection(SolutionItems) = preProject - ..\.editorconfig = ..\.editorconfig - ..\.gitattributes = ..\.gitattributes - ..\.gitignore = ..\.gitignore - ..\appveyor.yml = ..\appveyor.yml - ..\CODEOWNERS = ..\CODEOWNERS - ..\Directory.Build.props = ..\Directory.Build.props - ..\LICENSE = ..\LICENSE - ..\README.md = ..\README.md - ..\THIRD-PARTY-NOTICES.TXT = ..\THIRD-PARTY-NOTICES.TXT - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{D21A4D03-0AC2-4613-BB6D-74D2D16A72CC}" - ProjectSection(SolutionItems) = preProject - ..\test\.editorconfig = ..\test\.editorconfig - ..\test\Directory.Build.props = ..\test\Directory.Build.props - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.Benchmarks", "Renci.SshNet.Benchmarks\Renci.SshNet.Benchmarks.csproj", "{A8C83FF2-B733-4A01-8D4E-D6DA2D420484}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.IntegrationTests", "Renci.SshNet.IntegrationTests\Renci.SshNet.IntegrationTests.csproj", "{EEF98046-729C-419E-932D-4E569073C8CC}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Renci.SshNet.TestTools.OpenSSH", "Renci.SshNet.TestTools.OpenSSH\Renci.SshNet.TestTools.OpenSSH.csproj", "{78239046-2019-494E-B6EC-240AF787E4D0}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E8A42832-1183-4E66-9141-DEBA662374DF}" - ProjectSection(SolutionItems) = preProject - global.json = global.json - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Debug|ARM = Debug|ARM - Debug|Mixed Platforms = Debug|Mixed Platforms - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|Any CPU = Release|Any CPU - Release|ARM = Release|ARM - Release|Mixed Platforms = Release|Mixed Platforms - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|ARM.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x64.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x86.ActiveCfg = Debug|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.Build.0 = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|ARM.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x64.ActiveCfg = Release|Any CPU - {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x86.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|ARM.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|x64.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Debug|x86.ActiveCfg = Debug|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Any CPU.Build.0 = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|ARM.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x64.ActiveCfg = Release|Any CPU - {C45379B9-17B1-4E89-BC2E-6D41726413E8}.Release|x86.ActiveCfg = Release|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|ARM.ActiveCfg = Debug|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|ARM.Build.0 = Debug|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|x64.ActiveCfg = Debug|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|x64.Build.0 = Debug|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|x86.ActiveCfg = Debug|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Debug|x86.Build.0 = Debug|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|Any CPU.Build.0 = Release|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|ARM.ActiveCfg = Release|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|ARM.Build.0 = Release|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|x64.ActiveCfg = Release|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|x64.Build.0 = Release|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|x86.ActiveCfg = Release|Any CPU - {A8C83FF2-B733-4A01-8D4E-D6DA2D420484}.Release|x86.Build.0 = Release|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|ARM.ActiveCfg = Debug|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|ARM.Build.0 = Debug|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|x64.ActiveCfg = Debug|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|x64.Build.0 = Debug|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|x86.ActiveCfg = Debug|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Debug|x86.Build.0 = Debug|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Release|Any CPU.Build.0 = Release|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Release|ARM.ActiveCfg = Release|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Release|ARM.Build.0 = Release|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Release|x64.ActiveCfg = Release|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Release|x64.Build.0 = Release|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Release|x86.ActiveCfg = Release|Any CPU - {EEF98046-729C-419E-932D-4E569073C8CC}.Release|x86.Build.0 = Release|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|ARM.ActiveCfg = Debug|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|ARM.Build.0 = Debug|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|x64.ActiveCfg = Debug|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|x64.Build.0 = Debug|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|x86.ActiveCfg = Debug|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Debug|x86.Build.0 = Debug|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Release|Any CPU.Build.0 = Release|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Release|ARM.ActiveCfg = Release|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Release|ARM.Build.0 = Release|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Release|x64.ActiveCfg = Release|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Release|x64.Build.0 = Release|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Release|x86.ActiveCfg = Release|Any CPU - {78239046-2019-494E-B6EC-240AF787E4D0}.Release|x86.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {94EE3919-19FA-4D9B-8DA9-249050B15232} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} - {A6C3FFD3-16A5-44D3-8C1F-3613D6DD17D1} = {2D6CAE62-D053-476F-9BDD-2B1F27FA9C5D} - {D21A4D03-0AC2-4613-BB6D-74D2D16A72CC} = {04E8CC26-116E-4116-9558-7ED542548E70} - {E8A42832-1183-4E66-9141-DEBA662374DF} = {04E8CC26-116E-4116-9558-7ED542548E70} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {BAD6019D-4AF7-4E15-99A0-8036E16FC0E5} - EndGlobalSection - GlobalSection(TestCaseManagementSettings) = postSolution - CategoryFile = Renci.SshNet1.vsmdi - EndGlobalSection -EndGlobal diff --git a/src/Data/Key.ECDSA.Encrypted.txt b/test/Data/Key.ECDSA.Encrypted.txt similarity index 100% rename from src/Data/Key.ECDSA.Encrypted.txt rename to test/Data/Key.ECDSA.Encrypted.txt diff --git a/src/Data/Key.ECDSA.txt b/test/Data/Key.ECDSA.txt similarity index 100% rename from src/Data/Key.ECDSA.txt rename to test/Data/Key.ECDSA.txt diff --git a/src/Data/Key.ECDSA384.Encrypted.txt b/test/Data/Key.ECDSA384.Encrypted.txt similarity index 100% rename from src/Data/Key.ECDSA384.Encrypted.txt rename to test/Data/Key.ECDSA384.Encrypted.txt diff --git a/src/Data/Key.ECDSA384.txt b/test/Data/Key.ECDSA384.txt similarity index 100% rename from src/Data/Key.ECDSA384.txt rename to test/Data/Key.ECDSA384.txt diff --git a/src/Data/Key.ECDSA521.Encrypted.txt b/test/Data/Key.ECDSA521.Encrypted.txt similarity index 100% rename from src/Data/Key.ECDSA521.Encrypted.txt rename to test/Data/Key.ECDSA521.Encrypted.txt diff --git a/src/Data/Key.ECDSA521.txt b/test/Data/Key.ECDSA521.txt similarity index 100% rename from src/Data/Key.ECDSA521.txt rename to test/Data/Key.ECDSA521.txt diff --git a/src/Data/Key.OPENSSH.ECDSA.Encrypted.txt b/test/Data/Key.OPENSSH.ECDSA.Encrypted.txt similarity index 100% rename from src/Data/Key.OPENSSH.ECDSA.Encrypted.txt rename to test/Data/Key.OPENSSH.ECDSA.Encrypted.txt diff --git a/src/Data/Key.OPENSSH.ECDSA.txt b/test/Data/Key.OPENSSH.ECDSA.txt similarity index 100% rename from src/Data/Key.OPENSSH.ECDSA.txt rename to test/Data/Key.OPENSSH.ECDSA.txt diff --git a/src/Data/Key.OPENSSH.ECDSA384.Encrypted.txt b/test/Data/Key.OPENSSH.ECDSA384.Encrypted.txt similarity index 100% rename from src/Data/Key.OPENSSH.ECDSA384.Encrypted.txt rename to test/Data/Key.OPENSSH.ECDSA384.Encrypted.txt diff --git a/src/Data/Key.OPENSSH.ECDSA384.txt b/test/Data/Key.OPENSSH.ECDSA384.txt similarity index 100% rename from src/Data/Key.OPENSSH.ECDSA384.txt rename to test/Data/Key.OPENSSH.ECDSA384.txt diff --git a/src/Data/Key.OPENSSH.ECDSA521.Encrypted.txt b/test/Data/Key.OPENSSH.ECDSA521.Encrypted.txt similarity index 100% rename from src/Data/Key.OPENSSH.ECDSA521.Encrypted.txt rename to test/Data/Key.OPENSSH.ECDSA521.Encrypted.txt diff --git a/src/Data/Key.OPENSSH.ECDSA521.txt b/test/Data/Key.OPENSSH.ECDSA521.txt similarity index 100% rename from src/Data/Key.OPENSSH.ECDSA521.txt rename to test/Data/Key.OPENSSH.ECDSA521.txt diff --git a/src/Data/Key.OPENSSH.ED25519.Encrypted.txt b/test/Data/Key.OPENSSH.ED25519.Encrypted.txt similarity index 100% rename from src/Data/Key.OPENSSH.ED25519.Encrypted.txt rename to test/Data/Key.OPENSSH.ED25519.Encrypted.txt diff --git a/src/Data/Key.OPENSSH.ED25519.txt b/test/Data/Key.OPENSSH.ED25519.txt similarity index 100% rename from src/Data/Key.OPENSSH.ED25519.txt rename to test/Data/Key.OPENSSH.ED25519.txt diff --git a/src/Data/Key.OPENSSH.RSA.Encrypted.txt b/test/Data/Key.OPENSSH.RSA.Encrypted.txt similarity index 100% rename from src/Data/Key.OPENSSH.RSA.Encrypted.txt rename to test/Data/Key.OPENSSH.RSA.Encrypted.txt diff --git a/src/Data/Key.OPENSSH.RSA.txt b/test/Data/Key.OPENSSH.RSA.txt similarity index 100% rename from src/Data/Key.OPENSSH.RSA.txt rename to test/Data/Key.OPENSSH.RSA.txt diff --git a/src/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt b/test/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt similarity index 100% rename from src/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt rename to test/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt diff --git a/src/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt b/test/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt similarity index 100% rename from src/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt rename to test/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt diff --git a/src/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt similarity index 100% rename from src/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt rename to test/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt diff --git a/src/Data/Key.RSA.Encrypted.Des.CBC.12345.txt b/test/Data/Key.RSA.Encrypted.Des.CBC.12345.txt similarity index 100% rename from src/Data/Key.RSA.Encrypted.Des.CBC.12345.txt rename to test/Data/Key.RSA.Encrypted.Des.CBC.12345.txt diff --git a/src/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt b/test/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt similarity index 100% rename from src/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt rename to test/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt diff --git a/src/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt b/test/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt similarity index 100% rename from src/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt rename to test/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt diff --git a/src/Data/Key.RSA.txt b/test/Data/Key.RSA.txt similarity index 100% rename from src/Data/Key.RSA.txt rename to test/Data/Key.RSA.txt diff --git a/src/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt b/test/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt similarity index 100% rename from src/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt rename to test/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt diff --git a/src/Data/Key.SSH2.DSA.txt b/test/Data/Key.SSH2.DSA.txt similarity index 100% rename from src/Data/Key.SSH2.DSA.txt rename to test/Data/Key.SSH2.DSA.txt diff --git a/src/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt b/test/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt similarity index 100% rename from src/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt rename to test/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt diff --git a/src/Data/Key.SSH2.RSA.txt b/test/Data/Key.SSH2.RSA.txt similarity index 100% rename from src/Data/Key.SSH2.RSA.txt rename to test/Data/Key.SSH2.RSA.txt diff --git a/src/Renci.SshNet.Benchmarks/Common/ExtensionsBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Common/ExtensionsBenchmarks.cs similarity index 100% rename from src/Renci.SshNet.Benchmarks/Common/ExtensionsBenchmarks.cs rename to test/Renci.SshNet.Benchmarks/Common/ExtensionsBenchmarks.cs diff --git a/src/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs similarity index 100% rename from src/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs rename to test/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs diff --git a/src/Renci.SshNet.Benchmarks/Program.cs b/test/Renci.SshNet.Benchmarks/Program.cs similarity index 100% rename from src/Renci.SshNet.Benchmarks/Program.cs rename to test/Renci.SshNet.Benchmarks/Program.cs diff --git a/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj b/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj new file mode 100644 index 000000000..ebad6e9d9 --- /dev/null +++ b/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj @@ -0,0 +1,20 @@ + + + Exe + net7.0 + enable + enable + + + + + + + + + + + + + + diff --git a/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs similarity index 100% rename from src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs rename to test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs diff --git a/src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs similarity index 100% rename from src/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs rename to test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs diff --git a/src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs similarity index 100% rename from src/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs rename to test/Renci.SshNet.Benchmarks/Security/Cryptography/ED25519DigitalSignatureBenchmarks.cs diff --git a/src/Renci.SshNet.IntegrationTests/.editorconfig b/test/Renci.SshNet.IntegrationTests/.editorconfig similarity index 100% rename from src/Renci.SshNet.IntegrationTests/.editorconfig rename to test/Renci.SshNet.IntegrationTests/.editorconfig diff --git a/src/Renci.SshNet.IntegrationTests/.gitignore b/test/Renci.SshNet.IntegrationTests/.gitignore similarity index 100% rename from src/Renci.SshNet.IntegrationTests/.gitignore rename to test/Renci.SshNet.IntegrationTests/.gitignore diff --git a/src/Renci.SshNet.IntegrationTests/App.config b/test/Renci.SshNet.IntegrationTests/App.config similarity index 100% rename from src/Renci.SshNet.IntegrationTests/App.config rename to test/Renci.SshNet.IntegrationTests/App.config diff --git a/src/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs b/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs rename to test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs diff --git a/src/Renci.SshNet.IntegrationTests/AuthenticationTests.cs b/test/Renci.SshNet.IntegrationTests/AuthenticationTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/AuthenticationTests.cs rename to test/Renci.SshNet.IntegrationTests/AuthenticationTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/CipherTests.cs b/test/Renci.SshNet.IntegrationTests/CipherTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/CipherTests.cs rename to test/Renci.SshNet.IntegrationTests/CipherTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/Common/ArrayBuilder.cs b/test/Renci.SshNet.IntegrationTests/Common/ArrayBuilder.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/Common/ArrayBuilder.cs rename to test/Renci.SshNet.IntegrationTests/Common/ArrayBuilder.cs diff --git a/src/Renci.SshNet.IntegrationTests/Common/AsyncSocketListener.cs b/test/Renci.SshNet.IntegrationTests/Common/AsyncSocketListener.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/Common/AsyncSocketListener.cs rename to test/Renci.SshNet.IntegrationTests/Common/AsyncSocketListener.cs diff --git a/src/Renci.SshNet.IntegrationTests/Common/DateTimeAssert.cs b/test/Renci.SshNet.IntegrationTests/Common/DateTimeAssert.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/Common/DateTimeAssert.cs rename to test/Renci.SshNet.IntegrationTests/Common/DateTimeAssert.cs diff --git a/src/Renci.SshNet.IntegrationTests/Common/DateTimeExtensions.cs b/test/Renci.SshNet.IntegrationTests/Common/DateTimeExtensions.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/Common/DateTimeExtensions.cs rename to test/Renci.SshNet.IntegrationTests/Common/DateTimeExtensions.cs diff --git a/src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs b/test/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs rename to test/Renci.SshNet.IntegrationTests/Common/RemoteSshdConfigExtensions.cs diff --git a/src/Renci.SshNet.IntegrationTests/Common/Socks5Handler.cs b/test/Renci.SshNet.IntegrationTests/Common/Socks5Handler.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/Common/Socks5Handler.cs rename to test/Renci.SshNet.IntegrationTests/Common/Socks5Handler.cs diff --git a/src/Renci.SshNet.IntegrationTests/ConnectivityTests.cs b/test/Renci.SshNet.IntegrationTests/ConnectivityTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/ConnectivityTests.cs rename to test/Renci.SshNet.IntegrationTests/ConnectivityTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/Credential.cs b/test/Renci.SshNet.IntegrationTests/Credential.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/Credential.cs rename to test/Renci.SshNet.IntegrationTests/Credential.cs diff --git a/src/Renci.SshNet.IntegrationTests/Dockerfile b/test/Renci.SshNet.IntegrationTests/Dockerfile similarity index 100% rename from src/Renci.SshNet.IntegrationTests/Dockerfile rename to test/Renci.SshNet.IntegrationTests/Dockerfile diff --git a/src/Renci.SshNet.IntegrationTests/HmacTests.cs b/test/Renci.SshNet.IntegrationTests/HmacTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/HmacTests.cs rename to test/Renci.SshNet.IntegrationTests/HmacTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/HostConfig.cs b/test/Renci.SshNet.IntegrationTests/HostConfig.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/HostConfig.cs rename to test/Renci.SshNet.IntegrationTests/HostConfig.cs diff --git a/src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs b/test/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs rename to test/Renci.SshNet.IntegrationTests/HostKeyAlgorithmTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/HostKeyFile.cs b/test/Renci.SshNet.IntegrationTests/HostKeyFile.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/HostKeyFile.cs rename to test/Renci.SshNet.IntegrationTests/HostKeyFile.cs diff --git a/src/Renci.SshNet.IntegrationTests/IConnectionInfoFactory.cs b/test/Renci.SshNet.IntegrationTests/IConnectionInfoFactory.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/IConnectionInfoFactory.cs rename to test/Renci.SshNet.IntegrationTests/IConnectionInfoFactory.cs diff --git a/src/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs b/test/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs rename to test/Renci.SshNet.IntegrationTests/KeyExchangeAlgorithmTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/LinuxAdminConnectionFactory.cs b/test/Renci.SshNet.IntegrationTests/LinuxAdminConnectionFactory.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/LinuxAdminConnectionFactory.cs rename to test/Renci.SshNet.IntegrationTests/LinuxAdminConnectionFactory.cs diff --git a/src/Renci.SshNet.IntegrationTests/LinuxVMConnectionFactory.cs b/test/Renci.SshNet.IntegrationTests/LinuxVMConnectionFactory.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/LinuxVMConnectionFactory.cs rename to test/Renci.SshNet.IntegrationTests/LinuxVMConnectionFactory.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/ScpClientTest.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/ScpClientTest.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/ScpClientTest.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/ScpClientTest.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ChangeDirectory.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ChangeDirectory.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ChangeDirectory.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ChangeDirectory.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.CreateDirectory.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.CreateDirectory.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.CreateDirectory.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.CreateDirectory.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.DeleteDirectory.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.DeleteDirectory.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.DeleteDirectory.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.DeleteDirectory.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Download.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Download.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Download.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Download.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ListDirectory.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ListDirectory.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ListDirectory.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.ListDirectory.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFile.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFile.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFile.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFile.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFileAsync.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFileAsync.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFileAsync.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.RenameFileAsync.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.SynchronizeDirectories.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.SynchronizeDirectories.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.SynchronizeDirectories.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.SynchronizeDirectories.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpFileTest.cs diff --git a/src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs rename to test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs diff --git a/src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs b/test/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs rename to test/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/Program.cs b/test/Renci.SshNet.IntegrationTests/Program.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/Program.cs rename to test/Renci.SshNet.IntegrationTests/Program.cs diff --git a/src/Renci.SshNet.IntegrationTests/RemoteSshd.cs b/test/Renci.SshNet.IntegrationTests/RemoteSshd.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/RemoteSshd.cs rename to test/Renci.SshNet.IntegrationTests/RemoteSshd.cs diff --git a/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj similarity index 77% rename from src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj rename to test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj index db411f361..e59cc1a93 100644 --- a/src/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj +++ b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj @@ -3,20 +3,9 @@ net7.0 enable - false true - - $(NoWarn);CS1591;SYSLIB0021;SYSLIB1045;SYSLIB0014;IDE0220;IDE0010 - + $(NoWarn);SYSLIB0021;SYSLIB1045;SYSLIB0014;IDE0220;IDE0010 @@ -27,7 +16,6 @@ - - runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -49,8 +36,9 @@ - + + diff --git a/src/Renci.SshNet.IntegrationTests/ScpClientTests.cs b/test/Renci.SshNet.IntegrationTests/ScpClientTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/ScpClientTests.cs rename to test/Renci.SshNet.IntegrationTests/ScpClientTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/ScpTests.cs b/test/Renci.SshNet.IntegrationTests/ScpTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/ScpTests.cs rename to test/Renci.SshNet.IntegrationTests/ScpTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/SftpClientTests.cs b/test/Renci.SshNet.IntegrationTests/SftpClientTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/SftpClientTests.cs rename to test/Renci.SshNet.IntegrationTests/SftpClientTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/SftpTests.cs b/test/Renci.SshNet.IntegrationTests/SftpTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/SftpTests.cs rename to test/Renci.SshNet.IntegrationTests/SftpTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/SshClientTests.cs b/test/Renci.SshNet.IntegrationTests/SshClientTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/SshClientTests.cs rename to test/Renci.SshNet.IntegrationTests/SshClientTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/SshConnectionDisruptor.cs b/test/Renci.SshNet.IntegrationTests/SshConnectionDisruptor.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/SshConnectionDisruptor.cs rename to test/Renci.SshNet.IntegrationTests/SshConnectionDisruptor.cs diff --git a/src/Renci.SshNet.IntegrationTests/SshConnectionRestorer.cs b/test/Renci.SshNet.IntegrationTests/SshConnectionRestorer.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/SshConnectionRestorer.cs rename to test/Renci.SshNet.IntegrationTests/SshConnectionRestorer.cs diff --git a/src/Renci.SshNet.IntegrationTests/SshTests.cs b/test/Renci.SshNet.IntegrationTests/SshTests.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/SshTests.cs rename to test/Renci.SshNet.IntegrationTests/SshTests.cs diff --git a/src/Renci.SshNet.IntegrationTests/TestBase.cs b/test/Renci.SshNet.IntegrationTests/TestBase.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/TestBase.cs rename to test/Renci.SshNet.IntegrationTests/TestBase.cs diff --git a/src/Renci.SshNet.IntegrationTests/TestInitializer.cs b/test/Renci.SshNet.IntegrationTests/TestInitializer.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/TestInitializer.cs rename to test/Renci.SshNet.IntegrationTests/TestInitializer.cs diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs b/test/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs similarity index 96% rename from src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs rename to test/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs index b98de1267..97e8c3776 100644 --- a/src/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs +++ b/test/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs @@ -36,7 +36,7 @@ public async Task InitializeAsync() { _sshServerImage = new ImageFromDockerfileBuilder() .WithName("renci-ssh-tests-server-image") - .WithDockerfileDirectory(CommonDirectoryPath.GetSolutionDirectory(), "Renci.SshNet.IntegrationTests") + .WithDockerfileDirectory(CommonDirectoryPath.GetSolutionDirectory(), Path.Combine("test", "Renci.SshNet.IntegrationTests")) .WithDockerfile("Dockerfile") .WithDeleteIfExists(true) diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs b/test/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs rename to test/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs diff --git a/src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs b/test/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs rename to test/Renci.SshNet.IntegrationTests/TestsFixtures/SshUser.cs diff --git a/src/Renci.SshNet.IntegrationTests/Users.cs b/test/Renci.SshNet.IntegrationTests/Users.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/Users.cs rename to test/Renci.SshNet.IntegrationTests/Users.cs diff --git a/src/Renci.SshNet.IntegrationTests/Usings.cs b/test/Renci.SshNet.IntegrationTests/Usings.cs similarity index 100% rename from src/Renci.SshNet.IntegrationTests/Usings.cs rename to test/Renci.SshNet.IntegrationTests/Usings.cs diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/id_dsa b/test/Renci.SshNet.IntegrationTests/resources/client/id_dsa similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/id_dsa rename to test/Renci.SshNet.IntegrationTests/resources/client/id_dsa diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk b/test/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk rename to test/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa b/test/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa rename to test/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/id_rsa b/test/Renci.SshNet.IntegrationTests/resources/client/id_rsa similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/id_rsa rename to test/Renci.SshNet.IntegrationTests/resources/client/id_rsa diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub b/test/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub rename to test/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass b/test/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass rename to test/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh b/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh rename to test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub b/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub rename to test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh b/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh rename to test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub b/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub rename to test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh b/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh rename to test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub b/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub rename to test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub diff --git a/src/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh b/test/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh rename to test/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh diff --git a/src/Renci.SshNet.IntegrationTests/resources/issue #70.png b/test/Renci.SshNet.IntegrationTests/resources/issue #70.png similarity index 100% rename from src/Renci.SshNet.IntegrationTests/resources/issue #70.png rename to test/Renci.SshNet.IntegrationTests/resources/issue #70.png diff --git a/src/Renci.SshNet.IntegrationTests/server/script/start.sh b/test/Renci.SshNet.IntegrationTests/server/script/start.sh similarity index 100% rename from src/Renci.SshNet.IntegrationTests/server/script/start.sh rename to test/Renci.SshNet.IntegrationTests/server/script/start.sh diff --git a/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_dsa_key b/test/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_dsa_key similarity index 100% rename from src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_dsa_key rename to test/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_dsa_key diff --git a/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ecdsa_key b/test/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ecdsa_key similarity index 100% rename from src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ecdsa_key rename to test/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ecdsa_key diff --git a/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ed25519_key b/test/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ed25519_key similarity index 100% rename from src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ed25519_key rename to test/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_ed25519_key diff --git a/src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_rsa_key b/test/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_rsa_key similarity index 100% rename from src/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_rsa_key rename to test/Renci.SshNet.IntegrationTests/server/ssh/ssh_host_rsa_key diff --git a/src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys b/test/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys similarity index 100% rename from src/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys rename to test/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Cipher.cs b/test/Renci.SshNet.TestTools.OpenSSH/Cipher.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/Cipher.cs rename to test/Renci.SshNet.TestTools.OpenSSH/Cipher.cs diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs rename to test/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs rename to test/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs rename to test/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs rename to test/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs rename to test/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs diff --git a/src/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs b/test/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs rename to test/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs diff --git a/src/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs b/test/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs rename to test/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs diff --git a/src/Renci.SshNet.TestTools.OpenSSH/LogLevel.cs b/test/Renci.SshNet.TestTools.OpenSSH/LogLevel.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/LogLevel.cs rename to test/Renci.SshNet.TestTools.OpenSSH/LogLevel.cs diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Match.cs b/test/Renci.SshNet.TestTools.OpenSSH/Match.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/Match.cs rename to test/Renci.SshNet.TestTools.OpenSSH/Match.cs diff --git a/src/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs b/test/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs rename to test/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs diff --git a/src/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs b/test/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs rename to test/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs diff --git a/test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj b/test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj new file mode 100644 index 000000000..26ab725ef --- /dev/null +++ b/test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj @@ -0,0 +1,13 @@ +锘 + + net7.0 + enable + enable + $(NoWarn);SYSLIB0021;SYSLIB1045 + + + + + + + \ No newline at end of file diff --git a/src/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs b/test/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs rename to test/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs diff --git a/src/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs b/test/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs similarity index 100% rename from src/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs rename to test/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs diff --git a/src/Renci.SshNet.Tests/.editorconfig b/test/Renci.SshNet.Tests/.editorconfig similarity index 100% rename from src/Renci.SshNet.Tests/.editorconfig rename to test/Renci.SshNet.Tests/.editorconfig diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTestBase.cs b/test/Renci.SshNet.Tests/Classes/BaseClientTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/BaseClientTestBase.cs rename to test/Renci.SshNet.Tests/Classes/BaseClientTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs b/test/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs rename to test/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs b/test/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs rename to test/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NegativeOne.cs diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs b/test/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs rename to test/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs b/test/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs rename to test/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAlivesNotSentConcurrently.cs diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_Connect.cs b/test/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_Connect.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_Connect.cs rename to test/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_Connect.cs diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs b/test/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs rename to test/Renci.SshNet.Tests/Classes/BaseClientTest_Disconnected_KeepAliveInterval_NotNegativeOne.cs diff --git a/src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs b/test/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs rename to test/Renci.SshNet.Tests/Classes/BaseClientTest_NotConnected_KeepAliveInterval_NotNegativeOne.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelForwardedTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTestBase.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTestBase.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Disposed_Closed.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Disposed_Closed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Disposed_Closed.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Disposed_Closed.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelStub.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelStub.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelStub.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelStub.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTestBase.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTestBase.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsNotOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofNotReceived_SendEofInvoked.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_DisconnectWaitingForChannelCloseMessage.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_DisconnectWaitingForChannelCloseMessage.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_DisconnectWaitingForChannelCloseMessage.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_DisconnectWaitingForChannelCloseMessage.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_TimeoutWaitingForChannelCloseMessage.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_TimeoutWaitingForChannelCloseMessage.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_TimeoutWaitingForChannelCloseMessage.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsConnectedAndChannelIsOpen_EofReceived_TimeoutWaitingForChannelCloseMessage.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsNotOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsOpen.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsOpen.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_Dispose_SessionIsNotConnectedAndChannelIsOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_OnClose_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_DisposeChannelInClosedEventHandler.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_DisposeChannelInClosedEventHandler.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_DisposeChannelInClosedEventHandler.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_DisposeChannelInClosedEventHandler.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofNotReceived.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofReceived.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofReceived.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofReceived.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen_EofReceived.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelDataReceived_OnData_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelEofReceived_OnEof_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelExtendedDataReceived_OnExtendedData_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelFailureReceived_OnFailure_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelRequestReceived_OnRequest_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelSuccessReceived_OnSuccess_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionChannelWindowAdjustReceived_OnWindowAdjust_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_OnDisconnected_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionDisconnected_SessionIsConnectedAndChannelIsOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionErrorOccurred_OnErrorOccurred_Exception.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionErrorOccurred_OnErrorOccurred_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionErrorOccurred_OnErrorOccurred_Exception.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_OnSessionErrorOccurred_OnErrorOccurred_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsNotOpen.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsNotOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsNotOpen.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsNotOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsOpen.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsOpen.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ChannelTest_SendEof_ChannelIsOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ClientChannelStub.cs b/test/Renci.SshNet.Tests/Classes/Channels/ClientChannelStub.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ClientChannelStub.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ClientChannelStub.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ClientChannelTest_OnSessionChannelOpenConfirmationReceived_OnOpenConfirmation_Exception.cs b/test/Renci.SshNet.Tests/Classes/Channels/ClientChannelTest_OnSessionChannelOpenConfirmationReceived_OnOpenConfirmation_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ClientChannelTest_OnSessionChannelOpenConfirmationReceived_OnOpenConfirmation_Exception.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ClientChannelTest_OnSessionChannelOpenConfirmationReceived_OnOpenConfirmation_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/Channels/ClientChannelTest_OnSessionChannelOpenFailureReceived_OnOpenFailure_Exception.cs b/test/Renci.SshNet.Tests/Classes/Channels/ClientChannelTest_OnSessionChannelOpenFailureReceived_OnOpenFailure_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Channels/ClientChannelTest_OnSessionChannelOpenFailureReceived_OnOpenFailure_Exception.cs rename to test/Renci.SshNet.Tests/Classes/Channels/ClientChannelTest_OnSessionChannelOpenFailureReceived_OnOpenFailure_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTestBase.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTestBase.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_MultiList_AllAllowedAuthenticationsHaveReachedPartialSuccessLimit.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_MultiList_AllAllowedAuthenticationsHaveReachedPartialSuccessLimit.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_MultiList_AllAllowedAuthenticationsHaveReachedPartialSuccessLimit.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_MultiList_AllAllowedAuthenticationsHaveReachedPartialSuccessLimit.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_SingleList_AuthenticationMethodFailed.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_SingleList_AuthenticationMethodFailed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_SingleList_AuthenticationMethodFailed.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_SingleList_AuthenticationMethodFailed.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_SingleList_AuthenticationMethodNotConfigured.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_SingleList_AuthenticationMethodNotConfigured.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_SingleList_AuthenticationMethodNotConfigured.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Failure_SingleList_AuthenticationMethodNotConfigured.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_DifferentAllowedAuthenticationsAfterPartialSuccess.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_DifferentAllowedAuthenticationsAfterPartialSuccess.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_DifferentAllowedAuthenticationsAfterPartialSuccess.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_DifferentAllowedAuthenticationsAfterPartialSuccess.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch2.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch2.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch2.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInAlternateBranch2.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInSameBranch.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInSameBranch.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInSameBranch.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedByFailureInSameBranch.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInAlternateBranch.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInSameBranch.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInSameBranch.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInSameBranch.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PartialSuccessLimitReachedFollowedBySuccessInSameBranch.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PostponePartialAccessAuthenticationMethod.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PostponePartialAccessAuthenticationMethod.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PostponePartialAccessAuthenticationMethod.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_PostponePartialAccessAuthenticationMethod.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_SameAllowedAuthenticationsAfterPartialSuccess.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_SameAllowedAuthenticationsAfterPartialSuccess.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_SameAllowedAuthenticationsAfterPartialSuccess.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_SameAllowedAuthenticationsAfterPartialSuccess.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_SkipFailedAuthenticationMethod.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_SkipFailedAuthenticationMethod.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_SkipFailedAuthenticationMethod.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_MultiList_SkipFailedAuthenticationMethod.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess.cs diff --git a/src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess_PartialSuccessLimitReached.cs b/test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess_PartialSuccessLimitReached.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess_PartialSuccessLimitReached.cs rename to test/Renci.SshNet.Tests/Classes/ClientAuthenticationTest_Success_SingleList_SameAllowedAuthenticationAfterPartialSuccess_PartialSuccessLimitReached.cs diff --git a/src/Renci.SshNet.Tests/Classes/CommandAsyncResultTest.cs b/test/Renci.SshNet.Tests/Classes/CommandAsyncResultTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/CommandAsyncResultTest.cs rename to test/Renci.SshNet.Tests/Classes/CommandAsyncResultTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/AuthenticationBannerEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/AuthenticationBannerEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/AuthenticationBannerEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/AuthenticationBannerEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs b/test/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs b/test/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/BigIntegerTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ChannelDataEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ChannelDataEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ChannelDataEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/ChannelDataEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ChannelEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ChannelEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ChannelEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/ChannelEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ChannelOpenFailedEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ChannelOpenFailedEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ChannelOpenFailedEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/ChannelOpenFailedEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ChannelRequestEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ChannelRequestEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ChannelRequestEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/ChannelRequestEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs b/test/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/CountdownEventTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_NotSet.cs b/test/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_NotSet.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_NotSet.cs rename to test/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_NotSet.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_Set.cs b/test/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_Set.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_Set.cs rename to test/Renci.SshNet.Tests/Classes/Common/CountdownEventTest_Dispose_Set.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExceptionEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ExceptionEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ExceptionEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/ExceptionEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs b/test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs rename to test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Concat.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs b/test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs rename to test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_IsEqualTo_ByteArray.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Pad.cs b/test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Pad.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Pad.cs rename to test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Pad.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Reverse.cs b/test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Reverse.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Reverse.cs rename to test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Reverse.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_Count.cs b/test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_Count.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_Count.cs rename to test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_Count.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_OffsetAndCount.cs b/test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_OffsetAndCount.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_OffsetAndCount.cs rename to test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_Take_OffsetAndCount.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToBigInteger2.cs b/test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToBigInteger2.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToBigInteger2.cs rename to test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_ToBigInteger2.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_TrimLeadingZeros.cs b/test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_TrimLeadingZeros.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_TrimLeadingZeros.cs rename to test/Renci.SshNet.Tests/Classes/Common/ExtensionsTest_TrimLeadingZeros.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/NetConfServerExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/NetConfServerExceptionTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/NetConfServerExceptionTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/NetConfServerExceptionTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ObjectIdentifierTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ObjectIdentifierTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ObjectIdentifierTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/ObjectIdentifierTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/PackTest.cs b/test/Renci.SshNet.Tests/Classes/Common/PackTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/PackTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/PackTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs b/test/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/PacketDumpTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs b/test/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/PipeStreamTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs b/test/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs rename to test/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs b/test/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs rename to test/Renci.SshNet.Tests/Classes/Common/PipeStream_Close_BlockingWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs b/test/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs rename to test/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_BytesRemainingAfterRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs b/test/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs rename to test/Renci.SshNet.Tests/Classes/Common/PipeStream_Flush_NoBytesRemainingAfterRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/PortForwardEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/PortForwardEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/PortForwardEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/PortForwardEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs b/test/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs rename to test/Renci.SshNet.Tests/Classes/Common/PosixPathTest_CreateAbsoluteOrRelativeFilePath.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetDirectoryName.cs b/test/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetDirectoryName.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetDirectoryName.cs rename to test/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetDirectoryName.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs b/test/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs rename to test/Renci.SshNet.Tests/Classes/Common/PosixPathTest_GetFileName.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ScpDownloadEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ScpDownloadEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ScpDownloadEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/ScpDownloadEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ScpExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ScpExceptionTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ScpExceptionTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/ScpExceptionTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ScpUploadEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ScpUploadEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ScpUploadEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/ScpUploadEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/SftpPathNotFoundExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SftpPathNotFoundExceptionTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/SftpPathNotFoundExceptionTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/SftpPathNotFoundExceptionTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/SftpPermissionDeniedExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SftpPermissionDeniedExceptionTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/SftpPermissionDeniedExceptionTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/SftpPermissionDeniedExceptionTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/ShellDataEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ShellDataEventArgsTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/ShellDataEventArgsTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/ShellDataEventArgsTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/SshAuthenticationExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SshAuthenticationExceptionTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/SshAuthenticationExceptionTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/SshAuthenticationExceptionTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/SshDataTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SshDataTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/SshDataTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/SshDataTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/SshOperationTimeoutExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SshOperationTimeoutExceptionTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/SshOperationTimeoutExceptionTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/SshOperationTimeoutExceptionTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Common/SshPassPhraseNullOrEmptyExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SshPassPhraseNullOrEmptyExceptionTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Common/SshPassPhraseNullOrEmptyExceptionTest.cs rename to test/Renci.SshNet.Tests/Classes/Common/SshPassPhraseNullOrEmptyExceptionTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs b/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs rename to test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionRefusedByServer.cs b/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionRefusedByServer.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionRefusedByServer.cs rename to test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionRefusedByServer.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionSucceeded.cs b/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionSucceeded.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionSucceeded.cs rename to test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_ConnectionSucceeded.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs b/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs rename to test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_HostNameInvalid.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs b/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs rename to test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTestBase.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTestBase.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ConnectionToProxyRefused.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ConnectionToProxyRefused.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ConnectionToProxyRefused.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ConnectionToProxyRefused.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyClosesConnectionBeforeStatusLineIsSent.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyHostInvalid.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsEmpty.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyPasswordIsNull.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseDoesNotContainHttpStatusLine.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_ExtraTextBeforeStatusLine.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_HeadersAndContent.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIs200_OnlyHeaders.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyResponseStatusIsNot200.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsEmpty.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNotNullAndNotEmpty.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_ProxyUserNameIsNull.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs rename to test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs b/test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs rename to test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ConnectionClosedByServer_NoDataSentByServer.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter.cs b/test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter.cs rename to test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseContainsNullCharacter.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs b/test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs rename to test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseInvalid_SshIdentificationOnlyContainsProtocolVersion.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs b/test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs rename to test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_Comments.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs b/test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs rename to test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_NoComments.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs b/test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs rename to test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_ServerResponseValid_TerminatedByLineFeedWithoutCarriageReturn.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs b/test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs rename to test/Renci.SshNet.Tests/Classes/Connection/ProtocolVersionExchangeTest_TimeoutReadingIdentificationString.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionRejectedByProxy.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionToProxyRefused.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionToProxyRefused.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionToProxyRefused.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionToProxyRefused.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingDestinationAddress.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyCode.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutReadingReplyVersion.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ConnectionToProxyRefused.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ConnectionToProxyRefused.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ConnectionToProxyRefused.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ConnectionToProxyRefused.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_ProxySocksVersionIsNotSupported.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_AuthenticationFailed.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_PasswordExceedsMaximumLength.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs rename to test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_UserNameExceedsMaximumLength.cs diff --git a/src/Renci.SshNet.Tests/Classes/Connection/SshIdentificationTest.cs b/test/Renci.SshNet.Tests/Classes/Connection/SshIdentificationTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Connection/SshIdentificationTest.cs rename to test/Renci.SshNet.Tests/Classes/Connection/SshIdentificationTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/ConnectionInfoTest.cs b/test/Renci.SshNet.Tests/Classes/ConnectionInfoTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ConnectionInfoTest.cs rename to test/Renci.SshNet.Tests/Classes/ConnectionInfoTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/ConnectionInfoTest_Authenticate_Failure.cs b/test/Renci.SshNet.Tests/Classes/ConnectionInfoTest_Authenticate_Failure.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ConnectionInfoTest_Authenticate_Failure.cs rename to test/Renci.SshNet.Tests/Classes/ConnectionInfoTest_Authenticate_Failure.cs diff --git a/src/Renci.SshNet.Tests/Classes/ConnectionInfoTest_Authenticate_Success.cs b/test/Renci.SshNet.Tests/Classes/ConnectionInfoTest_Authenticate_Success.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ConnectionInfoTest_Authenticate_Success.cs rename to test/Renci.SshNet.Tests/Classes/ConnectionInfoTest_Authenticate_Success.cs diff --git a/src/Renci.SshNet.Tests/Classes/ExpectActionTest.cs b/test/Renci.SshNet.Tests/Classes/ExpectActionTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ExpectActionTest.cs rename to test/Renci.SshNet.Tests/Classes/ExpectActionTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortDisposed.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortDisposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortDisposed.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortDisposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortNeverStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortNeverStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortNeverStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortNeverStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelBound.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelBound.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelBound.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStopped.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStopped.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStopped.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStopped.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_SessionErrorOccurred_ChannelBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_SessionErrorOccurred_ChannelBound.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_SessionErrorOccurred_ChannelBound.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_SessionErrorOccurred_ChannelBound.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortDisposed.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortDisposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortDisposed.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortDisposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortNeverStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortNeverStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortNeverStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortNeverStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortStopped.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortStopped.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortStopped.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_PortStopped.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_SessionNotConnected.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_SessionNotConnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_SessionNotConnected.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_SessionNotConnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_SessionNull.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_SessionNull.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_SessionNull.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Start_SessionNull.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketSendShutdownImmediately.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketSendShutdownImmediately.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketSendShutdownImmediately.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketSendShutdownImmediately.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketVersionNotSupported.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketVersionNotSupported.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketVersionNotSupported.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Started_SocketVersionNotSupported.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortDisposed.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortDisposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortDisposed.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortDisposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortNeverStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortNeverStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortNeverStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortNeverStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelBound.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelBound.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelBound.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStopped.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStopped.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStopped.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStopped.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortDisposed.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortDisposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortDisposed.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortDisposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortDisposed_NeverStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortDisposed_NeverStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortDisposed_NeverStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortDisposed_NeverStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortNeverStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortNeverStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortNeverStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortNeverStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStarted_ChannelBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStarted_ChannelBound.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStarted_ChannelBound.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStarted_ChannelBound.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStarted_ChannelNotBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStarted_ChannelNotBound.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStarted_ChannelNotBound.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStarted_ChannelNotBound.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStopped.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStopped.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStopped.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Dispose_PortStopped.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortDisposed.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortDisposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortDisposed.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortDisposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortNeverStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortNeverStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortNeverStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortNeverStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStopped.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStopped.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStopped.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_PortStopped.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_SessionNotConnected.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_SessionNotConnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_SessionNotConnected.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_SessionNotConnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_SessionNull.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_SessionNull.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_SessionNull.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Start_SessionNull.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortDisposed.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortDisposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortDisposed.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortDisposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortNeverStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortNeverStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortNeverStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortNeverStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStarted_ChannelBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStarted_ChannelBound.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStarted_ChannelBound.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStarted_ChannelBound.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStarted_ChannelNotBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStarted_ChannelNotBound.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStarted_ChannelNotBound.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStarted_ChannelNotBound.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStopped.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStopped.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStopped.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortLocalTest_Stop_PortStopped.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortDisposed.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortDisposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortDisposed.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortDisposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortNeverStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortNeverStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortNeverStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortNeverStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortStarted_ChannelBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortStarted_ChannelBound.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortStarted_ChannelBound.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortStarted_ChannelBound.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortStopped.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortStopped.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortStopped.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Dispose_PortStopped.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortDisposed.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortDisposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortDisposed.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortDisposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortNeverStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortNeverStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortNeverStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortNeverStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStopped.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStopped.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStopped.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortStopped.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNotConnected.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNotConnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNotConnected.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNotConnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNull.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNull.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNull.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_SessionNull.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Started.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Started.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Started.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Started.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortDisposed.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortDisposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortDisposed.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortDisposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortNeverStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortNeverStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortNeverStarted.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortNeverStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortStarted_ChannelBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortStarted_ChannelBound.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortStarted_ChannelBound.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortStarted_ChannelBound.cs diff --git a/src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortStopped.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortStopped.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortStopped.cs rename to test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Stop_PortStopped.cs diff --git a/src/Renci.SshNet.Tests/Classes/KeyboardInteractiveAuthenticationMethodTest.cs b/test/Renci.SshNet.Tests/Classes/KeyboardInteractiveAuthenticationMethodTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/KeyboardInteractiveAuthenticationMethodTest.cs rename to test/Renci.SshNet.Tests/Classes/KeyboardInteractiveAuthenticationMethodTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs rename to test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs rename to test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/PseudoTerminalInfoTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/PseudoTerminalInfoTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/PseudoTerminalInfoTest.cs rename to test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelRequest/PseudoTerminalInfoTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Connection/GlobalRequestMessageTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Connection/GlobalRequestMessageTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Messages/Connection/GlobalRequestMessageTest.cs rename to test/Renci.SshNet.Tests/Classes/Messages/Connection/GlobalRequestMessageTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs rename to test/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupBuilder.cs b/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupBuilder.cs rename to test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupBuilder.cs diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeInitTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeInitTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeInitTest.cs rename to test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeInitTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs b/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs rename to test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyTest.cs rename to test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeInitMessageTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeInitMessageTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeInitMessageTest.cs rename to test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeInitMessageTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs b/test/Renci.SshNet.Tests/Classes/NetConfClientTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/NetConfClientTest.cs rename to test/Renci.SshNet.Tests/Classes/NetConfClientTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTestBase.cs b/test/Renci.SshNet.Tests/Classes/NetConfClientTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/NetConfClientTestBase.cs rename to test/Renci.SshNet.Tests/Classes/NetConfClientTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs b/test/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs rename to test/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs b/test/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs rename to test/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs b/test/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs rename to test/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disconnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs b/test/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/NetConfClientTest_Dispose_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs b/test/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs rename to test/Renci.SshNet.Tests/Classes/NetConfClientTest_Finalize_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/NoneAuthenticationMethodTest.cs b/test/Renci.SshNet.Tests/Classes/NoneAuthenticationMethodTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/NoneAuthenticationMethodTest.cs rename to test/Renci.SshNet.Tests/Classes/NoneAuthenticationMethodTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs b/test/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs rename to test/Renci.SshNet.Tests/Classes/PasswordAuthenticationMethodTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs b/test/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs rename to test/Renci.SshNet.Tests/Classes/PasswordConnectionInfoTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/PipeStreamTest_Dispose.cs b/test/Renci.SshNet.Tests/Classes/PipeStreamTest_Dispose.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/PipeStreamTest_Dispose.cs rename to test/Renci.SshNet.Tests/Classes/PipeStreamTest_Dispose.cs diff --git a/src/Renci.SshNet.Tests/Classes/PrivateKeyAuthenticationMethodTest.cs b/test/Renci.SshNet.Tests/Classes/PrivateKeyAuthenticationMethodTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/PrivateKeyAuthenticationMethodTest.cs rename to test/Renci.SshNet.Tests/Classes/PrivateKeyAuthenticationMethodTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs rename to test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/RemotePathDoubleQuoteTransformationTest.cs b/test/Renci.SshNet.Tests/Classes/RemotePathDoubleQuoteTransformationTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/RemotePathDoubleQuoteTransformationTest.cs rename to test/Renci.SshNet.Tests/Classes/RemotePathDoubleQuoteTransformationTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/RemotePathShellQuoteTransformationTest.cs b/test/Renci.SshNet.Tests/Classes/RemotePathShellQuoteTransformationTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/RemotePathShellQuoteTransformationTest.cs rename to test/Renci.SshNet.Tests/Classes/RemotePathShellQuoteTransformationTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest.cs b/test/Renci.SshNet.Tests/Classes/ScpClientTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ScpClientTest.cs rename to test/Renci.SshNet.Tests/Classes/ScpClientTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTestBase.cs b/test/Renci.SshNet.Tests/Classes/ScpClientTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ScpClientTestBase.cs rename to test/Renci.SshNet.Tests/Classes/ScpClientTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs b/test/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs rename to test/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndDirectoryInfo_SendExecRequestReturnsFalse.cs diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs b/test/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs rename to test/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndFileInfo_SendExecRequestReturnsFalse.cs diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs b/test/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs rename to test/Renci.SshNet.Tests/Classes/ScpClientTest_Download_PathAndStream_SendExecRequestReturnsFalse.cs diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs b/test/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs rename to test/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_DirectoryInfoAndPath_SendExecRequestReturnsFalse.cs diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs b/test/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs rename to test/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_SendExecRequestReturnsFalse.cs diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs b/test/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs rename to test/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_FileInfoAndPath_Success.cs diff --git a/src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs b/test/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs rename to test/Renci.SshNet.Tests/Classes/ScpClientTest_Upload_StreamAndPath_SendExecRequestReturnsFalse.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/BlockCipherTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/BlockCipherTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/Cryptography/BlockCipherTest.cs rename to test/Renci.SshNet.Tests/Classes/Security/Cryptography/BlockCipherTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs rename to test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs rename to test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Arc4CipherTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs rename to test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/BlowfishCipherTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs rename to test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/CastCipherTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs rename to test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/DesCipherTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS5PaddingTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS5PaddingTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS5PaddingTest.cs rename to test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS5PaddingTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS7PaddingTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS7PaddingTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS7PaddingTest.cs rename to test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/Paddings/PKCS7PaddingTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs rename to test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/TripleDesCipherTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs rename to test/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs rename to test/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha1Test.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha1Test.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha1Test.cs rename to test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha1Test.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs rename to test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup14Sha256Test.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup16Sha512Test.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup16Sha512Test.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup16Sha512Test.cs rename to test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup16Sha512Test.cs diff --git a/src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup1Sha1Test.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup1Sha1Test.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup1Sha1Test.cs rename to test/Renci.SshNet.Tests/Classes/Security/KeyExchangeDiffieHellmanGroup1Sha1Test.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateClientAuthentication.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateClientAuthentication.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateClientAuthentication.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateClientAuthentication.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateConnector.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateConnector.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateConnector.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateConnector.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsAlmostSixTimesGreaterThanChunkSize.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsAlmostSixTimesGreaterThanChunkSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsAlmostSixTimesGreaterThanChunkSize.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsAlmostSixTimesGreaterThanChunkSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsEqualToChunkSize.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsEqualToChunkSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsEqualToChunkSize.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsEqualToChunkSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsExactlyFiveTimesGreaterThanChunkSize.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsExactlyFiveTimesGreaterThanChunkSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsExactlyFiveTimesGreaterThanChunkSize.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsExactlyFiveTimesGreaterThanChunkSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLessThanChunkSize.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLessThanChunkSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLessThanChunkSize.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLessThanChunkSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLittleMoreThanFiveTimesGreaterThanChunkSize.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLittleMoreThanFiveTimesGreaterThanChunkSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLittleMoreThanFiveTimesGreaterThanChunkSize.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsLittleMoreThanFiveTimesGreaterThanChunkSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsZero.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_ChannelOpenThrowsException.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_ChannelOpenThrowsException.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_ChannelOpenThrowsException.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_ChannelOpenThrowsException.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestReturnsFalse.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestReturnsFalse.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestReturnsFalse.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestReturnsFalse.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestThrowsException.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestThrowsException.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestThrowsException.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendPseudoTerminalRequestThrowsException.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestReturnsFalse.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestReturnsFalse.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestReturnsFalse.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestReturnsFalse.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestThrowsException.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestThrowsException.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestThrowsException.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_SendShellRequestThrowsException.cs diff --git a/src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_Success.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_Success.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_Success.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateShellStream_Success.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest.cs b/test/Renci.SshNet.Tests/Classes/SessionTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTestBase.cs b/test/Renci.SshNet.Tests/Classes/SessionTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTestBase.cs rename to test/Renci.SshNet.Tests/Classes/SessionTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectToServerFails.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectToServerFails.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_ConnectToServerFails.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_ConnectToServerFails.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ConnectionReset.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_Connected_Disconnect.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_Connected_GlobalRequestMessageAfterAuthenticationRace.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsBadPacket.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessage.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsDisconnectMessageAndShutsDownSocket.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerSendsUnsupportedMessageType.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSendAfterSendingIncompletePacket.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerShutsDownSocket.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_NotConnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs rename to test/Renci.SshNet.Tests/Classes/SessionTest_SocketConnected_BadPacketAndDispose.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/FStatVfsRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/FStatVfsRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/FStatVfsRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/FStatVfsRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/HardLinkRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/HardLinkRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/HardLinkRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/HardLinkRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/PosixRenameRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/PosixRenameRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/PosixRenameRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/PosixRenameRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/StatVfsRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/StatVfsRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/StatVfsRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/ExtendedRequests/StatVfsRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpBlockRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpBlockRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpBlockRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpBlockRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpCloseRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpCloseRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpCloseRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpCloseRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpFSetStatRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpFSetStatRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpFSetStatRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpFSetStatRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpFStatRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpFStatRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpFStatRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpFStatRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpInitRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpInitRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpInitRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpInitRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpLStatRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpLStatRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpLStatRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpLStatRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpLinkRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpLinkRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpLinkRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpLinkRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpMkDirRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpMkDirRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpMkDirRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpMkDirRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpOpenDirRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpOpenDirRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpOpenDirRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpOpenDirRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpOpenRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpOpenRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpOpenRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpOpenRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadDirRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadDirRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadDirRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadDirRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadLinkRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadLinkRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadLinkRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadLinkRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpReadRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRealPathRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRealPathRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRealPathRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRealPathRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRemoveRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRemoveRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRemoveRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRemoveRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRenameRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRenameRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRenameRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRenameRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRmDirRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRmDirRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRmDirRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpRmDirRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpSetStatRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpSetStatRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpSetStatRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpSetStatRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpStatRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpStatRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpStatRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpStatRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpSymLinkRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpSymLinkRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpSymLinkRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpSymLinkRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpUnblockRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpUnblockRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpUnblockRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpUnblockRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpWriteRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpWriteRequestTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpWriteRequestTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Requests/SftpWriteRequestTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Responses/ExtendedReplies/StatVfsReplyInfoTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Responses/ExtendedReplies/StatVfsReplyInfoTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Responses/ExtendedReplies/StatVfsReplyInfoTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Responses/ExtendedReplies/StatVfsReplyInfoTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpAttrsResponseTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpAttrsResponseTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpAttrsResponseTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpAttrsResponseTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpDataResponseTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpDataResponseTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpDataResponseTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpDataResponseTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpExtendedReplyResponseTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpExtendedReplyResponseTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpExtendedReplyResponseTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpExtendedReplyResponseTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpHandleResponseTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpHandleResponseTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpHandleResponseTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpHandleResponseTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpNameResponseTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpNameResponseTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpNameResponseTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpNameResponseTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpStatusResponseTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpStatusResponseTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpStatusResponseTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpStatusResponseTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpVersionResponseTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpVersionResponseTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpVersionResponseTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpVersionResponseTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpDataResponseBuilder.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpDataResponseBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpDataResponseBuilder.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpDataResponseBuilder.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpDownloadAsyncResultTest.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpDownloadAsyncResultTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpDownloadAsyncResultTest.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpDownloadAsyncResultTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_DisposeShouldUnblockReadAndReadAhead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsNotOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsNotOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsNotOpen.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsNotOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_BeginCloseThrowsException.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Dispose_SftpSessionIsOpen_EndCloseThrowsException.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsComplete.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsPartial.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsPartial.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsPartial.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_LastChunkBeforeEofIsPartial.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsNotReached.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_PreviousChunkIsIncompleteAndEofIsReached.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadBeginReadException.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadBeginReadException.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadBeginReadException.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadBeginReadException.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_DiscardsFurtherReadAheads.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_DiscardsFurtherReadAheads.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_DiscardsFurtherReadAheads.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_DiscardsFurtherReadAheads.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadAheadEndInvokeException_PreventsFurtherReadAheads.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackBeginReadException.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackBeginReadException.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackBeginReadException.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackBeginReadException.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackEndInvokeException.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackEndInvokeException.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackEndInvokeException.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_ReadBackEndInvokeException.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_ChunkAvailable.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_ChunkAvailable.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_ChunkAvailable.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_ChunkAvailable.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_NoChunkAvailable.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_NoChunkAvailable.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_NoChunkAvailable.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReadAheadExceptionInWaitOnHandle_NoChunkAvailable.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReahAheadExceptionInBeginRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReahAheadExceptionInBeginRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReahAheadExceptionInBeginRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileReaderTest_Read_ReahAheadExceptionInBeginRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamAsyncTestBase.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamAsyncTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamAsyncTestBase.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamAsyncTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTestBase.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTestBase.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Closed.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Closed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Closed.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Closed.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionNotOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionNotOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionNotOpen.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionNotOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileAccessInvalid.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileAccessInvalid.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileAccessInvalid.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileAccessInvalid.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileExists.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileExists.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileExists.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessReadWrite_FileExists.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileExists.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileExists.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileExists.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessWrite_FileExists.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeInvalid.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeInvalid.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeInvalid.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeInvalid.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpenOrCreate_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeOpen_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Disposed.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_NotReadFromBuffer.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_DataInBuffer_ReadFromBuffer.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_ReadMode_NoDataInBuffer.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_SessionNotOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_SessionNotOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_SessionNotOpen.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_SessionNotOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_DataInBuffer.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_NoDataInBuffer.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_NoDataInBuffer.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_NoDataInBuffer.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Flush_WriteMode_NoDataInBuffer.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileAccessInvalid.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileAccessInvalid.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileAccessInvalid.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileAccessInvalid.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileDoesNotExist.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileExists.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileExists.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileExists.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessReadWrite_FileExists.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileDoesNotExist.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessWrite_FileExists.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeInvalid.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeInvalid.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeInvalid.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeInvalid.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpenOrCreate_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeOpen_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadAsync_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_LessDataThanReadBufferSizeAvailable.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndEqualToBufferSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadLessBytesFromServerThanCountAndLessThanBufferSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Read_ReadMode_NoDataInReaderBufferAndReadMoreBytesFromServerThanCount.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetNegative.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetNegative.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetNegative.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetNegative.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetPositive.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetPositive.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetPositive.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetPositive.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetZero.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetZero.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetZero.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginBeginAndOffsetZero.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetNegative.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetNegative.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetNegative.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetNegative.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetPositive.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetPositive.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetPositive.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetPositive.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetZero.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetZero.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetZero.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtBeginningOfStream_OriginEndAndOffsetZero.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_NoBuffering.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Seek_PositionedAtMiddleOfStream_OriginBeginAndOffsetZero_ReadBuffer.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Closed.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Closed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Closed.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Closed.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthGreatherThanPosition.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthGreatherThanPosition.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthGreatherThanPosition.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthGreatherThanPosition.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInReadBuffer_NewLengthLessThanPosition.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthGreatherThanPosition.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthGreatherThanPosition.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthGreatherThanPosition.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthGreatherThanPosition.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_DataInWriteBuffer_NewLengthLessThanPosition.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Disposed.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionNotOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionNotOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionNotOpen.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionNotOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_WriteAsync_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Write_SessionOpen_CountGreatherThanTwoTimesTheWriteBufferSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpHandleResponseBuilder.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpHandleResponseBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpHandleResponseBuilder.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpHandleResponseBuilder.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpInitRequestBuilder.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpInitRequestBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpInitRequestBuilder.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpInitRequestBuilder.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpNameResponseBuilder.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpNameResponseBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpNameResponseBuilder.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpNameResponseBuilder.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpOpenRequestBuilder.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpOpenRequestBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpOpenRequestBuilder.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpOpenRequestBuilder.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpReadRequestBuilder.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpReadRequestBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpReadRequestBuilder.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpReadRequestBuilder.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpRealPathRequestBuilder.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpRealPathRequestBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpRealPathRequestBuilder.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpRealPathRequestBuilder.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestRead.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestRead.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestRead.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestStatVfs.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestStatVfs.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestStatVfs.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_Connected_RequestStatVfs.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_MultipleSftpMessagesInSingleSshDataMessage.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_MultipleSftpMessagesInSingleSshDataMessage.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_MultipleSftpMessagesInSingleSshDataMessage.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_MultipleSftpMessagesInSingleSshDataMessage.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_MultipleSftpMessagesSplitOverMultipleSshDataMessages.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_MultipleSftpMessagesSplitOverMultipleSshDataMessages.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_MultipleSftpMessagesSplitOverMultipleSshDataMessages.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_MultipleSftpMessagesSplitOverMultipleSshDataMessages.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_SingleSftpMessageInSshDataMessage.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_SingleSftpMessageInSshDataMessage.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_SingleSftpMessageInSshDataMessage.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpSessionTest_DataReceived_SingleSftpMessageInSshDataMessage.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsRequestBuilder.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsRequestBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsRequestBuilder.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsRequestBuilder.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpStatVfsResponseBuilder.cs diff --git a/src/Renci.SshNet.Tests/Classes/Sftp/SftpVersionResponseBuilder.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpVersionResponseBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/Sftp/SftpVersionResponseBuilder.cs rename to test/Renci.SshNet.Tests/Classes/Sftp/SftpVersionResponseBuilder.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest.Connect.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteDirectory.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFile.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFile.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFile.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFile.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFileAsync.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFileAsync.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFileAsync.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest.DeleteFileAsync.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectory.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectoryAsync.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectoryAsync.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectoryAsync.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest.ListDirectoryAsync.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTestBase.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTestBase.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTestBase.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs similarity index 93% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs index 80c050a82..92f29113a 100644 --- a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs +++ b/test/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs @@ -119,9 +119,15 @@ public void HostKeyReceivedOnSessionShouldNoLongerBeSignaledViaHostKeyReceivedOn private static KeyHostAlgorithm GetKeyHostAlgorithm() { var executingAssembly = Assembly.GetExecutingAssembly(); + var resourceName = string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"); - using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) + using (var s = executingAssembly.GetManifestResourceStream(resourceName)) { + if (s is null) + { + throw new ArgumentException($"Resource '{resourceName}' does not exist in assembly '{executingAssembly.GetName().Name}'."); + } + var privateKey = new PrivateKeyFile(s); return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First(); } diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disconnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest_Dispose_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/SftpClientTest_Finalize_Connected.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest_Finalize_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SftpClientTest_Finalize_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SftpClientTest_Finalize_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/ShellStreamTest.cs b/test/Renci.SshNet.Tests/Classes/ShellStreamTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ShellStreamTest.cs rename to test/Renci.SshNet.Tests/Classes/ShellStreamTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize.cs b/test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize.cs rename to test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteLessBytesThanBufferSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs b/test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs rename to test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteMoreBytesThanBufferSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteNumberOfBytesEqualToBufferSize.cs b/test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteNumberOfBytesEqualToBufferSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteNumberOfBytesEqualToBufferSize.cs rename to test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteNumberOfBytesEqualToBufferSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs b/test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs rename to test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferEmptyAndWriteZeroBytes.cs diff --git a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferFullAndWriteLessBytesThanBufferSize.cs b/test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferFullAndWriteLessBytesThanBufferSize.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferFullAndWriteLessBytesThanBufferSize.cs rename to test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferFullAndWriteLessBytesThanBufferSize.cs diff --git a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferFullAndWriteZeroBytes.cs b/test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferFullAndWriteZeroBytes.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferFullAndWriteZeroBytes.cs rename to test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferFullAndWriteZeroBytes.cs diff --git a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteLessBytesThanBufferCanContain.cs b/test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteLessBytesThanBufferCanContain.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteLessBytesThanBufferCanContain.cs rename to test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteLessBytesThanBufferCanContain.cs diff --git a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteMoreBytesThanBufferCanContain.cs b/test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteMoreBytesThanBufferCanContain.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteMoreBytesThanBufferCanContain.cs rename to test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteMoreBytesThanBufferCanContain.cs diff --git a/src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteZeroBytes.cs b/test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteZeroBytes.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteZeroBytes.cs rename to test/Renci.SshNet.Tests/Classes/ShellStreamTest_Write_WriteBufferNotEmptyAndWriteZeroBytes.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest.cs b/test/Renci.SshNet.Tests/Classes/SshClientTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshClientTest.cs rename to test/Renci.SshNet.Tests/Classes/SshClientTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs b/test/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSizeAndTerminalModes_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs b/test/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SshClientTest_CreateShellStream_TerminalNameAndColumnsAndRowsAndWidthAndHeightAndBufferSize_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_Disconnect_ForwardedPortStarted.cs b/test/Renci.SshNet.Tests/Classes/SshClientTest_Disconnect_ForwardedPortStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshClientTest_Disconnect_ForwardedPortStarted.cs rename to test/Renci.SshNet.Tests/Classes/SshClientTest_Disconnect_ForwardedPortStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Connected.cs b/test/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disconnected.cs b/test/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disconnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disconnected.cs rename to test/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disconnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disposed.cs b/test/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_ForwardedPortStarted.cs b/test/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_ForwardedPortStarted.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_ForwardedPortStarted.cs rename to test/Renci.SshNet.Tests/Classes/SshClientTest_Dispose_ForwardedPortStarted.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest.cs b/test/Renci.SshNet.Tests/Classes/SshCommandTest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshCommandTest.cs rename to test/Renci.SshNet.Tests/Classes/SshCommandTest.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest_BeginExecute_EndExecuteInvokedOnAsyncResultFromPreviousInvocation.cs b/test/Renci.SshNet.Tests/Classes/SshCommandTest_BeginExecute_EndExecuteInvokedOnAsyncResultFromPreviousInvocation.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshCommandTest_BeginExecute_EndExecuteInvokedOnAsyncResultFromPreviousInvocation.cs rename to test/Renci.SshNet.Tests/Classes/SshCommandTest_BeginExecute_EndExecuteInvokedOnAsyncResultFromPreviousInvocation.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest_BeginExecute_EndExecuteNotInvokedOnAsyncResultFromPreviousInvocation.cs b/test/Renci.SshNet.Tests/Classes/SshCommandTest_BeginExecute_EndExecuteNotInvokedOnAsyncResultFromPreviousInvocation.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshCommandTest_BeginExecute_EndExecuteNotInvokedOnAsyncResultFromPreviousInvocation.cs rename to test/Renci.SshNet.Tests/Classes/SshCommandTest_BeginExecute_EndExecuteNotInvokedOnAsyncResultFromPreviousInvocation.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest_Dispose.cs b/test/Renci.SshNet.Tests/Classes/SshCommandTest_Dispose.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshCommandTest_Dispose.cs rename to test/Renci.SshNet.Tests/Classes/SshCommandTest_Dispose.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute.cs b/test/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute.cs rename to test/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultFromOtherInstance.cs b/test/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultFromOtherInstance.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultFromOtherInstance.cs rename to test/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultFromOtherInstance.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultIsNull.cs b/test/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultIsNull.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultIsNull.cs rename to test/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_AsyncResultIsNull.cs diff --git a/src/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_ChannelOpen.cs b/test/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_ChannelOpen.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_ChannelOpen.cs rename to test/Renci.SshNet.Tests/Classes/SshCommandTest_EndExecute_ChannelOpen.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSessionStub.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSessionStub.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSessionStub.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSessionStub.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Connected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disconnected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disconnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disconnected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disconnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disposed.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_NeverConnected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_NeverConnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_NeverConnected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_NeverConnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_SendSubsystemRequestFails.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_SendSubsystemRequestFails.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_SendSubsystemRequestFails.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_Connect_SendSubsystemRequestFails.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Connected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Disposed.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_NeverConnected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_NeverConnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_NeverConnected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_Disconnect_NeverConnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Connected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disconnected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disconnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disconnected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disconnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disposed.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_NeverConnected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_NeverConnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_NeverConnected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_Dispose_NeverConnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_Connected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_Disposed.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_OnDataReceived_Exception.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_OnDataReceived_Exception.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_OnDataReceived_Exception.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelDataReceived_OnDataReceived_Exception.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Connected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Disposed.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_OnChannelException_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Connected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Disposed.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionDisconnected_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionErrorOccurred_Connected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionErrorOccurred_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionErrorOccurred_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionErrorOccurred_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionErrorOccurred_Disposed.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionErrorOccurred_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionErrorOccurred_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_OnSessionErrorOccurred_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Connected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Connected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Connected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Connected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disconnected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disconnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disconnected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disconnected.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disposed.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disposed.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disposed.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_Disposed.cs diff --git a/src/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_NeverConnected.cs b/test/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_NeverConnected.cs similarity index 100% rename from src/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_NeverConnected.cs rename to test/Renci.SshNet.Tests/Classes/SubsystemSession_SendData_NeverConnected.cs diff --git a/src/Renci.SshNet.Tests/Common/ArgumentExceptionAssert.cs b/test/Renci.SshNet.Tests/Common/ArgumentExceptionAssert.cs similarity index 100% rename from src/Renci.SshNet.Tests/Common/ArgumentExceptionAssert.cs rename to test/Renci.SshNet.Tests/Common/ArgumentExceptionAssert.cs diff --git a/src/Renci.SshNet.Tests/Common/ArrayBuilder.cs b/test/Renci.SshNet.Tests/Common/ArrayBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Common/ArrayBuilder.cs rename to test/Renci.SshNet.Tests/Common/ArrayBuilder.cs diff --git a/src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs b/test/Renci.SshNet.Tests/Common/AsyncSocketListener.cs similarity index 100% rename from src/Renci.SshNet.Tests/Common/AsyncSocketListener.cs rename to test/Renci.SshNet.Tests/Common/AsyncSocketListener.cs diff --git a/src/Renci.SshNet.Tests/Common/DictionaryAssert.cs b/test/Renci.SshNet.Tests/Common/DictionaryAssert.cs similarity index 100% rename from src/Renci.SshNet.Tests/Common/DictionaryAssert.cs rename to test/Renci.SshNet.Tests/Common/DictionaryAssert.cs diff --git a/src/Renci.SshNet.Tests/Common/Extensions.cs b/test/Renci.SshNet.Tests/Common/Extensions.cs similarity index 100% rename from src/Renci.SshNet.Tests/Common/Extensions.cs rename to test/Renci.SshNet.Tests/Common/Extensions.cs diff --git a/src/Renci.SshNet.Tests/Common/HttpProxyStub.cs b/test/Renci.SshNet.Tests/Common/HttpProxyStub.cs similarity index 100% rename from src/Renci.SshNet.Tests/Common/HttpProxyStub.cs rename to test/Renci.SshNet.Tests/Common/HttpProxyStub.cs diff --git a/src/Renci.SshNet.Tests/Common/HttpRequest.cs b/test/Renci.SshNet.Tests/Common/HttpRequest.cs similarity index 100% rename from src/Renci.SshNet.Tests/Common/HttpRequest.cs rename to test/Renci.SshNet.Tests/Common/HttpRequest.cs diff --git a/src/Renci.SshNet.Tests/Common/SftpFileAttributesBuilder.cs b/test/Renci.SshNet.Tests/Common/SftpFileAttributesBuilder.cs similarity index 100% rename from src/Renci.SshNet.Tests/Common/SftpFileAttributesBuilder.cs rename to test/Renci.SshNet.Tests/Common/SftpFileAttributesBuilder.cs diff --git a/src/Renci.SshNet.Tests/Common/TestBase.cs b/test/Renci.SshNet.Tests/Common/TestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Common/TestBase.cs rename to test/Renci.SshNet.Tests/Common/TestBase.cs diff --git a/src/Renci.SshNet.Tests/Common/TripleATestBase.cs b/test/Renci.SshNet.Tests/Common/TripleATestBase.cs similarity index 100% rename from src/Renci.SshNet.Tests/Common/TripleATestBase.cs rename to test/Renci.SshNet.Tests/Common/TripleATestBase.cs diff --git a/src/Renci.SshNet.Tests/Properties/Resources.Designer.cs b/test/Renci.SshNet.Tests/Properties/Resources.Designer.cs similarity index 100% rename from src/Renci.SshNet.Tests/Properties/Resources.Designer.cs rename to test/Renci.SshNet.Tests/Properties/Resources.Designer.cs diff --git a/src/Renci.SshNet.Tests/Properties/Resources.resx b/test/Renci.SshNet.Tests/Properties/Resources.resx similarity index 100% rename from src/Renci.SshNet.Tests/Properties/Resources.resx rename to test/Renci.SshNet.Tests/Properties/Resources.resx diff --git a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj similarity index 77% rename from src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj rename to test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index aa9d79a2a..a4bce13e7 100644 --- a/src/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -1,26 +1,12 @@ 锘 net462;net6.0;net7.0 - - $(NoWarn);CS1591 - - - - $(MSBuildProgramFiles32)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll @@ -36,14 +22,14 @@ $(MSTestV1UnitTestFrameworkAssemblyCandidate) - + - + From 46796094f1f9662d8a0b533fa4cd84086493e465 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Sun, 15 Oct 2023 07:25:22 +0100 Subject: [PATCH 52/96] Delete more dummy tests (#1213) --- .../AuthenticationBannerEventArgsTest.cs | 29 --------- ...thenticationPasswordChangeEventArgsTest.cs | 43 ------------- .../AuthenticationPromptEventArgsTest.cs | 31 --------- .../Common/AuthenticationPromptTest.cs | 44 ------------- .../Classes/Common/ExceptionEventArgsTest.cs | 26 -------- .../Common/NetConfServerExceptionTest.cs | 48 -------------- .../Classes/Common/ProxyExceptionTest.cs | 48 -------------- .../Common/ScpDownloadEventArgsTest.cs | 27 -------- .../Classes/Common/ScpExceptionTest.cs | 48 -------------- .../Classes/Common/ScpUploadEventArgsTest.cs | 27 -------- .../Common/SftpPathNotFoundExceptionTest.cs | 48 -------------- .../SftpPermissionDeniedExceptionTest.cs | 48 -------------- .../Classes/Common/ShellDataEventArgsTest.cs | 35 ---------- .../Common/SshAuthenticationExceptionTest.cs | 47 -------------- .../Common/SshConnectionExceptionTest.cs | 64 ------------------- .../Classes/Common/SshExceptionTest.cs | 48 -------------- .../SshOperationTimeoutExceptionTest.cs | 48 -------------- .../SshPassPhraseNullOrEmptyExceptionTest.cs | 48 -------------- 18 files changed, 757 deletions(-) delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/AuthenticationBannerEventArgsTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/ExceptionEventArgsTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/NetConfServerExceptionTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/ScpDownloadEventArgsTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/ScpExceptionTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/ScpUploadEventArgsTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/SftpPathNotFoundExceptionTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/SftpPermissionDeniedExceptionTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/ShellDataEventArgsTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/SshAuthenticationExceptionTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/SshOperationTimeoutExceptionTest.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/SshPassPhraseNullOrEmptyExceptionTest.cs diff --git a/test/Renci.SshNet.Tests/Classes/Common/AuthenticationBannerEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/AuthenticationBannerEventArgsTest.cs deleted file mode 100644 index f41123f4a..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/AuthenticationBannerEventArgsTest.cs +++ /dev/null @@ -1,29 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - - - /// - ///This is a test class for AuthenticationBannerEventArgsTest and is intended - ///to contain all AuthenticationBannerEventArgsTest Unit Tests - /// - [TestClass] - public class AuthenticationBannerEventArgsTest : TestBase - { - /// - ///A test for AuthenticationBannerEventArgs Constructor - /// - [TestMethod] - public void AuthenticationBannerEventArgsConstructorTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - string message = string.Empty; // TODO: Initialize to an appropriate value - string language = string.Empty; // TODO: Initialize to an appropriate value - AuthenticationBannerEventArgs target = new AuthenticationBannerEventArgs(username, message, language); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs deleted file mode 100644 index 9200d2a43..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/AuthenticationPasswordChangeEventArgsTest.cs +++ /dev/null @@ -1,43 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - - - /// - ///This is a test class for AuthenticationPasswordChangeEventArgsTest and is intended - ///to contain all AuthenticationPasswordChangeEventArgsTest Unit Tests - /// - [TestClass] - public class AuthenticationPasswordChangeEventArgsTest : TestBase - { - /// - ///A test for AuthenticationPasswordChangeEventArgs Constructor - /// - [TestMethod] - public void AuthenticationPasswordChangeEventArgsConstructorTest() - { - var username = string.Empty; // TODO: Initialize to an appropriate value - var target = new AuthenticationPasswordChangeEventArgs(username); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for NewPassword - /// - [TestMethod] - public void NewPasswordTest() - { - string username = string.Empty; // TODO: Initialize to an appropriate value - var target = new AuthenticationPasswordChangeEventArgs(username); // TODO: Initialize to an appropriate value - byte[] expected = null; // TODO: Initialize to an appropriate value - byte[] actual; - target.NewPassword = expected; - actual = target.NewPassword; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs deleted file mode 100644 index 47b83126f..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptEventArgsTest.cs +++ /dev/null @@ -1,31 +0,0 @@ -锘縰sing System.Collections.Generic; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - - - /// - ///This is a test class for AuthenticationPromptEventArgsTest and is intended - ///to contain all AuthenticationPromptEventArgsTest Unit Tests - /// - [TestClass] - public class AuthenticationPromptEventArgsTest : TestBase - { - /// - ///A test for AuthenticationPromptEventArgs Constructor - /// - [TestMethod] - public void AuthenticationPromptEventArgsConstructorTest() - { - var username = string.Empty; // TODO: Initialize to an appropriate value - var instruction = string.Empty; // TODO: Initialize to an appropriate value - var language = string.Empty; // TODO: Initialize to an appropriate value - IEnumerable prompts = null; // TODO: Initialize to an appropriate value - var target = new AuthenticationPromptEventArgs(username, instruction, language, prompts); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs b/test/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs deleted file mode 100644 index 5fbf25821..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/AuthenticationPromptTest.cs +++ /dev/null @@ -1,44 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for AuthenticationPromptTest and is intended - ///to contain all AuthenticationPromptTest Unit Tests - /// - [TestClass] - public class AuthenticationPromptTest : TestBase - { - /// - ///A test for AuthenticationPrompt Constructor - /// - [TestMethod] - public void AuthenticationPromptConstructorTest() - { - var id = 0; // TODO: Initialize to an appropriate value - var isEchoed = false; // TODO: Initialize to an appropriate value - var request = string.Empty; // TODO: Initialize to an appropriate value - var target = new AuthenticationPrompt(id, isEchoed, request); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for Response - /// - [TestMethod] - public void ResponseTest() - { - var id = 0; // TODO: Initialize to an appropriate value - var isEchoed = false; // TODO: Initialize to an appropriate value - var request = string.Empty; // TODO: Initialize to an appropriate value - var target = new AuthenticationPrompt(id, isEchoed, request); // TODO: Initialize to an appropriate value - var expected = string.Empty; // TODO: Initialize to an appropriate value - target.Response = expected; - var actual = target.Response; - Assert.AreEqual(expected, actual); - Assert.Inconclusive("Verify the correctness of this test method."); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/ExceptionEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ExceptionEventArgsTest.cs deleted file mode 100644 index ce9542324..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/ExceptionEventArgsTest.cs +++ /dev/null @@ -1,26 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for ExceptionEventArgsTest and is intended - ///to contain all ExceptionEventArgsTest Unit Tests - /// - [TestClass] - public class ExceptionEventArgsTest : TestBase - { - /// - ///A test for ExceptionEventArgs Constructor - /// - [TestMethod] - public void ExceptionEventArgsConstructorTest() - { - Exception exception = null; // TODO: Initialize to an appropriate value - ExceptionEventArgs target = new ExceptionEventArgs(exception); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/NetConfServerExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/NetConfServerExceptionTest.cs deleted file mode 100644 index fc3ac4d76..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/NetConfServerExceptionTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for NetConfServerExceptionTest and is intended - ///to contain all NetConfServerExceptionTest Unit Tests - /// - [TestClass] - public class NetConfServerExceptionTest : TestBase - { - /// - ///A test for NetConfServerException Constructor - /// - [TestMethod] - public void NetConfServerExceptionConstructorTest() - { - NetConfServerException target = new NetConfServerException(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for NetConfServerException Constructor - /// - [TestMethod] - public void NetConfServerExceptionConstructorTest1() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - NetConfServerException target = new NetConfServerException(message); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for NetConfServerException Constructor - /// - [TestMethod] - public void NetConfServerExceptionConstructorTest2() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - Exception innerException = null; // TODO: Initialize to an appropriate value - NetConfServerException target = new NetConfServerException(message, innerException); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.cs deleted file mode 100644 index b14d6ccea..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/ProxyExceptionTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for ProxyExceptionTest and is intended - ///to contain all ProxyExceptionTest Unit Tests - /// - [TestClass] - public class ProxyExceptionTest : TestBase - { - /// - ///A test for ProxyException Constructor - /// - [TestMethod] - public void ProxyExceptionConstructorTest() - { - ProxyException target = new ProxyException(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ProxyException Constructor - /// - [TestMethod] - public void ProxyExceptionConstructorTest1() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - ProxyException target = new ProxyException(message); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ProxyException Constructor - /// - [TestMethod] - public void ProxyExceptionConstructorTest2() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - Exception innerException = null; // TODO: Initialize to an appropriate value - ProxyException target = new ProxyException(message, innerException); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/ScpDownloadEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ScpDownloadEventArgsTest.cs deleted file mode 100644 index bfb16348f..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/ScpDownloadEventArgsTest.cs +++ /dev/null @@ -1,27 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for ScpDownloadEventArgsTest and is intended - ///to contain all ScpDownloadEventArgsTest Unit Tests - /// - [TestClass] - public class ScpDownloadEventArgsTest : TestBase - { - /// - ///A test for ScpDownloadEventArgs Constructor - /// - [TestMethod] - public void ScpDownloadEventArgsConstructorTest() - { - string filename = string.Empty; // TODO: Initialize to an appropriate value - long size = 0; // TODO: Initialize to an appropriate value - long downloaded = 0; // TODO: Initialize to an appropriate value - ScpDownloadEventArgs target = new ScpDownloadEventArgs(filename, size, downloaded); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/ScpExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ScpExceptionTest.cs deleted file mode 100644 index 328024b00..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/ScpExceptionTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for ScpExceptionTest and is intended - ///to contain all ScpExceptionTest Unit Tests - /// - [TestClass] - public class ScpExceptionTest : TestBase - { - /// - ///A test for ScpException Constructor - /// - [TestMethod] - public void ScpExceptionConstructorTest() - { - ScpException target = new ScpException(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ScpException Constructor - /// - [TestMethod] - public void ScpExceptionConstructorTest1() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - ScpException target = new ScpException(message); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ScpException Constructor - /// - [TestMethod] - public void ScpExceptionConstructorTest2() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - Exception innerException = null; // TODO: Initialize to an appropriate value - ScpException target = new ScpException(message, innerException); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/ScpUploadEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ScpUploadEventArgsTest.cs deleted file mode 100644 index 9c5238b93..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/ScpUploadEventArgsTest.cs +++ /dev/null @@ -1,27 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for ScpUploadEventArgsTest and is intended - ///to contain all ScpUploadEventArgsTest Unit Tests - /// - [TestClass] - public class ScpUploadEventArgsTest : TestBase - { - /// - ///A test for ScpUploadEventArgs Constructor - /// - [TestMethod] - public void ScpUploadEventArgsConstructorTest() - { - string filename = string.Empty; // TODO: Initialize to an appropriate value - long size = 0; // TODO: Initialize to an appropriate value - long uploaded = 0; // TODO: Initialize to an appropriate value - ScpUploadEventArgs target = new ScpUploadEventArgs(filename, size, uploaded); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/SftpPathNotFoundExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SftpPathNotFoundExceptionTest.cs deleted file mode 100644 index 124e0b535..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/SftpPathNotFoundExceptionTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for SftpPathNotFoundExceptionTest and is intended - ///to contain all SftpPathNotFoundExceptionTest Unit Tests - /// - [TestClass] - public class SftpPathNotFoundExceptionTest : TestBase - { - /// - ///A test for SftpPathNotFoundException Constructor - /// - [TestMethod] - public void SftpPathNotFoundExceptionConstructorTest() - { - SftpPathNotFoundException target = new SftpPathNotFoundException(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SftpPathNotFoundException Constructor - /// - [TestMethod] - public void SftpPathNotFoundExceptionConstructorTest1() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - SftpPathNotFoundException target = new SftpPathNotFoundException(message); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SftpPathNotFoundException Constructor - /// - [TestMethod] - public void SftpPathNotFoundExceptionConstructorTest2() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - Exception innerException = null; // TODO: Initialize to an appropriate value - SftpPathNotFoundException target = new SftpPathNotFoundException(message, innerException); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/SftpPermissionDeniedExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SftpPermissionDeniedExceptionTest.cs deleted file mode 100644 index 30800de9a..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/SftpPermissionDeniedExceptionTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for SftpPermissionDeniedExceptionTest and is intended - ///to contain all SftpPermissionDeniedExceptionTest Unit Tests - /// - [TestClass] - public class SftpPermissionDeniedExceptionTest : TestBase - { - /// - ///A test for SftpPermissionDeniedException Constructor - /// - [TestMethod] - public void SftpPermissionDeniedExceptionConstructorTest() - { - SftpPermissionDeniedException target = new SftpPermissionDeniedException(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SftpPermissionDeniedException Constructor - /// - [TestMethod] - public void SftpPermissionDeniedExceptionConstructorTest1() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - SftpPermissionDeniedException target = new SftpPermissionDeniedException(message); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SftpPermissionDeniedException Constructor - /// - [TestMethod] - public void SftpPermissionDeniedExceptionConstructorTest2() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - Exception innerException = null; // TODO: Initialize to an appropriate value - SftpPermissionDeniedException target = new SftpPermissionDeniedException(message, innerException); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/ShellDataEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/ShellDataEventArgsTest.cs deleted file mode 100644 index 482529342..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/ShellDataEventArgsTest.cs +++ /dev/null @@ -1,35 +0,0 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for ShellDataEventArgsTest and is intended - ///to contain all ShellDataEventArgsTest Unit Tests - /// - [TestClass] - public class ShellDataEventArgsTest - { - /// - ///A test for ShellDataEventArgs Constructor - /// - [TestMethod] - public void ShellDataEventArgsConstructorTest() - { - byte[] data = null; // TODO: Initialize to an appropriate value - ShellDataEventArgs target = new ShellDataEventArgs(data); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for ShellDataEventArgs Constructor - /// - [TestMethod] - public void ShellDataEventArgsConstructorTest1() - { - string line = string.Empty; // TODO: Initialize to an appropriate value - ShellDataEventArgs target = new ShellDataEventArgs(line); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/SshAuthenticationExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SshAuthenticationExceptionTest.cs deleted file mode 100644 index 95a889580..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/SshAuthenticationExceptionTest.cs +++ /dev/null @@ -1,47 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for SshAuthenticationExceptionTest and is intended - ///to contain all SshAuthenticationExceptionTest Unit Tests - /// - [TestClass] - public class SshAuthenticationExceptionTest - { - /// - ///A test for SshAuthenticationException Constructor - /// - [TestMethod] - public void SshAuthenticationExceptionConstructorTest() - { - SshAuthenticationException target = new SshAuthenticationException(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshAuthenticationException Constructor - /// - [TestMethod] - public void SshAuthenticationExceptionConstructorTest1() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - SshAuthenticationException target = new SshAuthenticationException(message); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshAuthenticationException Constructor - /// - [TestMethod] - public void SshAuthenticationExceptionConstructorTest2() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - Exception innerException = null; // TODO: Initialize to an appropriate value - SshAuthenticationException target = new SshAuthenticationException(message, innerException); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs deleted file mode 100644 index ccb2a643a..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/SshConnectionExceptionTest.cs +++ /dev/null @@ -1,64 +0,0 @@ -锘縰sing System; - -using Microsoft.VisualStudio.TestTools.UnitTesting; - -using Renci.SshNet.Common; -using Renci.SshNet.Messages.Transport; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for SshConnectionExceptionTest and is intended - ///to contain all SshConnectionExceptionTest Unit Tests - /// - [TestClass] - public class SshConnectionExceptionTest : TestBase - { - /// - ///A test for SshConnectionException Constructor - /// - [TestMethod] - public void SshConnectionExceptionConstructorTest() - { - var target = new SshConnectionException(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshConnectionException Constructor - /// - [TestMethod] - public void SshConnectionExceptionConstructorTest1() - { - var message = string.Empty; // TODO: Initialize to an appropriate value - var target = new SshConnectionException(message); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshConnectionException Constructor - /// - [TestMethod] - public void SshConnectionExceptionConstructorTest2() - { - var message = string.Empty; // TODO: Initialize to an appropriate value - var disconnectReasonCode = new DisconnectReason(); // TODO: Initialize to an appropriate value - var target = new SshConnectionException(message, disconnectReasonCode); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshConnectionException Constructor - /// - [TestMethod] - public void SshConnectionExceptionConstructorTest3() - { - var message = string.Empty; // TODO: Initialize to an appropriate value - var disconnectReasonCode = new DisconnectReason(); // TODO: Initialize to an appropriate value - Exception inner = null; // TODO: Initialize to an appropriate value - var target = new SshConnectionException(message, disconnectReasonCode, inner); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs deleted file mode 100644 index ebf5ca894..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/SshExceptionTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for SshExceptionTest and is intended - ///to contain all SshExceptionTest Unit Tests - /// - [TestClass] - public class SshExceptionTest : TestBase - { - /// - ///A test for SshException Constructor - /// - [TestMethod] - public void SshExceptionConstructorTest() - { - SshException target = new SshException(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshException Constructor - /// - [TestMethod] - public void SshExceptionConstructorTest1() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - SshException target = new SshException(message); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshException Constructor - /// - [TestMethod] - public void SshExceptionConstructorTest2() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - Exception inner = null; // TODO: Initialize to an appropriate value - SshException target = new SshException(message, inner); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/SshOperationTimeoutExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SshOperationTimeoutExceptionTest.cs deleted file mode 100644 index 9a5f06115..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/SshOperationTimeoutExceptionTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for SshOperationTimeoutExceptionTest and is intended - ///to contain all SshOperationTimeoutExceptionTest Unit Tests - /// - [TestClass] - public class SshOperationTimeoutExceptionTest : TestBase - { - /// - ///A test for SshOperationTimeoutException Constructor - /// - [TestMethod] - public void SshOperationTimeoutExceptionConstructorTest() - { - SshOperationTimeoutException target = new SshOperationTimeoutException(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshOperationTimeoutException Constructor - /// - [TestMethod] - public void SshOperationTimeoutExceptionConstructorTest1() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - SshOperationTimeoutException target = new SshOperationTimeoutException(message); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshOperationTimeoutException Constructor - /// - [TestMethod] - public void SshOperationTimeoutExceptionConstructorTest2() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - Exception innerException = null; // TODO: Initialize to an appropriate value - SshOperationTimeoutException target = new SshOperationTimeoutException(message, innerException); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Common/SshPassPhraseNullOrEmptyExceptionTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SshPassPhraseNullOrEmptyExceptionTest.cs deleted file mode 100644 index 8da8ebc4c..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/SshPassPhraseNullOrEmptyExceptionTest.cs +++ /dev/null @@ -1,48 +0,0 @@ -锘縰sing System; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - /// - ///This is a test class for SshPassPhraseNullOrEmptyExceptionTest and is intended - ///to contain all SshPassPhraseNullOrEmptyExceptionTest Unit Tests - /// - [TestClass] - public class SshPassPhraseNullOrEmptyExceptionTest : TestBase - { - /// - ///A test for SshPassPhraseNullOrEmptyException Constructor - /// - [TestMethod] - public void SshPassPhraseNullOrEmptyExceptionConstructorTest() - { - SshPassPhraseNullOrEmptyException target = new SshPassPhraseNullOrEmptyException(); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshPassPhraseNullOrEmptyException Constructor - /// - [TestMethod] - public void SshPassPhraseNullOrEmptyExceptionConstructorTest1() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - SshPassPhraseNullOrEmptyException target = new SshPassPhraseNullOrEmptyException(message); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - - /// - ///A test for SshPassPhraseNullOrEmptyException Constructor - /// - [TestMethod] - public void SshPassPhraseNullOrEmptyExceptionConstructorTest2() - { - string message = string.Empty; // TODO: Initialize to an appropriate value - Exception innerException = null; // TODO: Initialize to an appropriate value - SshPassPhraseNullOrEmptyException target = new SshPassPhraseNullOrEmptyException(message, innerException); - Assert.Inconclusive("TODO: Implement code to verify target"); - } - } -} From 8e2363360d61e8817da7e0256b9c9cca9984afe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Mon, 16 Oct 2023 15:06:18 +0200 Subject: [PATCH 53/96] Update Nugets 10/2023 (#1214) * Update Nugets 10/2023 * Fix --- test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj | 4 ++-- .../Renci.SshNet.IntegrationTests.csproj | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj b/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj index ebad6e9d9..ee97588d6 100644 --- a/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj +++ b/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj @@ -7,7 +7,7 @@ - + @@ -15,6 +15,6 @@ - + diff --git a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj index e59cc1a93..285ed0f39 100644 --- a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj +++ b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj @@ -16,8 +16,7 @@ - - + - false + true preview-All true @@ -34,11 +34,9 @@ Use fixed version of analyzers. --> - + + diff --git a/src/Renci.SshNet/.editorconfig b/src/Renci.SshNet/.editorconfig index 97f5eb12b..c5f4bdf61 100644 --- a/src/Renci.SshNet/.editorconfig +++ b/src/Renci.SshNet/.editorconfig @@ -1,5 +1,38 @@ 锘縖*.cs] +#### Sonar rules #### + +# S1264: A "while" loop should be used instead of a "for" loop +# https://rules.sonarsource.com/csharp/RSPEC-1264 +dotnet_diagnostic.S1264.severity = none + +# S1450: Private fields only used as local variables in methods should become local variables +# https://rules.sonarsource.com/csharp/RSPEC-1450 +# +# TODO: Re-enable when the following issue is resolved: +# https://github.com/SonarSource/sonar-dotnet/issues/8239 +dotnet_diagnostic.S1450.severity = none + +# S2372: Exceptions should not be thrown from property getters +# https://rules.sonarsource.com/csharp/RSPEC-2372/ +dotnet_diagnostic.S2372.severity = none + +# S2583: Conditionally executed code should be reachable +# https://rules.sonarsource.com/csharp/RSPEC-2583/ +# +# TODO: Re-enable when the following issue is resolved: +# https://github.com/SonarSource/sonar-dotnet/issues/8264 +dotnet_diagnostic.S2583.severity = none + +# S2589: Boolean expressions should not be gratuitous +# https://rules.sonarsource.com/csharp/RSPEC-2589/ +# +# TODO: Re-enable when the following issue is resolved: +# https://github.com/SonarSource/sonar-dotnet/issues/8262 +dotnet_diagnostic.S2589.severity = none + +dotnet_diagnostic.S2372.severity = none + #### SYSLIB diagnostics #### # SYSLIB1045: Use 'GeneratedRegexAttribute' to generate the regular expression implementation at compile-time @@ -7,32 +40,114 @@ # TODO: Remove this when https://github.com/sshnet/SSH.NET/issues/1131 is implemented. dotnet_diagnostic.SYSLIB1045.severity = none -### StyleCop Analyzers rules ### +#### StyleCop Analyzers rules #### + +# SA1123: Do not place regions within elements +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1123.md +dotnet_diagnostic.SA1123.severity = none + +# SA1124: Do not use regions +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1124.md +dotnet_diagnostic.SA1124.severity = none # SA1202: Elements must be ordered by access # https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1202.md dotnet_diagnostic.SA1202.severity = none +# SA1204: Static elements must appear before instance elements +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1204.md +dotnet_diagnostic.SA1204.severity = none + +# SA1310: Field names must not contain underscore +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1310.md +#dotnet_diagnostic.SA1310.severity = none + +# SA1312: Variable names should begin with lower-case letter +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1312.md +dotnet_diagnostic.SA1312.severity = none + +# SA1636: File header copyright text should match +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1636.md +dotnet_diagnostic.SA1636.severity = none + +# SA1643: Destructor summary documentation must begin with standard text +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1643.md +dotnet_diagnostic.SA1643.severity = none + #### Meziantou.Analyzer rules #### +# MA0001: StringComparison is missing +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0001.md +dotnet_diagnostic.MA0001.severity = none + +# MA0011: IFormatProvider is missing +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0011.md +# +# TODO: Remove exclusion when issues are fixed +dotnet_diagnostic.MA0011.severity = none + +# MA0015: Specify the parameter name in ArgumentException +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0015.md +# +# TODO: Remove exclusion when issues are fixed +dotnet_diagnostic.MA0015.severity = none + +# MA0050: Validate arguments correctly in iterator methods +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0050.md +# +# TODO: Re-enable when https://github.com/meziantou/Meziantou.Analyzer/issues/617 is fixed +dotnet_diagnostic.MA0050.severity = none + # MA0053: Make class sealed # https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0053.md MA0053.public_class_should_be_sealed = false +# MA0055: Do not use finalizer +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0055.md +# +# TODO: Remove exclusion when issues are fixed +dotnet_diagnostic.MA0055.severity = none + +# MA0110: Use the Regex source generator +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0110.md +dotnet_diagnostic.MA0110.severity = none + #### .NET Compiler Platform analysers rules #### # CA1030: Use events where appropriate # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1030 -dotnet_diagnostic.CA10310.severity = none +dotnet_diagnostic.CA1030.severity = none # CA1031: Do not catch general exception types # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1031 dotnet_diagnostic.CA1031.severity = none +# CA1062: Validate arguments of public methods +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1062 +# +# TODO: Remove exclusion when issues are fixed +dotnet_diagnostic.CA1062.severity = none + +# CA1307: Specify StringComparison for clarity +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1307 +dotnet_diagnostic.CA1307.severity = none + +# CA1716: Identifiers should not match keywords +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1716 +dotnet_diagnostic.CA1716.severity = none + +# CA1822: Mark members as static +# https://learn.microsoft.com/en-US/dotnet/fundamentals/code-analysis/quality-rules/ca1822 +dotnet_code_quality.CA1822.api_surface = private,internal + # CA2213: Disposable fields should be disposed # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2213 dotnet_diagnostic.CA2213.severity = none +# CA3075: Insecure DTD Processing +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca3075 +dotnet_diagnostic.CA3075.severity = none + # IDE0004: Types that own disposable fields should be disposable # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0004 dotnet_diagnostic.IDE0004.severity = none @@ -40,3 +155,7 @@ dotnet_diagnostic.IDE0004.severity = none # IDE0048: Add parentheses for clarity # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0047 dotnet_diagnostic.IDE0048.severity = none + +# IDE0305: Collection initialization can be simplified +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0305 +dotnet_diagnostic.IDE0305.severity = none diff --git a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs index 18275e724..014d70689 100644 --- a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs @@ -22,11 +22,7 @@ public static bool IsEnabled(TraceEventType traceEventType) public static void Log(string text) { Loggging.TraceEvent(TraceEventType.Verbose, -#if NET6_0_OR_GREATER System.Environment.CurrentManagedThreadId, -#else - System.Threading.Thread.CurrentThread.ManagedThreadId, -#endif // NET6_0_OR_GREATER text); } } diff --git a/src/Renci.SshNet/Abstractions/DnsAbstraction.cs b/src/Renci.SshNet/Abstractions/DnsAbstraction.cs index 0a3f98ecc..30a10fe87 100644 --- a/src/Renci.SshNet/Abstractions/DnsAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/DnsAbstraction.cs @@ -25,7 +25,7 @@ internal static class DnsAbstraction /// /// Returns the Internet Protocol (IP) addresses for the specified host. /// - /// The host name or IP address to resolve + /// The host name or IP address to resolve. /// /// An array of type that holds the IP addresses for the host that /// is specified by the parameter. @@ -34,7 +34,7 @@ internal static class DnsAbstraction /// An error is encountered when resolving . public static IPAddress[] GetHostAddresses(string hostNameOrAddress) { - // TODO Eliminate sync variant, and implement timeout + /* TODO Eliminate sync variant, and implement timeout */ #if FEATURE_DNS_SYNC return Dns.GetHostAddresses(hostNameOrAddress); @@ -92,7 +92,7 @@ public static IPAddress[] GetHostAddresses(string hostNameOrAddress) /// /// Returns the Internet Protocol (IP) addresses for the specified host. /// - /// The host name or IP address to resolve + /// The host name or IP address to resolve. /// /// A task with result of an array of type that holds the IP addresses for the host that /// is specified by the parameter. diff --git a/src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs b/src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs index 1140c9a60..d9e15a508 100644 --- a/src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/ReflectionAbstraction.cs @@ -7,7 +7,7 @@ namespace Renci.SshNet.Abstractions internal static class ReflectionAbstraction { public static IEnumerable GetCustomAttributes(this Type type, bool inherit) - where T:Attribute + where T : Attribute { var attributes = type.GetCustomAttributes(typeof(T), inherit); return attributes.Cast(); diff --git a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs index f325fdc30..f8b289168 100644 --- a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs @@ -261,11 +261,6 @@ public static byte[] Read(Socket socket, int size, TimeSpan timeout) return buffer; } - public static Task ReadAsync(Socket socket, byte[] buffer, int offset, int length, CancellationToken cancellationToken) - { - return socket.ReceiveAsync(buffer, offset, length, cancellationToken); - } - /// /// Receives data from a bound into a receive buffer. /// @@ -293,7 +288,7 @@ public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeS var totalBytesRead = 0; var totalBytesToRead = size; - socket.ReceiveTimeout = (int)readTimeout.TotalMilliseconds; + socket.ReceiveTimeout = (int) readTimeout.TotalMilliseconds; do { @@ -330,6 +325,11 @@ public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeS return totalBytesRead; } + public static Task ReadAsync(Socket socket, byte[] buffer, int offset, int length, CancellationToken cancellationToken) + { + return socket.ReceiveAsync(buffer, offset, length, cancellationToken); + } + public static void Send(Socket socket, byte[] data) { Send(socket, data, 0, data.Length); diff --git a/src/Renci.SshNet/Abstractions/SocketExtensions.cs b/src/Renci.SshNet/Abstractions/SocketExtensions.cs index a51d0cb8d..9edfbf94b 100644 --- a/src/Renci.SshNet/Abstractions/SocketExtensions.cs +++ b/src/Renci.SshNet/Abstractions/SocketExtensions.cs @@ -10,24 +10,25 @@ namespace Renci.SshNet.Abstractions // Async helpers based on https://devblogs.microsoft.com/pfxteam/awaiting-socket-operations/ internal static class SocketExtensions { - private sealed class SocketAsyncEventArgsAwaitable : SocketAsyncEventArgs, INotifyCompletion + private sealed class AwaitableSocketAsyncEventArgs : SocketAsyncEventArgs, INotifyCompletion { private static readonly Action SENTINEL = () => { }; private bool _isCancelled; private Action _continuationAction; - public SocketAsyncEventArgsAwaitable() + public AwaitableSocketAsyncEventArgs() { - Completed += delegate { SetCompleted(); }; + Completed += (sender, e) => SetCompleted(); } - public SocketAsyncEventArgsAwaitable ExecuteAsync(Func func) + public AwaitableSocketAsyncEventArgs ExecuteAsync(Func func) { if (!func(this)) { SetCompleted(); } + return this; } @@ -48,7 +49,9 @@ public void SetCancelled() SetCompleted(); } - public SocketAsyncEventArgsAwaitable GetAwaiter() +#pragma warning disable S1144 // Unused private types or members should be removed + public AwaitableSocketAsyncEventArgs GetAwaiter() +#pragma warning restore S1144 // Unused private types or members should be removed { return this; } @@ -64,7 +67,9 @@ void INotifyCompletion.OnCompleted(Action continuation) } } +#pragma warning disable S1144 // Unused private types or members should be removed public void GetResult() +#pragma warning restore S1144 // Unused private types or members should be removed { if (_isCancelled) { @@ -88,11 +93,15 @@ public static async Task ConnectAsync(this Socket socket, IPEndPoint remoteEndpo { cancellationToken.ThrowIfCancellationRequested(); - using (var args = new SocketAsyncEventArgsAwaitable()) + using (var args = new AwaitableSocketAsyncEventArgs()) { args.RemoteEndPoint = remoteEndpoint; - using (cancellationToken.Register(o => ((SocketAsyncEventArgsAwaitable)o).SetCancelled(), args, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(o => ((AwaitableSocketAsyncEventArgs)o).SetCancelled(), args, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(o => ((AwaitableSocketAsyncEventArgs) o).SetCancelled(), args, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { await args.ExecuteAsync(socket.ConnectAsync); } @@ -103,11 +112,15 @@ public static async Task ReceiveAsync(this Socket socket, byte[] buffer, in { cancellationToken.ThrowIfCancellationRequested(); - using (var args = new SocketAsyncEventArgsAwaitable()) + using (var args = new AwaitableSocketAsyncEventArgs()) { args.SetBuffer(buffer, offset, length); - using (cancellationToken.Register(o => ((SocketAsyncEventArgsAwaitable)o).SetCancelled(), args, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(o => ((AwaitableSocketAsyncEventArgs) o).SetCancelled(), args, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(o => ((AwaitableSocketAsyncEventArgs) o).SetCancelled(), args, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { await args.ExecuteAsync(socket.ReceiveAsync); } diff --git a/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs b/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs index 0c9e3b64f..b3fe2bb4f 100644 --- a/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/ThreadAbstraction.cs @@ -1,4 +1,6 @@ 锘縰sing System; +using System.Threading; +using System.Threading.Tasks; namespace Renci.SshNet.Abstractions { @@ -10,18 +12,28 @@ internal static class ThreadAbstraction /// The number of milliseconds for which the thread is suspended. public static void Sleep(int millisecondsTimeout) { - System.Threading.Thread.Sleep(millisecondsTimeout); + Thread.Sleep(millisecondsTimeout); } - public static void ExecuteThreadLongRunning(Action action) + /// + /// Creates and starts a long-running for the specified . + /// + /// The to start. + /// is . + /// + /// A task that represents the execution of the specified . + /// + public static Task ExecuteThreadLongRunning(Action action) { if (action is null) { throw new ArgumentNullException(nameof(action)); } - var taskCreationOptions = System.Threading.Tasks.TaskCreationOptions.LongRunning; - _ = System.Threading.Tasks.Task.Factory.StartNew(action, taskCreationOptions); + return Task.Factory.StartNew(action, + CancellationToken.None, + TaskCreationOptions.LongRunning, + TaskScheduler.Current); } /// @@ -35,7 +47,7 @@ public static void ExecuteThread(Action action) throw new ArgumentNullException(nameof(action)); } - _ = System.Threading.ThreadPool.QueueUserWorkItem(o => action()); + _ = ThreadPool.QueueUserWorkItem(o => action()); } } } diff --git a/src/Renci.SshNet/AuthenticationMethod.cs b/src/Renci.SshNet/AuthenticationMethod.cs index b7ad7b682..16783f1bd 100644 --- a/src/Renci.SshNet/AuthenticationMethod.cs +++ b/src/Renci.SshNet/AuthenticationMethod.cs @@ -13,7 +13,9 @@ public abstract class AuthenticationMethod : IAuthenticationMethod /// /// The name of the authentication method. /// +#pragma warning disable CA2119 // Seal methods that satisfy private interfaces public abstract string Name { get; } +#pragma warning restore CA2119 // Seal methods that satisfy private interfaces /// /// Gets connection username. diff --git a/src/Renci.SshNet/AuthenticationResult.cs b/src/Renci.SshNet/AuthenticationResult.cs index 714149669..9dc54648f 100644 --- a/src/Renci.SshNet/AuthenticationResult.cs +++ b/src/Renci.SshNet/AuthenticationResult.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet { /// - /// Represents possible authentication methods results + /// Represents possible authentication methods results. /// public enum AuthenticationResult { @@ -9,10 +9,12 @@ public enum AuthenticationResult /// Authentication was successful. /// Success, + /// /// Authentication completed with partial success. /// PartialSuccess, + /// /// Authentication failed. /// diff --git a/src/Renci.SshNet/BaseClient.cs b/src/Renci.SshNet/BaseClient.cs index ca91a90f6..ddd434c2e 100644 --- a/src/Renci.SshNet/BaseClient.cs +++ b/src/Renci.SshNet/BaseClient.cs @@ -12,7 +12,7 @@ namespace Renci.SshNet /// /// Serves as base class for client implementations, provides common client functionality. /// - public abstract class BaseClient : IBaseClient, IDisposable + public abstract class BaseClient : IBaseClient { /// /// Holds value indicating whether the connection info is owned by this client. @@ -341,7 +341,9 @@ public void Disconnect() /// intervals. /// /// The method was called after the client was disposed. +#pragma warning disable S1133 // Deprecated code should be removed [Obsolete("Use KeepAliveInterval to send a keep-alive message at regular intervals.")] +#pragma warning restore S1133 // Deprecated code should be removed public void SendKeepAlive() { CheckDisposed(); @@ -393,8 +395,6 @@ private void Session_HostKeyReceived(object sender, HostKeyEventArgs e) /// public void Dispose() { - DiagnosticAbstraction.Log("Disposing client."); - Dispose(disposing: true); GC.SuppressFinalize(this); } @@ -412,14 +412,17 @@ protected virtual void Dispose(bool disposing) if (disposing) { + DiagnosticAbstraction.Log("Disposing client."); + Disconnect(); - if (_ownsConnectionInfo && _connectionInfo != null) + if (_ownsConnectionInfo && _connectionInfo is not null) { if (_connectionInfo is IDisposable connectionInfoDisposable) { connectionInfoDisposable.Dispose(); } + _connectionInfo = null; } @@ -433,10 +436,14 @@ protected virtual void Dispose(bool disposing) /// THe current instance is disposed. protected void CheckDisposed() { +#if NET7_0_OR_GREATER + ObjectDisposedException.ThrowIf(_isDisposed, this); +#else if (_isDisposed) { throw new ObjectDisposedException(GetType().FullName); } +#endif // NET7_0_OR_GREATER } /// diff --git a/src/Renci.SshNet/Channels/Channel.cs b/src/Renci.SshNet/Channels/Channel.cs index f68a39479..580c63e0f 100644 --- a/src/Renci.SshNet/Channels/Channel.cs +++ b/src/Renci.SshNet/Channels/Channel.cs @@ -16,13 +16,14 @@ namespace Renci.SshNet.Channels internal abstract class Channel : IChannel { private readonly object _serverWindowSizeLock = new object(); + private readonly object _messagingLock = new object(); private readonly uint _initialWindowSize; + private readonly ISession _session; private EventWaitHandle _channelClosedWaitHandle = new ManualResetEvent(initialState: false); private EventWaitHandle _channelServerWindowAdjustWaitHandle = new ManualResetEvent(initialState: false); private uint? _remoteWindowSize; private uint? _remoteChannelNumber; private uint? _remotePacketSize; - private readonly ISession _session; private bool _isDisposed; /// @@ -497,7 +498,7 @@ public void SendEof() throw CreateChannelClosedException(); } - lock (this) + lock (_messagingLock) { _session.SendMessage(new ChannelEofMessage(RemoteChannelNumber)); _eofMessageSent = true; @@ -525,7 +526,7 @@ protected virtual void Close() * message causing the server to disconnect the session. */ - lock (this) + lock (_messagingLock) { // Send EOF message first the following conditions are met: // * we have not sent a SSH_MSG_CHANNEL_EOF message @@ -704,7 +705,6 @@ private void OnChannelRequest(object sender, MessageEventArgs - /// Initializes a new instance. + /// Initializes a new instance of the class. /// /// The session. /// The local channel number. @@ -69,17 +69,17 @@ public void Bind(IPEndPoint remoteEndpoint, IForwardedPort forwardedPort) _forwardedPort = forwardedPort; _forwardedPort.Closing += ForwardedPort_Closing; - // Try to connect to the socket + // Try to connect to the socket try { _socket = SocketAbstraction.Connect(remoteEndpoint, ConnectionInfo.Timeout); - // send channel open confirmation message + // Send channel open confirmation message SendMessage(new ChannelOpenConfirmationMessage(RemoteChannelNumber, LocalWindowSize, LocalPacketSize, LocalChannelNumber)); } catch (Exception exp) { - // send channel open failure message + // Send channel open failure message SendMessage(new ChannelOpenFailureMessage(RemoteChannelNumber, exp.ToString(), ChannelOpenFailureMessage.ConnectFailed, "en")); throw; diff --git a/src/Renci.SshNet/Channels/ChannelSession.cs b/src/Renci.SshNet/Channels/ChannelSession.cs index c70e9d317..f222fc647 100644 --- a/src/Renci.SshNet/Channels/ChannelSession.cs +++ b/src/Renci.SshNet/Channels/ChannelSession.cs @@ -394,7 +394,7 @@ protected override void OnFailure() /// private void SendChannelOpenMessage() { - // do not allow open to be ChannelOpenMessage to be sent again until we've + // do not allow the ChannelOpenMessage to be sent again until we've // had a response on the previous attempt for the current channel if (Interlocked.CompareExchange(ref _sessionSemaphoreObtained, 1, 0) == 0) { diff --git a/src/Renci.SshNet/Channels/ChannelTypes.cs b/src/Renci.SshNet/Channels/ChannelTypes.cs index 230420232..cd5e0ed0a 100644 --- a/src/Renci.SshNet/Channels/ChannelTypes.cs +++ b/src/Renci.SshNet/Channels/ChannelTypes.cs @@ -1,5 +1,4 @@ -锘 -namespace Renci.SshNet.Channels +锘縩amespace Renci.SshNet.Channels { /// /// Lists channel types as defined by the protocol. @@ -7,19 +6,22 @@ namespace Renci.SshNet.Channels internal enum ChannelTypes { /// - /// session + /// Session. /// Session, + /// - /// x11 + /// X11. /// X11, + /// - /// forwarded-tcpip + /// Forwarded-tcpip. /// ForwardedTcpip, + /// - /// direct-tcpip + /// Direct-tcpip. /// DirectTcpip } diff --git a/src/Renci.SshNet/Channels/ClientChannel.cs b/src/Renci.SshNet/Channels/ClientChannel.cs index 3a0d05e68..ea4bfe164 100644 --- a/src/Renci.SshNet/Channels/ClientChannel.cs +++ b/src/Renci.SshNet/Channels/ClientChannel.cs @@ -49,7 +49,7 @@ protected virtual void OnOpenConfirmation(uint remoteChannelNumber, uint initial /// /// Send message to open a channel. /// - /// Message to send + /// Message to send. /// The client is not connected. /// The operation timed out. /// The size of the packet exceeds the maximum size defined by the protocol. diff --git a/src/Renci.SshNet/Channels/IChannelSession.cs b/src/Renci.SshNet/Channels/IChannelSession.cs index 4b0bdd202..13c2e2304 100644 --- a/src/Renci.SshNet/Channels/IChannelSession.cs +++ b/src/Renci.SshNet/Channels/IChannelSession.cs @@ -25,8 +25,12 @@ internal interface IChannelSession : IChannel /// /// if request was successful; otherwise . /// - bool SendPseudoTerminalRequest(string environmentVariable, uint columns, uint rows, uint width, uint height, - IDictionary terminalModeValues); + bool SendPseudoTerminalRequest(string environmentVariable, + uint columns, + uint rows, + uint width, + uint height, + IDictionary terminalModeValues); /// /// Sends the X11 forwarding request. diff --git a/src/Renci.SshNet/CipherInfo.cs b/src/Renci.SshNet/CipherInfo.cs index 81e5e0689..2c9832a19 100644 --- a/src/Renci.SshNet/CipherInfo.cs +++ b/src/Renci.SshNet/CipherInfo.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet { /// - /// Holds information about key size and cipher to use + /// Holds information about key size and cipher to use. /// public class CipherInfo { diff --git a/src/Renci.SshNet/ClientAuthentication.cs b/src/Renci.SshNet/ClientAuthentication.cs index 1cdfbecbe..5de87e536 100644 --- a/src/Renci.SshNet/ClientAuthentication.cs +++ b/src/Renci.SshNet/ClientAuthentication.cs @@ -1,9 +1,14 @@ 锘縰sing System; using System.Collections.Generic; +using System.Globalization; + using Renci.SshNet.Common; namespace Renci.SshNet { + /// + /// Represents a mechanism to authenticate a given client. + /// internal sealed class ClientAuthentication : IClientAuthentication { private readonly int _partialSuccessLimit; @@ -37,11 +42,14 @@ internal int PartialSuccessLimit } /// - /// Attempts to authentication for a given using the - /// of the specified . + /// Attempts to perform authentication for a given using the + /// of the specified + /// . /// /// A to use for authenticating. /// The for which to perform authentication. + /// or is . + /// Failed to authenticate the client. public void Authenticate(IConnectionInfoInternal connectionInfo, ISession session) { if (connectionInfo is null) @@ -102,8 +110,14 @@ private bool TryAuthenticate(ISession session, var matchingAuthenticationMethods = authenticationState.GetSupportedAuthenticationMethods(allowedAuthenticationMethods); if (matchingAuthenticationMethods.Count == 0) { - authenticationException = new SshAuthenticationException(string.Format("No suitable authentication method found to complete authentication ({0}).", - string.Join(",", allowedAuthenticationMethods))); + authenticationException = new SshAuthenticationException(string.Format(CultureInfo.InvariantCulture, + "No suitable authentication method found to complete authentication ({0}).", +#if NET || NETSTANDARD2_1_OR_GREATER + string.Join(',', allowedAuthenticationMethods))) +#else + string.Join(",", allowedAuthenticationMethods))) +#endif // NET || NETSTANDARD2_1_OR_GREATER + ; return false; } @@ -113,7 +127,7 @@ private bool TryAuthenticate(ISession session, // methods after a partial success if (authenticationState.GetPartialSuccessCount(authenticationMethod) >= _partialSuccessLimit) { - // TODO Get list of all authentication methods that have reached the partial success limit? + /* TODO Get list of all authentication methods that have reached the partial success limit? */ authenticationException = new SshAuthenticationException(string.Format("Reached authentication attempt limit for method ({0}).", authenticationMethod.Name)); @@ -195,7 +209,7 @@ public void RecordPartialSuccess(IAuthenticationMethod authenticationMethod) { if (_authenticationMethodPartialSuccessRegister.TryGetValue(authenticationMethod, out var partialSuccessCount)) { - _authenticationMethodPartialSuccessRegister[authenticationMethod] = ++partialSuccessCount; + _authenticationMethodPartialSuccessRegister[authenticationMethod] = partialSuccessCount + 1; } else { diff --git a/src/Renci.SshNet/Common/AsyncResult.cs b/src/Renci.SshNet/Common/AsyncResult.cs index 59b71bb48..5f62b1b4a 100644 --- a/src/Renci.SshNet/Common/AsyncResult.cs +++ b/src/Renci.SshNet/Common/AsyncResult.cs @@ -155,50 +155,4 @@ public bool IsCompleted get { return _completedState != StatePending; } } } - - /// - /// Base class to encapsulates the results of an asynchronous operation that returns result. - /// - /// The type of the result. - public abstract class AsyncResult : AsyncResult - { - // Field set when operation completes - private TResult _result; - - /// - /// Initializes a new instance of the class. - /// - /// The async callback. - /// The state. - protected AsyncResult(AsyncCallback asyncCallback, object state) - : base(asyncCallback, state) - { - } - - /// - /// Marks asynchronous operation as completed. - /// - /// The result. - /// if set to [completed synchronously]. - public void SetAsCompleted(TResult result, bool completedSynchronously) - { - // Save the asynchronous operation's result - _result = result; - - // Tell the base class that the operation completed successfully (no exception) - SetAsCompleted(exception: null, completedSynchronously); - } - - /// - /// Waits until the asynchronous operation completes, and then returns the value generated by the asynchronous operation. - /// - /// - /// The invocation result. - /// - public new TResult EndInvoke() - { - base.EndInvoke(); // Wait until operation has completed - return _result; // Return the result (if above didn't throw) - } - } } diff --git a/src/Renci.SshNet/Common/AsyncResult{TResult}.cs b/src/Renci.SshNet/Common/AsyncResult{TResult}.cs new file mode 100644 index 000000000..b5ab54122 --- /dev/null +++ b/src/Renci.SshNet/Common/AsyncResult{TResult}.cs @@ -0,0 +1,50 @@ +锘縰sing System; + +namespace Renci.SshNet.Common +{ + /// + /// Base class to encapsulates the results of an asynchronous operation that returns result. + /// + /// The type of the result. + public abstract class AsyncResult : AsyncResult + { + // Field set when operation completes + private TResult _result; + + /// + /// Initializes a new instance of the class. + /// + /// The async callback. + /// The state. + protected AsyncResult(AsyncCallback asyncCallback, object state) + : base(asyncCallback, state) + { + } + + /// + /// Marks asynchronous operation as completed. + /// + /// The result. + /// if set to [completed synchronously]. + public void SetAsCompleted(TResult result, bool completedSynchronously) + { + // Save the asynchronous operation's result + _result = result; + + // Tell the base class that the operation completed successfully (no exception) + SetAsCompleted(exception: null, completedSynchronously); + } + + /// + /// Waits until the asynchronous operation completes, and then returns the value generated by the asynchronous operation. + /// + /// + /// The invocation result. + /// + public new TResult EndInvoke() + { + base.EndInvoke(); // Wait until operation has completed + return _result; // Return the result (if above didn't throw) + } + } +} diff --git a/src/Renci.SshNet/Common/BigInteger.cs b/src/Renci.SshNet/Common/BigInteger.cs index 862af076a..53a659daf 100644 --- a/src/Renci.SshNet/Common/BigInteger.cs +++ b/src/Renci.SshNet/Common/BigInteger.cs @@ -1,4 +1,6 @@ -锘// +锘#pragma warning disable SA1028 // Code should not contain trailing whitespace +#pragma warning disable SA1515 // Single-line comment should be preceded by blank line +// // System.Numerics.BigInteger // // Authors: @@ -44,6 +46,8 @@ * * * ***************************************************************************/ +#pragma warning restore SA1515 // Single-line comment should be preceded by blank line +#pragma warning restore SA1028 // Code should not contain trailing whitespace using System; using System.Collections.Generic; @@ -106,7 +110,7 @@ public readonly int BitLength var msbBitCount = BitScanBackward(_data[msbIndex]) + 1; - return msbIndex * 4 * 8 + msbBitCount + ((_sign > 0) ? 0 : 1); + return (msbIndex * 4 * 8) + msbBitCount + ((_sign > 0) ? 0 : 1); } } @@ -145,8 +149,8 @@ public static BigInteger ModInverse(BigInteger bi, BigInteger modulus) p1 += (b / a) * p0; b %= a; - } + return 0; } @@ -210,7 +214,9 @@ public BigInteger(int value) else { _sign = -1; +#pragma warning disable SA1021 // Negative signs should be spaced correctly _data = new[] { (uint) -value }; +#pragma warning restore SA1021 // Negative signs should be spaced correctly } } @@ -419,7 +425,9 @@ public BigInteger(byte[] value) _sign = 1; } +#pragma warning disable CA1508 // Avoid dead conditional code | this is the following bug in the analyzer rule: https://github.com/dotnet/roslyn-analyzers/issues/6991 if (_sign == 1) +#pragma warning restore CA1508 // Avoid dead conditional code { while (value[len - 1] == 0) { @@ -514,8 +522,9 @@ public BigInteger(byte[] value) if (borrow != 0) { - // FIXME I believe this can't happen, can someone write a test for it? +#pragma warning disable CA2201 // Do not raise reserved exception types throw new Exception("non zero final carry"); +#pragma warning restore CA2201 // Do not raise reserved exception types } } } @@ -535,14 +544,14 @@ private static ulong Mantissa(byte[] v) var i1 = (uint)v[0] | ((uint)v[1] << 8) | ((uint)v[2] << 16) | ((uint)v[3] << 24); var i2 = (uint)v[4] | ((uint)v[5] << 8) | ((uint)(v[6] & 0xF) << 16); - return ((ulong) i1 | ((ulong) i2 << 32)); + return (ulong) i1 | ((ulong) i2 << 32); } /// /// Gets a value indicating whether the value of the current object is an even number. /// /// - /// if the value of the BigInteger object is an even number; otherwise, . + /// if the value of the object is an even number; otherwise, . /// public readonly bool IsEven { @@ -768,7 +777,9 @@ public static BigInteger Zero /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator int(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (value._data is null) { @@ -813,7 +824,9 @@ public static explicit operator int(BigInteger value) /// An object that contains the value of the parameter. /// [CLSCompliant(false)] +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator uint(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (value._data is null) { @@ -835,7 +848,9 @@ public static explicit operator uint(BigInteger value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator short(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { var val = (int) value; if (val is < short.MinValue or > short.MaxValue) @@ -854,7 +869,9 @@ public static explicit operator short(BigInteger value) /// An object that contains the value of the parameter. /// [CLSCompliant(false)] +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator ushort(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { var val = (uint) value; if (val > ushort.MaxValue) @@ -872,7 +889,9 @@ public static explicit operator ushort(BigInteger value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator byte(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { var val = (uint) value; if (val > byte.MaxValue) @@ -891,7 +910,9 @@ public static explicit operator byte(BigInteger value) /// An object that contains the value of the parameter. /// [CLSCompliant(false)] +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator sbyte(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { var val = (int) value; if (val is < sbyte.MinValue or > sbyte.MaxValue) @@ -909,7 +930,9 @@ public static explicit operator sbyte(BigInteger value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator long(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (value._data is null) { @@ -973,7 +996,9 @@ long.MinValue works fine since it's bigint encoding looks like a negative /// An object that contains the value of the parameter. /// [CLSCompliant(false)] +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator ulong(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (value._data is null) { @@ -1002,7 +1027,9 @@ public static explicit operator ulong(BigInteger value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator double(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (value._data is null) { @@ -1041,7 +1068,9 @@ public static explicit operator double(BigInteger value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator float(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return (float) (double) value; } @@ -1053,7 +1082,9 @@ public static explicit operator float(BigInteger value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator decimal(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (value._data is null) { @@ -1092,7 +1123,9 @@ public static explicit operator decimal(BigInteger value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static implicit operator BigInteger(int value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return new BigInteger(value); } @@ -1105,7 +1138,9 @@ public static implicit operator BigInteger(int value) /// An object that contains the value of the parameter. /// [CLSCompliant(false)] +#pragma warning disable CA2225 // Operator overloads have named alternates public static implicit operator BigInteger(uint value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return new BigInteger(value); } @@ -1117,7 +1152,9 @@ public static implicit operator BigInteger(uint value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static implicit operator BigInteger(short value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return new BigInteger(value); } @@ -1130,7 +1167,9 @@ public static implicit operator BigInteger(short value) /// An object that contains the value of the parameter. /// [CLSCompliant(false)] +#pragma warning disable CA2225 // Operator overloads have named alternates public static implicit operator BigInteger(ushort value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return new BigInteger(value); } @@ -1142,20 +1181,24 @@ public static implicit operator BigInteger(ushort value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static implicit operator BigInteger(byte value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return new BigInteger(value); } /// - /// + /// Defines an implicit conversion of a signed byte to a value. /// /// The value to convert to a . /// /// An object that contains the value of the parameter. /// [CLSCompliant(false)] +#pragma warning disable CA2225 // Operator overloads have named alternates public static implicit operator BigInteger(sbyte value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return new BigInteger(value); } @@ -1167,7 +1210,9 @@ public static implicit operator BigInteger(sbyte value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static implicit operator BigInteger(long value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return new BigInteger(value); } @@ -1180,7 +1225,9 @@ public static implicit operator BigInteger(long value) /// An object that contains the value of the parameter. /// [CLSCompliant(false)] +#pragma warning disable CA2225 // Operator overloads have named alternates public static implicit operator BigInteger(ulong value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return new BigInteger(value); } @@ -1192,7 +1239,9 @@ public static implicit operator BigInteger(ulong value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator BigInteger(double value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return new BigInteger(value); } @@ -1204,7 +1253,9 @@ public static explicit operator BigInteger(double value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator BigInteger(float value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return new BigInteger(value); } @@ -1216,7 +1267,9 @@ public static explicit operator BigInteger(float value) /// /// An object that contains the value of the parameter. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static explicit operator BigInteger(decimal value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return new BigInteger(value); } @@ -1255,7 +1308,7 @@ public static explicit operator BigInteger(decimal value) if (r > 0) { - //left > right + // left > right return new BigInteger(left._sign, CoreSub(left._data, right._data)); } @@ -1279,7 +1332,9 @@ public static explicit operator BigInteger(decimal value) if (left._sign == 0) { +#pragma warning disable SA1021 // Negative signs should be spaced correctly return new BigInteger((short) -right._sign, right._data); +#pragma warning restore SA1021 // Negative signs should be spaced correctly } if (left._sign == right._sign) @@ -1351,7 +1406,7 @@ public static explicit operator BigInteger(decimal value) ulong carry = 0; for (var j = 0; j < b.Length; ++j) { - carry = carry + ((ulong) ai) * b[j] + res[k]; + carry = carry + (((ulong) ai) * b[j]) + res[k]; res[k++] = (uint)carry; carry >>= 32; } @@ -1475,7 +1530,9 @@ public static explicit operator BigInteger(decimal value) return value; } +#pragma warning disable SA1021 // Negative signs should be spaced correctly return new BigInteger((short) -value._sign, value._data); +#pragma warning restore SA1021 // Negative signs should be spaced correctly } /// @@ -1488,7 +1545,9 @@ public static explicit operator BigInteger(decimal value) /// /// The sign of the operand is unchanged. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static BigInteger operator +(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { return value; } @@ -1500,7 +1559,9 @@ public static explicit operator BigInteger(decimal value) /// /// The value of the parameter incremented by 1. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static BigInteger operator ++(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (value._data is null) { @@ -1534,7 +1595,9 @@ public static explicit operator BigInteger(decimal value) /// /// The value of the parameter decremented by 1. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static BigInteger operator --(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (value._data is null) { @@ -1569,7 +1632,9 @@ public static explicit operator BigInteger(decimal value) /// /// The result of the bitwise And operation. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static BigInteger operator &(BigInteger left, BigInteger right) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (left._sign == 0) { @@ -1659,7 +1724,9 @@ public static explicit operator BigInteger(decimal value) /// /// The result of the bitwise Or operation. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static BigInteger operator |(BigInteger left, BigInteger right) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (left._sign == 0) { @@ -1749,7 +1816,9 @@ public static explicit operator BigInteger(decimal value) /// /// The result of the bitwise Or operation. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static BigInteger operator ^(BigInteger left, BigInteger right) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (left._sign == 0) { @@ -1838,7 +1907,9 @@ public static explicit operator BigInteger(decimal value) /// /// The bitwise one's complement of . /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static BigInteger operator ~(BigInteger value) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (value._data is null) { @@ -1895,9 +1966,14 @@ public static explicit operator BigInteger(decimal value) return new BigInteger(negRes ? (short)-1 : (short)1, result); } - //returns the 0-based index of the most significant set bit - //returns 0 if no bit is set, so extra care when using it - static int BitScanBackward(uint word) + /// + /// Returns the zero-based index of the most significant set bit. + /// + /// The value to scan. + /// + /// The zero-based index of the most significant set bit, or zero if no bit is set. + /// + private static int BitScanBackward(uint word) { for (var i = 31; i >= 0; --i) { @@ -1919,7 +1995,9 @@ static int BitScanBackward(uint word) /// /// A value that has been shifted to the left by the specified number of bits. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static BigInteger operator <<(BigInteger value, int shift) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (shift == 0 || value._data is null) { @@ -1976,7 +2054,9 @@ static int BitScanBackward(uint word) /// /// A value that has been shifted to the right by the specified number of bits. /// +#pragma warning disable CA2225 // Operator overloads have named alternates public static BigInteger operator >>(BigInteger value, int shift) +#pragma warning restore CA2225 // Operator overloads have named alternates { if (shift == 0 || value._sign == 0) { @@ -2092,7 +2172,6 @@ static int BitScanBackward(uint word) return left.CompareTo(right) < 0; } - /// /// Returns a value that indicates whether a 64-bit signed integer is less than a value. /// @@ -2672,7 +2751,11 @@ private readonly string ToStringWithPadding(string format, uint radix, IFormatPr return additional + baseStr; } +#if NET + return string.Concat("-", additional, baseStr.AsSpan(1)); +#else return "-" + additional + baseStr.Substring(1); +#endif // NET } return baseStr; @@ -2689,9 +2772,9 @@ private static uint[] MakeTwoComplement(uint[] v) for (var i = 0; i < v.Length; ++i) { var word = v[i]; - carry = (ulong)~word + carry; - word = (uint)carry; - carry = (uint)(carry >> 32); + carry = (ulong) ~word + carry; + word = (uint) carry; + carry = (uint) (carry >> 32); res[i] = word; } @@ -2713,7 +2796,7 @@ private readonly string ToString(uint radix, IFormatProvider provider) if (characterSet.Length < radix) { - throw new ArgumentException("charSet length less than radix", "characterSet"); + throw new ArgumentException("charSet length less than radix", nameof(radix)); } if (radix == 1) @@ -2731,7 +2814,7 @@ private readonly string ToString(uint radix, IFormatProvider provider) return _sign == 1 ? "1" : "-1"; } - var digits = new List(1 + _data.Length * 3 / 10); + var digits = new List(1 + ((_data.Length * 3) / 10)); BigInteger a; if (_sign == 1) @@ -2910,7 +2993,9 @@ public static bool TryParse(string value, NumberStyles style, IFormatProvider pr return true; } +#pragma warning disable S4136 // Method overloads should be grouped together private static bool Parse(string value, NumberStyles style, IFormatProvider fp, bool tryParse, out BigInteger result, out Exception exc) +#pragma warning restore S4136 // Method overloads should be grouped together { result = Zero; exc = null; @@ -2949,16 +3034,16 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, return false; } - var allowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) != 0; - var allowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) != 0; - var allowThousands = (style & NumberStyles.AllowThousands) != 0; - var allowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) != 0; - var allowParentheses = (style & NumberStyles.AllowParentheses) != 0; - var allowTrailingSign = (style & NumberStyles.AllowTrailingSign) != 0; - var allowLeadingSign = (style & NumberStyles.AllowLeadingSign) != 0; - var allowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) != 0; - var allowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) != 0; - var allowExponent = (style & NumberStyles.AllowExponent) != 0; + var allowCurrencySymbol = (style & NumberStyles.AllowCurrencySymbol) == NumberStyles.AllowCurrencySymbol; + var allowHexSpecifier = (style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier; + var allowThousands = (style & NumberStyles.AllowThousands) == NumberStyles.AllowThousands; + var allowDecimalPoint = (style & NumberStyles.AllowDecimalPoint) == NumberStyles.AllowDecimalPoint; + var allowParentheses = (style & NumberStyles.AllowParentheses) == NumberStyles.AllowParentheses; + var allowTrailingSign = (style & NumberStyles.AllowTrailingSign) == NumberStyles.AllowTrailingSign; + var allowLeadingSign = (style & NumberStyles.AllowLeadingSign) == NumberStyles.AllowLeadingSign; + var allowTrailingWhite = (style & NumberStyles.AllowTrailingWhite) == NumberStyles.AllowTrailingWhite; + var allowLeadingWhite = (style & NumberStyles.AllowLeadingWhite) == NumberStyles.AllowLeadingWhite; + var allowExponent = (style & NumberStyles.AllowExponent) == NumberStyles.AllowExponent; var pos = 0; @@ -3223,7 +3308,11 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, { if (!tryParse) { - exc = new OverflowException("Value too large or too small. exp=" + exponent + " rem = " + remainder + " pow = " + Pow(10, -exponent)); + exc = new OverflowException(string.Format(CultureInfo.InvariantCulture, + "Value too large or too small. exp= {0} rem = {1} pow = {2}", + exponent, + remainder, + Pow(10, -exponent))); } return false; @@ -3252,20 +3341,20 @@ private static bool Parse(string value, NumberStyles style, IFormatProvider fp, private static bool CheckStyle(NumberStyles style, bool tryParse, ref Exception exc) { - if ((style & NumberStyles.AllowHexSpecifier) != 0) + if ((style & NumberStyles.AllowHexSpecifier) == NumberStyles.AllowHexSpecifier) { var ne = style ^ NumberStyles.AllowHexSpecifier; - if ((ne & NumberStyles.AllowLeadingWhite) != 0) + if ((ne & NumberStyles.AllowLeadingWhite) == NumberStyles.AllowLeadingWhite) { ne ^= NumberStyles.AllowLeadingWhite; } - if ((ne & NumberStyles.AllowTrailingWhite) != 0) + if ((ne & NumberStyles.AllowTrailingWhite) == NumberStyles.AllowTrailingWhite) { ne ^= NumberStyles.AllowTrailingWhite; } - if (ne != 0) + if (ne != NumberStyles.None) { if (!tryParse) { @@ -3424,7 +3513,7 @@ private static bool ValidDigit(char e, bool allowHex) return char.IsDigit(e); } - private static Exception GetFormatException() + private static FormatException GetFormatException() { return new FormatException("Input string was not in the correct format"); } @@ -3545,7 +3634,9 @@ private static bool Parse(string value, bool tryParse, out BigInteger result, ou { result = val; } +#pragma warning disable CA1508 // Avoid dead conditional code | this is the following bug in the analyzer rule: https://github.com/dotnet/roslyn-analyzers/issues/6991 else if (sign == -1) +#pragma warning restore CA1508 // Avoid dead conditional code { result = new BigInteger(-1, val._data); } @@ -3836,7 +3927,6 @@ public static BigInteger GreatestCommonDivisor(BigInteger left, BigInteger right g = x; x = y % x; y = g; - } if (x.IsZero) @@ -3926,7 +4016,7 @@ public static double Log(BigInteger value, double baseValue) { if ((value._data[length] & (1 << curBit)) != 0) { - bitCount = curBit + length * 32; + bitCount = curBit + (length * 32); break; } } @@ -4472,7 +4562,7 @@ public readonly byte[] ToByteArray() if (carry == 0) { var ex = FirstNonFfByte(word); - var needExtra = (word & (1 << (ex * 8 - 1))) == 0; + var needExtra = (word & (1 << ((ex * 8) - 1))) == 0; var to = ex + (needExtra ? 1 : 0); if (to != extra) @@ -4488,7 +4578,9 @@ public readonly byte[] ToByteArray() if (needExtra) { +#pragma warning disable S1854 // Unused assignments should be removed res[j++] = 0xFF; +#pragma warning restore S1854 // Unused assignments should be removed } } else @@ -4498,7 +4590,9 @@ public readonly byte[] ToByteArray() res[j++] = (byte)(word >> 8); res[j++] = (byte)(word >> 16); res[j++] = (byte)(word >> 24); +#pragma warning disable S1854 // Unused assignments should be removed res[j++] = 0xFF; +#pragma warning restore S1854 // Unused assignments should be removed } } @@ -4807,14 +4901,14 @@ private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] { int i; - var rr = Base * un[j + n] + un[j + n - 1]; + var rr = (Base * un[j + n]) + un[j + n - 1]; var qq = rr / vn[n - 1]; rr -= qq * vn[n - 1]; - for (;;) + for (; ; ) { // Estimate too big ? - if ((qq >= Base) || (qq * vn[n - 2] > (rr * Base + un[j + n - 2]))) + if ((qq >= Base) || (qq * vn[n - 2] > ((rr * Base) + un[j + n - 2]))) { qq--; rr += (ulong)vn[n - 1]; @@ -4827,7 +4921,6 @@ private static void DivModUnsigned(uint[] u, uint[] v, out uint[] q, out uint[] break; } - // Multiply and subtract long b = 0; long t; diff --git a/src/Renci.SshNet/Common/ChannelDataEventArgs.cs b/src/Renci.SshNet/Common/ChannelDataEventArgs.cs index 4891fe240..dbc20b5be 100644 --- a/src/Renci.SshNet/Common/ChannelDataEventArgs.cs +++ b/src/Renci.SshNet/Common/ChannelDataEventArgs.cs @@ -1,4 +1,6 @@ -锘縩amespace Renci.SshNet.Common +锘縰sing System; + +namespace Renci.SshNet.Common { /// /// Provides data for event. @@ -10,9 +12,15 @@ internal class ChannelDataEventArgs : ChannelEventArgs /// /// Channel number. /// Channel data. + /// is . public ChannelDataEventArgs(uint channelNumber, byte[] data) : base(channelNumber) { + if (data is null) + { + throw new ArgumentNullException(nameof(data)); + } + Data = data; } diff --git a/src/Renci.SshNet/Common/ChannelRequestEventArgs.cs b/src/Renci.SshNet/Common/ChannelRequestEventArgs.cs index 7747b7621..95548194d 100644 --- a/src/Renci.SshNet/Common/ChannelRequestEventArgs.cs +++ b/src/Renci.SshNet/Common/ChannelRequestEventArgs.cs @@ -13,8 +13,14 @@ internal sealed class ChannelRequestEventArgs : EventArgs /// Initializes a new instance of the class. /// /// Request information. + /// is . public ChannelRequestEventArgs(RequestInfo info) { + if (info is null) + { + throw new ArgumentNullException(nameof(info)); + } + Info = info; } diff --git a/src/Renci.SshNet/Common/DerData.cs b/src/Renci.SshNet/Common/DerData.cs index 29361ace5..ba0a678dd 100644 --- a/src/Renci.SshNet/Common/DerData.cs +++ b/src/Renci.SshNet/Common/DerData.cs @@ -48,7 +48,7 @@ public DerData() /// Initializes a new instance of the class. /// /// DER encoded data. - /// its a construct + /// its a construct. public DerData(byte[] data, bool construct = false) { _data = new List(data); diff --git a/src/Renci.SshNet/Common/Extensions.cs b/src/Renci.SshNet/Common/Extensions.cs index 03f05be87..f364dc9f4 100644 --- a/src/Renci.SshNet/Common/Extensions.cs +++ b/src/Renci.SshNet/Common/Extensions.cs @@ -50,7 +50,7 @@ internal static BigInteger ToBigInteger(this byte[] data) } /// - /// Initializes a new instance of the structure using the SSH BigNum2 Format + /// Initializes a new instance of the structure using the SSH BigNum2 Format. /// public static BigInteger ToBigInteger2(this byte[] data) { @@ -60,6 +60,7 @@ public static BigInteger ToBigInteger2(this byte[] data) Buffer.BlockCopy(data, 0, buf, 1, data.Length); data = buf; } + return data.ToBigInteger(); } diff --git a/src/Renci.SshNet/Common/HostKeyEventArgs.cs b/src/Renci.SshNet/Common/HostKeyEventArgs.cs index 79e6aac8c..acd38965a 100644 --- a/src/Renci.SshNet/Common/HostKeyEventArgs.cs +++ b/src/Renci.SshNet/Common/HostKeyEventArgs.cs @@ -30,7 +30,7 @@ public class HostKeyEventArgs : EventArgs /// /// Gets the host key name. /// - public string HostKeyName{ get; private set; } + public string HostKeyName { get; private set; } /// /// Gets the MD5 fingerprint. @@ -50,7 +50,7 @@ public byte[] FingerPrint /// Gets the SHA256 fingerprint of the host key in the same format as the ssh command, /// i.e. non-padded base64, but without the SHA256: prefix. /// - /// ohD8VZEXGWo6Ez8GSEJQ9WpafgLFsOfLOtGGQCQo6Og + /// ohD8VZEXGWo6Ez8GSEJQ9WpafgLFsOfLOtGGQCQo6Og. /// /// Base64 encoded SHA256 fingerprint with padding (equals sign) removed. /// @@ -66,7 +66,7 @@ public string FingerPrintSHA256 /// Gets the MD5 fingerprint of the host key in the same format as the ssh command, /// i.e. hexadecimal bytes separated by colons, but without the MD5: prefix. /// - /// 97:70:33:82:fd:29:3a:73:39:af:6a:07:ad:f8:80:49 + /// 97:70:33:82:fd:29:3a:73:39:af:6a:07:ad:f8:80:49. public string FingerPrintMD5 { get @@ -87,27 +87,43 @@ public string FingerPrintMD5 /// Initializes a new instance of the class. /// /// The host. + /// is . public HostKeyEventArgs(KeyHostAlgorithm host) { + if (host is null) + { + throw new ArgumentNullException(nameof(host)); + } + CanTrust = true; HostKey = host.Data; HostKeyName = host.Name; KeyLength = host.Key.KeyLength; - + _lazyFingerPrint = new Lazy(() => - { - using var md5 = CryptoAbstraction.CreateMD5(); - return md5.ComputeHash(HostKey); - }); + { + using var md5 = CryptoAbstraction.CreateMD5(); + return md5.ComputeHash(HostKey); + }); _lazyFingerPrintSHA256 = new Lazy(() => - { - using var sha256 = CryptoAbstraction.CreateSHA256(); - return Convert.ToBase64String(sha256.ComputeHash(HostKey)).Replace("=", ""); - }); + { + using var sha256 = CryptoAbstraction.CreateSHA256(); + + return Convert.ToBase64String(sha256.ComputeHash(HostKey)) +#if NET || NETSTANDARD2_1_OR_GREATER + .Replace("=", string.Empty, StringComparison.Ordinal); +#else + .Replace("=", string.Empty); +#endif // NET || NETSTANDARD2_1_OR_GREATER + }); - _lazyFingerPrintMD5 = new Lazy(() => - BitConverter.ToString(FingerPrint).Replace("-", ":").ToLowerInvariant()); + _lazyFingerPrintMD5 = new Lazy(() => + { +#pragma warning disable CA1308 // Normalize strings to uppercase + return BitConverter.ToString(FingerPrint).Replace('-', ':').ToLowerInvariant(); +#pragma warning restore CA1308 // Normalize strings to uppercase + }); } } } diff --git a/src/Renci.SshNet/Common/NetConfServerException.cs b/src/Renci.SshNet/Common/NetConfServerException.cs index 0d807f0c7..e8614bcb3 100644 --- a/src/Renci.SshNet/Common/NetConfServerException.cs +++ b/src/Renci.SshNet/Common/NetConfServerException.cs @@ -41,7 +41,7 @@ public NetConfServerException(string message, Exception innerException) #if FEATURE_BINARY_SERIALIZATION /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The that holds the serialized object data about the exception being thrown. /// The that contains contextual information about the source or destination. diff --git a/src/Renci.SshNet/Common/ObjectIdentifier.cs b/src/Renci.SshNet/Common/ObjectIdentifier.cs index a02a40908..5aa310a54 100644 --- a/src/Renci.SshNet/Common/ObjectIdentifier.cs +++ b/src/Renci.SshNet/Common/ObjectIdentifier.cs @@ -7,7 +7,9 @@ namespace Renci.SshNet.Common /// /// Describes object identifier for DER encoding. /// +#pragma warning disable CA1815 // Override equals and operator equals on value types public struct ObjectIdentifier +#pragma warning restore CA1815 // Override equals and operator equals on value types { /// /// Gets the object identifier. diff --git a/src/Renci.SshNet/Common/PipeStream.cs b/src/Renci.SshNet/Common/PipeStream.cs index 887766f3b..da7b89cba 100644 --- a/src/Renci.SshNet/Common/PipeStream.cs +++ b/src/Renci.SshNet/Common/PipeStream.cs @@ -10,8 +10,6 @@ namespace Renci.SshNet.Common /// PipeStream is a thread-safe read/write data stream for use between two threads in a /// single-producer/single-consumer type problem. /// - /// 2006/10/13 1.0 - /// Update on 2008/10/9 1.1 - uses Monitor instead of Manual Reset events for more elegant synchronicity. /// /// Copyright (c) 2006 James Kolpack (james dot kolpack at google mail) /// @@ -46,11 +44,6 @@ public class PipeStream : Stream /// private bool _isFlushed; - /// - /// Maximum number of bytes to store in the buffer. - /// - private long _maxBufferLength = 200 * 1024 * 1024; - /// /// Setting this to true will cause Read() to block if it appears /// that it will run out of data. @@ -66,11 +59,7 @@ public class PipeStream : Stream /// Gets or sets the maximum number of bytes to store in the buffer. /// /// The length of the max buffer. - public long MaxBufferLength - { - get { return _maxBufferLength; } - set { _maxBufferLength = value; } - } + public long MaxBufferLength { get; set; } = 200 * 1024 * 1024; /// /// Gets or sets a value indicating whether to block last read method before the buffer is empty. @@ -88,19 +77,27 @@ public bool BlockLastReadBuffer { get { +#if NET7_0_OR_GREATER + ObjectDisposedException.ThrowIf(_isDisposed, this); +#else if (_isDisposed) { throw CreateObjectDisposedException(); } +#endif // NET7_0_OR_GREATER return _canBlockLastRead; } set { +#if NET7_0_OR_GREATER + ObjectDisposedException.ThrowIf(_isDisposed, this); +#else if (_isDisposed) { throw CreateObjectDisposedException(); } +#endif // NET7_0_OR_GREATER _canBlockLastRead = value; @@ -126,10 +123,14 @@ public bool BlockLastReadBuffer /// public override void Flush() { +#if NET7_0_OR_GREATER + ObjectDisposedException.ThrowIf(_isDisposed, this); +#else if (_isDisposed) { throw CreateObjectDisposedException(); } +#endif // NET7_0_OR_GREATER _isFlushed = true; lock (_buffer) @@ -200,15 +201,19 @@ public override int Read(byte[] buffer, int offset, int count) throw new ArgumentOutOfRangeException(nameof(offset), "offset or count is negative."); } - if (BlockLastReadBuffer && count >= _maxBufferLength) + if (BlockLastReadBuffer && count >= MaxBufferLength) { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "count({0}) > mMaxBufferLength({1})", count, _maxBufferLength)); + throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "count({0}) > mMaxBufferLength({1})", count, MaxBufferLength)); } +#if NET7_0_OR_GREATER + ObjectDisposedException.ThrowIf(_isDisposed, this); +#else if (_isDisposed) { throw CreateObjectDisposedException(); } +#endif // NET7_0_OR_GREATER if (count == 0) { @@ -284,10 +289,14 @@ public override void Write(byte[] buffer, int offset, int count) throw new ArgumentOutOfRangeException(nameof(offset), "offset or count is negative."); } +#if NET7_0_OR_GREATER + ObjectDisposedException.ThrowIf(_isDisposed, this); +#else if (_isDisposed) { throw CreateObjectDisposedException(); } +#endif // NET7_0_OR_GREATER if (count == 0) { @@ -297,7 +306,7 @@ public override void Write(byte[] buffer, int offset, int count) lock (_buffer) { // wait until the buffer isn't full - while (Length >= _maxBufferLength) + while (Length >= MaxBufferLength) { _ = Monitor.Wait(_buffer); } @@ -380,10 +389,14 @@ public override long Length { get { +#if NET7_0_OR_GREATER + ObjectDisposedException.ThrowIf(_isDisposed, this); +#else if (_isDisposed) { throw CreateObjectDisposedException(); } +#endif // NET7_0_OR_GREATER return _buffer.Count; } @@ -402,9 +415,11 @@ public override long Position set { throw new NotSupportedException(); } } +#if !NET7_0_OR_GREATER private ObjectDisposedException CreateObjectDisposedException() { return new ObjectDisposedException(GetType().FullName); } +#endif // !NET7_0_OR_GREATER } } diff --git a/src/Renci.SshNet/Common/SemaphoreLight.cs b/src/Renci.SshNet/Common/SemaphoreLight.cs index d506d44e0..106b10180 100644 --- a/src/Renci.SshNet/Common/SemaphoreLight.cs +++ b/src/Renci.SshNet/Common/SemaphoreLight.cs @@ -6,7 +6,7 @@ namespace Renci.SshNet.Common /// /// Light implementation of SemaphoreSlim. /// - public class SemaphoreLight : IDisposable + public sealed class SemaphoreLight : IDisposable { private readonly object _lock = new object(); private ManualResetEvent _waitHandle; @@ -228,7 +228,7 @@ public void Dispose() /// Releases unmanaged and - optionally - managed resources. /// /// to release both managed and unmanaged resources; to release only unmanaged resources. - protected void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing) { diff --git a/src/Renci.SshNet/Common/SshConnectionException.cs b/src/Renci.SshNet/Common/SshConnectionException.cs index 75c7227a1..a5c227b8e 100644 --- a/src/Renci.SshNet/Common/SshConnectionException.cs +++ b/src/Renci.SshNet/Common/SshConnectionException.cs @@ -47,6 +47,17 @@ public SshConnectionException(string message, DisconnectReason disconnectReasonC DisconnectReason = disconnectReasonCode; } + /// + /// Initializes a new instance of the class. + /// + /// The message. + /// The inner. + public SshConnectionException(string message, Exception inner) + : base(message, inner) + { + DisconnectReason = DisconnectReason.None; + } + /// /// Initializes a new instance of the class. /// diff --git a/src/Renci.SshNet/Common/SshData.cs b/src/Renci.SshNet/Common/SshData.cs index 5dd9fa9ea..9cbf4fd95 100644 --- a/src/Renci.SshNet/Common/SshData.cs +++ b/src/Renci.SshNet/Common/SshData.cs @@ -7,7 +7,9 @@ namespace Renci.SshNet.Common /// /// Base ssh data serialization type. /// +#pragma warning disable CA1001 // Types that own disposable fields should be disposable public abstract class SshData +#pragma warning restore CA1001 // Types that own disposable fields should be disposable { internal const int DefaultCapacity = 64; @@ -63,9 +65,12 @@ public byte[] GetBytes() { var messageLength = BufferCapacity; var capacity = messageLength != -1 ? messageLength : DefaultCapacity; - var dataStream = new SshDataStream(capacity); - WriteBytes(dataStream); - return dataStream.ToArray(); + + using (var dataStream = new SshDataStream(capacity)) + { + WriteBytes(dataStream); + return dataStream.ToArray(); + } } /// @@ -129,7 +134,9 @@ private void LoadInternal(byte[] value, int offset, int count) /// /// Reads all data left in internal buffer at current position. /// - /// An array of bytes containing the remaining data in the internal buffer. + /// + /// An array of bytes containing the remaining data in the internal buffer. + /// protected byte[] ReadBytes() { var bytesLength = (int) (_stream.Length - _stream.Position); @@ -142,16 +149,12 @@ protected byte[] ReadBytes() /// Reads next specified number of bytes data type from internal buffer. /// /// Number of bytes to read. - /// An array of bytes that was read from the internal buffer. - /// is greater than the internal buffer size. + /// + /// An array of bytes that was read from the internal buffer. + /// + /// is greater than the number of bytes available to be read. protected byte[] ReadBytes(int length) { - /* - * Note that this also prevents allocating non-relevant lengths, such as if length is greater than _data.Count but less than int.MaxValue. - * For the nerds, the condition translates to: if (length > data.Count && length < int.MaxValue) - * Which probably would cause all sorts of exception, most notably OutOfMemoryException. - */ - var data = new byte[length]; var bytesRead = _stream.Read(data, 0, length); @@ -166,7 +169,10 @@ protected byte[] ReadBytes(int length) /// /// Reads next byte data type from internal buffer. /// - /// Byte read. + /// + /// The read. + /// + /// Attempt to read past the end of the stream. protected byte ReadByte() { var byteRead = _stream.ReadByte(); @@ -184,6 +190,7 @@ protected byte ReadByte() /// /// The that was read. /// + /// Attempt to read past the end of the stream. protected bool ReadBoolean() { return ReadByte() != 0; @@ -195,6 +202,7 @@ protected bool ReadBoolean() /// /// The that was read. /// + /// Attempt to read past the end of the stream. protected ushort ReadUInt16() { return Pack.BigEndianToUInt16(ReadBytes(2)); @@ -206,6 +214,7 @@ protected ushort ReadUInt16() /// /// The that was read. /// + /// Attempt to read past the end of the stream. protected uint ReadUInt32() { return Pack.BigEndianToUInt32(ReadBytes(4)); @@ -217,6 +226,7 @@ protected uint ReadUInt32() /// /// The that was read. /// + /// Attempt to read past the end of the stream. protected ulong ReadUInt64() { return Pack.BigEndianToUInt64(ReadBytes(8)); @@ -260,8 +270,10 @@ protected string[] ReadNamesList() /// /// Reads next extension-pair data type from internal buffer. /// - /// Extensions pair dictionary. - protected IDictionary ReadExtensionPair() + /// + /// Extensions pair dictionary. + /// + protected Dictionary ReadExtensionPair() { var result = new Dictionary(); @@ -373,7 +385,11 @@ protected void Write(BigInteger data) /// name-list data to write. protected void Write(string[] data) { +#if NET || NETSTANDARD2_1_OR_GREATER + Write(string.Join(',', data), Ascii); +#else Write(string.Join(",", data), Ascii); +#endif // NET || NETSTANDARD2_1_OR_GREATER } /// diff --git a/src/Renci.SshNet/Common/SshDataStream.cs b/src/Renci.SshNet/Common/SshDataStream.cs index 3a15d7438..6bad5f21f 100644 --- a/src/Renci.SshNet/Common/SshDataStream.cs +++ b/src/Renci.SshNet/Common/SshDataStream.cs @@ -101,6 +101,24 @@ public void Write(byte[] data) Write(data, 0, data.Length); } + /// + /// Writes string data to the SSH data stream using the specified encoding. + /// + /// The string data to write. + /// The character encoding to use. + /// is . + /// is . + public void Write(string s, Encoding encoding) + { + if (encoding is null) + { + throw new ArgumentNullException(nameof(encoding)); + } + + var bytes = encoding.GetBytes(s); + WriteBinary(bytes, 0, bytes.Length); + } + /// /// Reads a byte array from the SSH data stream. /// @@ -149,24 +167,6 @@ public void WriteBinary(byte[] buffer, int offset, int count) Write(buffer, offset, count); } - /// - /// Writes string data to the SSH data stream using the specified encoding. - /// - /// The string data to write. - /// The character encoding to use. - /// is . - /// is . - public void Write(string s, Encoding encoding) - { - if (encoding is null) - { - throw new ArgumentNullException(nameof(encoding)); - } - - var bytes = encoding.GetBytes(s); - WriteBinary(bytes, 0, bytes.Length); - } - /// /// Reads a from the SSH datastream. /// diff --git a/src/Renci.SshNet/Common/TerminalModes.cs b/src/Renci.SshNet/Common/TerminalModes.cs index 8737872b8..6b813837a 100644 --- a/src/Renci.SshNet/Common/TerminalModes.cs +++ b/src/Renci.SshNet/Common/TerminalModes.cs @@ -1,10 +1,13 @@ 锘縩amespace Renci.SshNet.Common { /// - /// Specifies the initial assignments of the opcode values that are used in the 'encoded terminal modes' valu + /// Specifies the initial assignments of the opcode values that are used in the 'encoded terminal modes' value. /// +#pragma warning disable CA1028 // Enum Storage should be Int32 public enum TerminalModes : byte +#pragma warning restore CA1028 // Enum Storage should be Int32 { +#pragma warning disable CA1707 // Identifiers should not contain underscores /// /// Indicates end of options. /// @@ -289,5 +292,6 @@ public enum TerminalModes : byte /// Specifies the output baud rate in bits per second. /// TTY_OP_OSPEED = 129, +#pragma warning restore CA1707 // Identifiers should not contain underscores } } diff --git a/src/Renci.SshNet/Compression/CompressionMode.cs b/src/Renci.SshNet/Compression/CompressionMode.cs index 1577e0bc8..b0b6f6b94 100644 --- a/src/Renci.SshNet/Compression/CompressionMode.cs +++ b/src/Renci.SshNet/Compression/CompressionMode.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet.Compression { /// - /// Specifies compression modes + /// Specifies compression modes. /// public enum CompressionMode { diff --git a/src/Renci.SshNet/Compression/Compressor.cs b/src/Renci.SshNet/Compression/Compressor.cs index b63a292ed..63eb3e336 100644 --- a/src/Renci.SshNet/Compression/Compressor.cs +++ b/src/Renci.SshNet/Compression/Compressor.cs @@ -6,7 +6,7 @@ namespace Renci.SshNet.Compression { /// - /// Represents base class for compression algorithm implementation + /// Represents base class for compression algorithm implementation. /// public abstract class Compressor : Algorithm, IDisposable { @@ -20,7 +20,7 @@ public abstract class Compressor : Algorithm, IDisposable /// Gets or sets a value indicating whether compression is active. /// /// - /// if compression is active; otherwise, . + /// if compression is active; otherwise, . /// protected bool IsActive { get; set; } @@ -42,7 +42,7 @@ protected Compressor() } /// - /// Initializes the algorithm + /// Initializes the algorithm. /// /// The session. public virtual void Init(Session session) @@ -54,7 +54,9 @@ public virtual void Init(Session session) /// Compresses the specified data. /// /// Data to compress. - /// Compressed data + /// + /// The compressed data. + /// public virtual byte[] Compress(byte[] data) { return Compress(data, 0, data.Length); @@ -142,7 +144,7 @@ public void Dispose() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// to release both managed and unmanaged resources; to release only unmanaged resources. protected virtual void Dispose(bool disposing) diff --git a/src/Renci.SshNet/Compression/Zlib.cs b/src/Renci.SshNet/Compression/Zlib.cs index 0dc5918c4..504697fd7 100644 --- a/src/Renci.SshNet/Compression/Zlib.cs +++ b/src/Renci.SshNet/Compression/Zlib.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet.Compression { /// - /// Represents "zlib" compression implementation + /// Represents "zlib" compression implementation. /// internal sealed class Zlib : Compressor { @@ -14,7 +14,7 @@ public override string Name } /// - /// Initializes the algorithm + /// Initializes the algorithm. /// /// The session. public override void Init(Session session) diff --git a/src/Renci.SshNet/Compression/ZlibOpenSsh.cs b/src/Renci.SshNet/Compression/ZlibOpenSsh.cs index 177d76b49..45bf1165f 100644 --- a/src/Renci.SshNet/Compression/ZlibOpenSsh.cs +++ b/src/Renci.SshNet/Compression/ZlibOpenSsh.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Compression { /// - /// Represents "zlib@openssh.org" compression implementation + /// Represents "zlib@openssh.org" compression implementation. /// public class ZlibOpenSsh : Compressor { @@ -16,7 +16,7 @@ public override string Name } /// - /// Initializes the algorithm + /// Initializes the algorithm. /// /// The session. public override void Init(Session session) @@ -32,4 +32,4 @@ private void Session_UserAuthenticationSuccessReceived(object sender, MessageEve Session.UserAuthenticationSuccessReceived -= Session_UserAuthenticationSuccessReceived; } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Compression/ZlibStream.cs b/src/Renci.SshNet/Compression/ZlibStream.cs index 5c9d3b841..e09244992 100644 --- a/src/Renci.SshNet/Compression/ZlibStream.cs +++ b/src/Renci.SshNet/Compression/ZlibStream.cs @@ -1,11 +1,16 @@ 锘縰sing System.IO; +#pragma warning disable S125 // Sections of code should not be commented out +#pragma warning disable SA1005 // Single line comments should begin with single space + namespace Renci.SshNet.Compression { /// /// Implements Zlib compression algorithm. /// +#pragma warning disable CA1711 // Identifiers should not have incorrect suffix public class ZlibStream +#pragma warning restore CA1711 // Identifiers should not have incorrect suffix { //private readonly Ionic.Zlib.ZlibStream _baseStream; @@ -45,5 +50,9 @@ public void Write(byte[] buffer, int offset, int count) { //this._baseStream.Write(buffer, offset, count); } +#pragma warning restore SA1005 // Single line comments should begin with single space } } + +#pragma warning restore SA1005 // Single line comments should begin with single space +#pragma warning restore S125 // Sections of code should not be commented out diff --git a/src/Renci.SshNet/Connection/IConnector.cs b/src/Renci.SshNet/Connection/IConnector.cs index e49587b74..6ce454eb2 100644 --- a/src/Renci.SshNet/Connection/IConnector.cs +++ b/src/Renci.SshNet/Connection/IConnector.cs @@ -3,10 +3,28 @@ namespace Renci.SshNet.Connection { + /// + /// Represents a means to connect to a SSH endpoint. + /// internal interface IConnector { + /// + /// Connects to a SSH endpoint using the specified . + /// + /// The to use to establish a connection to a SSH endpoint. + /// + /// A connected to the SSH endpoint represented by the specified . + /// Socket Connect(IConnectionInfo connectionInfo); + /// + /// Asynchronously connects to a SSH endpoint using the specified . + /// + /// The to use to establish a connection to a SSH endpoint. + /// The token to monitor for cancellation requests. + /// + /// A connected to the SSH endpoint represented by the specified . + /// System.Threading.Tasks.Task ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken); } } diff --git a/src/Renci.SshNet/Connection/IProtocolVersionExchange.cs b/src/Renci.SshNet/Connection/IProtocolVersionExchange.cs index 252cda986..1cbe3d7f2 100644 --- a/src/Renci.SshNet/Connection/IProtocolVersionExchange.cs +++ b/src/Renci.SshNet/Connection/IProtocolVersionExchange.cs @@ -1,5 +1,7 @@ 锘縰sing System; using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; namespace Renci.SshNet.Connection { @@ -19,6 +21,16 @@ internal interface IProtocolVersionExchange /// SshIdentification Start(string clientVersion, Socket socket, TimeSpan timeout); - System.Threading.Tasks.Task StartAsync(string clientVersion, Socket socket, System.Threading.CancellationToken cancellationToken); + /// + /// Asynchronously performs the SSH protocol version exchange. + /// + /// The identification string of the SSH client. + /// A connected to the server. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the SSH protocol version exchange. The value of its + /// contains the SSH identification of the server. + /// + Task StartAsync(string clientVersion, Socket socket, CancellationToken cancellationToken); } } diff --git a/src/Renci.SshNet/Connection/ISocketFactory.cs b/src/Renci.SshNet/Connection/ISocketFactory.cs index 0d76eeb29..a12233182 100644 --- a/src/Renci.SshNet/Connection/ISocketFactory.cs +++ b/src/Renci.SshNet/Connection/ISocketFactory.cs @@ -2,8 +2,22 @@ namespace Renci.SshNet.Connection { + /// + /// Represents a factory to create instances. + /// internal interface ISocketFactory { + /// + /// Creates a with the specified , + /// and that does not use the + /// Nagle algorithm. + /// + /// The . + /// The . + /// The . + /// + /// The . + /// Socket Create(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType); } } diff --git a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs index fb0203f17..00c5d0573 100644 --- a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs +++ b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs @@ -23,7 +23,7 @@ internal sealed class ProtocolVersionExchange : IProtocolVersionExchange { private const byte Null = 0x00; - private static readonly Regex ServerVersionRe = new Regex("^SSH-(?[^-]+)-(?.+?)([ ](?.+))?$", RegexOptions.Compiled); + private static readonly Regex ServerVersionRe = new Regex("^SSH-(?[^-]+)-(?.+?)([ ](?.+))?$", RegexOptions.Compiled | RegexOptions.ExplicitCapture); /// /// Performs the SSH protocol version exchange. @@ -67,6 +67,16 @@ public SshIdentification Start(string clientVersion, Socket socket, TimeSpan tim } } + /// + /// Asynchronously performs the SSH protocol version exchange. + /// + /// The identification string of the SSH client. + /// A connected to the server. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the SSH protocol version exchange. The value of its + /// contains the SSH identification of the server. + /// public async Task StartAsync(string clientVersion, Socket socket, CancellationToken cancellationToken) { // Immediately send the identification string since the spec states both sides MUST send an identification string diff --git a/src/Renci.SshNet/Connection/ProxyConnector.cs b/src/Renci.SshNet/Connection/ProxyConnector.cs index 089ee562a..d8261e024 100644 --- a/src/Renci.SshNet/Connection/ProxyConnector.cs +++ b/src/Renci.SshNet/Connection/ProxyConnector.cs @@ -5,6 +5,10 @@ namespace Renci.SshNet.Connection { + /// + /// Represents a connector that uses a proxy server to establish a connection to a given SSH + /// endpoint. + /// internal abstract class ProxyConnector : ConnectorBase { protected ProxyConnector(ISocketFactory socketFactory) @@ -15,18 +19,37 @@ protected ProxyConnector(ISocketFactory socketFactory) protected abstract void HandleProxyConnect(IConnectionInfo connectionInfo, Socket socket); // ToDo: Performs async/sync fallback, true async version should be implemented in derived classes - protected virtual Task HandleProxyConnectAsync(IConnectionInfo connectionInfo, Socket socket, CancellationToken cancellationToken) + protected virtual +#if NET || NETSTANDARD2_1_OR_GREATER + async +#endif // NET || NETSTANDARD2_1_OR_GREATER + Task HandleProxyConnectAsync(IConnectionInfo connectionInfo, Socket socket, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - using (cancellationToken.Register(o => ((Socket)o).Dispose(), socket, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(o => ((Socket)o).Dispose(), socket, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(o => ((Socket) o).Dispose(), socket, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { +#pragma warning disable MA0042 // Do not use blocking calls in an async method; false positive caused by https://github.com/meziantou/Meziantou.Analyzer/issues/613 HandleProxyConnect(connectionInfo, socket); +#pragma warning restore MA0042 // Do not use blocking calls in an async method } +#if !NET && !NETSTANDARD2_1_OR_GREATER return Task.CompletedTask; +#endif // !NET && !NETSTANDARD2_1_OR_GREATER } + /// + /// Connects to a SSH endpoint using the specified . + /// + /// The to use to establish a connection to a SSH endpoint. + /// + /// A connected to the SSH endpoint represented by the specified . + /// public override Socket Connect(IConnectionInfo connectionInfo) { var socket = SocketConnect(connectionInfo.ProxyHost, connectionInfo.ProxyPort, connectionInfo.Timeout); @@ -45,6 +68,14 @@ public override Socket Connect(IConnectionInfo connectionInfo) } } + /// + /// Asynchronously connects to a SSH endpoint using the specified . + /// + /// The to use to establish a connection to a SSH endpoint. + /// The token to monitor for cancellation requests. + /// + /// A connected to the SSH endpoint represented by the specified . + /// public override async Task ConnectAsync(IConnectionInfo connectionInfo, CancellationToken cancellationToken) { var socket = await SocketConnectAsync(connectionInfo.ProxyHost, connectionInfo.ProxyPort, cancellationToken).ConfigureAwait(false); diff --git a/src/Renci.SshNet/Connection/SocketFactory.cs b/src/Renci.SshNet/Connection/SocketFactory.cs index d279da288..698634947 100644 --- a/src/Renci.SshNet/Connection/SocketFactory.cs +++ b/src/Renci.SshNet/Connection/SocketFactory.cs @@ -2,11 +2,25 @@ namespace Renci.SshNet.Connection { + /// + /// Represents a factory to create instances. + /// internal sealed class SocketFactory : ISocketFactory { + /// + /// Creates a with the specified , + /// and that does not use the + /// Nagle algorithm. + /// + /// The . + /// The . + /// The . + /// + /// The . + /// public Socket Create(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) { - return new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp) { NoDelay = true }; + return new Socket(addressFamily, socketType, protocolType) { NoDelay = true }; } } } diff --git a/src/Renci.SshNet/Connection/Socks4Connector.cs b/src/Renci.SshNet/Connection/Socks4Connector.cs index 4da6bf773..d679c17a3 100644 --- a/src/Renci.SshNet/Connection/Socks4Connector.cs +++ b/src/Renci.SshNet/Connection/Socks4Connector.cs @@ -62,21 +62,23 @@ private static byte[] CreateSocks4ConnectionRequest(string hostname, ushort port var addressBytes = GetSocks4DestinationAddress(hostname); var proxyUserBytes = GetProxyUserBytes(username); - var connectionRequest = new byte - [ - // SOCKS version number - 1 + - // Command code - 1 + - // Port number - 2 + - // IP address - addressBytes.Length + - // Username - proxyUserBytes.Length + - // Null terminator - 1 - ]; + var connectionRequest = new byte[// SOCKS version number + 1 + + + // Command code + 1 + + + // Port number + 2 + + + // IP address + addressBytes.Length + + + // Username + proxyUserBytes.Length + + + // Null terminator + 1]; var index = 0; diff --git a/src/Renci.SshNet/Connection/Socks5Connector.cs b/src/Renci.SshNet/Connection/Socks5Connector.cs index ef9f9974c..a1ed5f751 100644 --- a/src/Renci.SshNet/Connection/Socks5Connector.cs +++ b/src/Renci.SshNet/Connection/Socks5Connector.cs @@ -30,10 +30,13 @@ protected override void HandleProxyConnect(IConnectionInfo connectionInfo, Socke { // SOCKS version number 0x05, + // Number of supported authentication methods 0x02, + // No authentication 0x00, + // Username/Password authentication 0x02 }; @@ -156,19 +159,20 @@ private static byte[] CreateSocks5UserNameAndPasswordAuthenticationRequest(strin throw new ProxyException("Proxy password is too long."); } - var authenticationRequest = new byte - [ - // Version of the negotiation - 1 + - // Length of the username - 1 + - // Username - username.Length + - // Length of the password - 1 + - // Password - password.Length - ]; + var authenticationRequest = new byte[// Version of the negotiation + 1 + + + // Length of the username + 1 + + + // Username + username.Length + + + // Length of the password + 1 + + + // Password + password.Length]; var index = 0; @@ -195,21 +199,23 @@ private static byte[] CreateSocks5ConnectionRequest(string hostname, ushort port { var addressBytes = GetSocks5DestinationAddress(hostname, out var addressType); - var connectionRequest = new byte - [ - // SOCKS version number - 1 + - // Command code - 1 + - // Reserved - 1 + - // Address type - 1 + - // Address - addressBytes.Length + - // Port number - 2 - ]; + var connectionRequest = new byte[// SOCKS version number + 1 + + + // Command code + 1 + + + // Reserved + 1 + + + // Address type + 1 + + + // Address + addressBytes.Length + + + // Port number + 2]; var index = 0; diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index 1f109c279..02e817b24 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -398,8 +398,10 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy { "ecdsa-sha2-nistp256", data => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(), data) }, { "ecdsa-sha2-nistp384", data => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(), data) }, { "ecdsa-sha2-nistp521", data => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(), data) }, - { "rsa-sha2-512", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-512", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); }}, - { "rsa-sha2-256", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-256", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); }}, +#pragma warning disable SA1107 // Code should not contain multiple statements on one line + { "rsa-sha2-512", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-512", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); } }, + { "rsa-sha2-256", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-256", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); } }, +#pragma warning restore SA1107 // Code should not contain multiple statements on one line { "ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data) }, { "ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(), data) }, }; @@ -470,14 +472,28 @@ void IConnectionInfoInternal.UserAuthenticationBannerReceived(object sender, Mes AuthenticationBanner?.Invoke(this, new AuthenticationBannerEventArgs(Username, e.Message.Message, e.Message.Language)); } + /// + /// Creates a none authentication method. + /// + /// + /// A none authentication method. + /// IAuthenticationMethod IConnectionInfoInternal.CreateNoneAuthenticationMethod() { return new NoneAuthenticationMethod(Username); } + /// + /// Gets the supported authentication methods for this connection. + /// + /// + /// The supported authentication methods for this connection. + /// IList IConnectionInfoInternal.AuthenticationMethods { +#pragma warning disable S2365 // Properties should not make collection or array copies get { return AuthenticationMethods.Cast().ToList(); } +#pragma warning restore S2365 // Properties should not make collection or array copies } } } diff --git a/src/Renci.SshNet/ForwardedPortDynamic.cs b/src/Renci.SshNet/ForwardedPortDynamic.cs index be67f6289..21ab59a20 100644 --- a/src/Renci.SshNet/ForwardedPortDynamic.cs +++ b/src/Renci.SshNet/ForwardedPortDynamic.cs @@ -361,10 +361,12 @@ private bool HandleSocks(IChannelDirectTcpip channel, Socket clientSocket, TimeS Closing -= closeClientSocket; } - void closeClientSocket(object _, EventArgs args) +#pragma warning disable SA1300 // Element should begin with upper-case letter + void closeClientSocket(object sender, EventArgs args) { CloseClientSocket(clientSocket); - }; + } +#pragma warning restore SA1300 // Element should begin with upper-case letter } private static void CloseClientSocket(Socket clientSocket) diff --git a/src/Renci.SshNet/ForwardedPortStatus.cs b/src/Renci.SshNet/ForwardedPortStatus.cs index a8ab2224e..5695e28c7 100644 --- a/src/Renci.SshNet/ForwardedPortStatus.cs +++ b/src/Renci.SshNet/ForwardedPortStatus.cs @@ -34,7 +34,9 @@ public override bool Equals(object obj) return forwardedPortStatus._value == _value; } +#pragma warning disable S3875 // "operator==" should not be overloaded on reference types public static bool operator ==(ForwardedPortStatus left, ForwardedPortStatus right) +#pragma warning restore S3875 // "operator==" should not be overloaded on reference types { // check if lhs is null if (left is null) diff --git a/src/Renci.SshNet/HashInfo.cs b/src/Renci.SshNet/HashInfo.cs index 60829f1ed..cbbbf5fe7 100644 --- a/src/Renci.SshNet/HashInfo.cs +++ b/src/Renci.SshNet/HashInfo.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet { /// - /// Holds information about key size and cipher to use + /// Holds information about key size and cipher to use. /// public class HashInfo { @@ -23,7 +23,7 @@ public class HashInfo public Func HashAlgorithm { get; private set; } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Size of the key. /// The hash algorithm to use for a given key. diff --git a/src/Renci.SshNet/IBaseClient.cs b/src/Renci.SshNet/IBaseClient.cs index ff6d30bd3..add066f73 100644 --- a/src/Renci.SshNet/IBaseClient.cs +++ b/src/Renci.SshNet/IBaseClient.cs @@ -10,7 +10,7 @@ namespace Renci.SshNet /// /// Serves as base class for client implementations, provides common client functionality. /// - public interface IBaseClient + public interface IBaseClient : IDisposable { /// /// Gets the connection info. @@ -87,11 +87,6 @@ public interface IBaseClient /// The method was called after the client was disposed. void Disconnect(); - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - void Dispose(); - /// /// Sends a keep-alive message to the server. /// diff --git a/src/Renci.SshNet/IClientAuthentication.cs b/src/Renci.SshNet/IClientAuthentication.cs index 5dbfccc3e..15124fc79 100644 --- a/src/Renci.SshNet/IClientAuthentication.cs +++ b/src/Renci.SshNet/IClientAuthentication.cs @@ -1,7 +1,23 @@ -锘縩amespace Renci.SshNet +锘縰sing System; + +using Renci.SshNet.Common; + +namespace Renci.SshNet { + /// + /// Represents a mechanism to authenticate a given client. + /// internal interface IClientAuthentication { + /// + /// Attempts to perform authentication for a given using the + /// of the specified + /// . + /// + /// A to use for authenticating. + /// The for which to perform authentication. + /// or is . + /// Failed to Authenticate the client. void Authenticate(IConnectionInfoInternal connectionInfo, ISession session); } } diff --git a/src/Renci.SshNet/IConnectionInfo.cs b/src/Renci.SshNet/IConnectionInfo.cs index 77908d2d7..a0f2898ef 100644 --- a/src/Renci.SshNet/IConnectionInfo.cs +++ b/src/Renci.SshNet/IConnectionInfo.cs @@ -3,39 +3,10 @@ using System.Text; using Renci.SshNet.Common; -using Renci.SshNet.Messages.Authentication; using Renci.SshNet.Messages.Connection; namespace Renci.SshNet { - internal interface IConnectionInfoInternal : IConnectionInfo - { - /// - /// Signals that an authentication banner message was received from the server. - /// - /// The session in which the banner message was received. - /// The banner message. - void UserAuthenticationBannerReceived(object sender, MessageEventArgs e); - - /// - /// Gets the supported authentication methods for this connection. - /// - /// - /// The supported authentication methods for this connection. - /// - IList AuthenticationMethods { get; } - - /// - /// Creates a for the credentials represented - /// by the current . - /// - /// - /// A for the credentials represented by the - /// current . - /// - IAuthenticationMethod CreateNoneAuthenticationMethod(); - } - /// /// Represents remote connection information. /// diff --git a/src/Renci.SshNet/IConnectionInfoInternal.cs b/src/Renci.SshNet/IConnectionInfoInternal.cs new file mode 100644 index 000000000..053e36dda --- /dev/null +++ b/src/Renci.SshNet/IConnectionInfoInternal.cs @@ -0,0 +1,37 @@ +锘縰sing System.Collections.Generic; + +using Renci.SshNet.Messages.Authentication; + +namespace Renci.SshNet +{ + /// + /// Represents remote connection information. + /// + internal interface IConnectionInfoInternal : IConnectionInfo + { + /// + /// Signals that an authentication banner message was received from the server. + /// + /// The session in which the banner message was received. + /// The banner message. + void UserAuthenticationBannerReceived(object sender, MessageEventArgs e); + + /// + /// Gets the supported authentication methods for this connection. + /// + /// + /// The supported authentication methods for this connection. + /// + IList AuthenticationMethods { get; } + + /// + /// Creates a for the credentials represented + /// by the current . + /// + /// + /// A for the credentials represented by the + /// current . + /// + IAuthenticationMethod CreateNoneAuthenticationMethod(); + } +} diff --git a/src/Renci.SshNet/IForwardedPort.cs b/src/Renci.SshNet/IForwardedPort.cs index 173613b38..92e49ee3b 100644 --- a/src/Renci.SshNet/IForwardedPort.cs +++ b/src/Renci.SshNet/IForwardedPort.cs @@ -1,7 +1,5 @@ 锘縰sing System; -using Renci.SshNet.Common; - namespace Renci.SshNet { /// @@ -13,33 +11,5 @@ public interface IForwardedPort : IDisposable /// The event occurs as the forwarded port is being stopped. /// event EventHandler Closing; - - /// - /// Occurs when an exception is thrown. - /// - event EventHandler Exception; - - /// - /// Occurs when a port forwarding request is received. - /// - event EventHandler RequestReceived; - - /// - /// Gets a value indicating whether port forwarding is started. - /// - /// - /// if port forwarding is started; otherwise, . - /// - bool IsStarted { get; } - - /// - /// Starts port forwarding. - /// - void Start(); - - /// - /// Stops port forwarding. - /// - void Stop(); } } diff --git a/src/Renci.SshNet/ISession.cs b/src/Renci.SshNet/ISession.cs index fbac05708..5a035b104 100644 --- a/src/Renci.SshNet/ISession.cs +++ b/src/Renci.SshNet/ISession.cs @@ -17,7 +17,7 @@ namespace Renci.SshNet internal interface ISession : IDisposable { /// - /// Gets or sets the connection info. + /// Gets the connection info. /// /// The connection info. IConnectionInfo ConnectionInfo { get; } @@ -86,6 +86,9 @@ internal interface ISession : IDisposable /// /// Creates a "forwarded-tcpip" SSH channel. /// + /// The number of the remote channel. + /// The window size of the remote channel. + /// The data packet size of the remote channel. /// /// A new "forwarded-tcpip" SSH channel. /// diff --git a/src/Renci.SshNet/ISftpClient.cs b/src/Renci.SshNet/ISftpClient.cs index f9015f5a4..efbce934a 100644 --- a/src/Renci.SshNet/ISftpClient.cs +++ b/src/Renci.SshNet/ISftpClient.cs @@ -13,7 +13,7 @@ namespace Renci.SshNet /// /// Implementation of the SSH File Transfer Protocol (SFTP) over SSH. /// - public interface ISftpClient : IBaseClient, IDisposable + public interface ISftpClient : IBaseClient { /// /// Gets or sets the maximum size of the buffer in bytes. @@ -78,12 +78,12 @@ public interface ISftpClient : IBaseClient, IDisposable /// /// The file to append the lines to. The file is created if it does not already exist. /// The lines to append to the file. - /// is -or- is . + /// is . -or- is . /// Client is not connected. /// The specified path is invalid, or its directory was not found on the remote host. /// The method was called after the client was disposed. /// - /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM) + /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM). /// void AppendAllLines(string path, IEnumerable contents); @@ -239,7 +239,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// /// is . /// is or contains only whitespace. - /// If a problem occurs while copying the file + /// If a problem occurs while copying the file. IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback asyncCallback, object state); /// @@ -568,7 +568,7 @@ public interface ISftpClient : IBaseClient, IDisposable void EndUploadFile(IAsyncResult asyncResult); /// - /// Checks whether file or directory exists; + /// Checks whether file or directory exists. /// /// The path. /// @@ -592,7 +592,9 @@ public interface ISftpClient : IBaseClient, IDisposable /// was not found on the remote host. /// is . /// The method was called after the client was disposed. +#pragma warning disable CA1716 // Identifiers should not match keywords ISftpFile Get(string path); +#pragma warning restore CA1716 // Identifiers should not match keywords /// /// Gets the of the file on the path. @@ -898,31 +900,31 @@ public interface ISftpClient : IBaseClient, IDisposable void RenameFile(string oldPath, string newPath); /// - /// Asynchronously renames remote file from old path to new path. + /// Renames remote file from old path to new path. /// /// Path to the old file location. /// Path to the new file location. - /// The to observe. - /// A that represents the asynchronous rename operation. - /// is . -or- or is . + /// if set to then perform a posix rename. + /// is . -or- or is . /// Client is not connected. /// Permission to rename the file was denied by the remote host. -or- A SSH command was denied by the server. - /// A SSH error where is the message from the remote host. + /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. - Task RenameFileAsync(string oldPath, string newPath, CancellationToken cancellationToken); + void RenameFile(string oldPath, string newPath, bool isPosix); /// - /// Renames remote file from old path to new path. + /// Asynchronously renames remote file from old path to new path. /// /// Path to the old file location. /// Path to the new file location. - /// if set to then perform a posix rename. - /// is . -or- or is . + /// The to observe. + /// A that represents the asynchronous rename operation. + /// is . -or- or is . /// Client is not connected. /// Permission to rename the file was denied by the remote host. -or- A SSH command was denied by the server. - /// A SSH error where is the message from the remote host. + /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. - void RenameFile(string oldPath, string newPath, bool isPosix); + Task RenameFileAsync(string oldPath, string newPath, CancellationToken cancellationToken); /// /// Sets the date and time the specified file was last accessed. @@ -951,7 +953,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// The file for which to set the date and time information. /// A containing the value to set for the last write date and time of path. This value is expressed in UTC time. void SetLastWriteTimeUtc(string path, DateTime lastWriteTimeUtc); - + /// /// Sets the specified of the file on the specified path. /// @@ -986,7 +988,7 @@ public interface ISftpClient : IBaseClient, IDisposable /// is . /// is or contains only whitespace. /// was not found on the remote host. - /// If a problem occurs while copying the file + /// If a problem occurs while copying the file. IEnumerable SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern); /// diff --git a/src/Renci.SshNet/ISubsystemSession.cs b/src/Renci.SshNet/ISubsystemSession.cs index af1ce31e7..f1fe6f914 100644 --- a/src/Renci.SshNet/ISubsystemSession.cs +++ b/src/Renci.SshNet/ISubsystemSession.cs @@ -13,7 +13,7 @@ internal interface ISubsystemSession : IDisposable /// Gets or set the number of seconds to wait for an operation to complete. /// /// - /// The number of seconds to wait for an operation to complete, or -1 to wait indefinitely. + /// The number of seconds to wait for an operation to complete, or -1 to wait indefinitely. /// int OperationTimeout { get; } @@ -41,7 +41,7 @@ internal interface ISubsystemSession : IDisposable /// Waits a specified time for a given to get signaled. /// /// The handle to wait for. - /// The number of millieseconds wait for to get signaled, or -1 to wait indefinitely. + /// The number of millieseconds wait for to get signaled, or -1 to wait indefinitely. /// The connection was closed by the server. /// The channel was closed. /// The handle did not get signaled within the specified timeout. @@ -52,7 +52,7 @@ internal interface ISubsystemSession : IDisposable /// 32-bit signed integer to specify the time interval in milliseconds. /// /// The handle to wait for. - /// To number of milliseconds to wait for to get signaled, or -1 to wait indefinitely. + /// To number of milliseconds to wait for to get signaled, or -1 to wait indefinitely. /// /// if received a signal within the specified timeout; /// otherwise, . @@ -72,7 +72,7 @@ internal interface ISubsystemSession : IDisposable /// /// The first handle to wait for. /// The second handle to wait for. - /// To number of milliseconds to wait for a to get signaled, or -1 to wait indefinitely. + /// To number of milliseconds to wait for a to get signaled, or -1 to wait indefinitely. /// /// 0 if received a signal within the specified timeout and 1 /// if received a signal within the specified timeout, or @@ -98,7 +98,7 @@ internal interface ISubsystemSession : IDisposable /// integer to specify the time interval. /// /// A array - constructed using - containing the objects to wait for. - /// To number of milliseconds to wait for a to get signaled, or -1 to wait indefinitely. + /// To number of milliseconds to wait for a to get signaled, or -1 to wait indefinitely. /// /// The array index of the first non-system object that satisfied the wait. /// diff --git a/src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs b/src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs index 5c14bf80c..2d3825b3f 100644 --- a/src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs +++ b/src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs @@ -134,12 +134,13 @@ public KeyboardInteractiveConnectionInfo(string host, int port, string username, kbdInteractive.AuthenticationPrompt += AuthenticationMethod_AuthenticationPrompt; } } - } private void AuthenticationMethod_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e) { +#pragma warning disable MA0091 // Sender should be 'this' for instance events AuthenticationPrompt?.Invoke(sender, e); +#pragma warning restore MA0091 // Sender should be 'this' for instance events } /// diff --git a/src/Renci.SshNet/Messages/Authentication/FailureMessage.cs b/src/Renci.SshNet/Messages/Authentication/FailureMessage.cs index e3229287e..61379600f 100644 --- a/src/Renci.SshNet/Messages/Authentication/FailureMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/FailureMessage.cs @@ -25,7 +25,7 @@ public class FailureMessage : Message /// Gets a value indicating whether authentication is partially successful. /// /// - /// if partially successful; otherwise, . + /// if partially successful; otherwise, . /// public bool PartialSuccess { get; private set; } @@ -38,7 +38,11 @@ protected override void LoadData() PartialSuccess = ReadBoolean(); if (PartialSuccess) { +#if NET || NETSTANDARD2_1_OR_GREATER + Message = string.Join(',', AllowedAuthentications); +#else Message = string.Join(",", AllowedAuthentications); +#endif // NET || NETSTANDARD2_1_OR_GREATER } } @@ -47,7 +51,9 @@ protected override void LoadData() /// protected override void SaveData() { +#pragma warning disable MA0025 // Implement the functionality instead of throwing NotImplementedException throw new NotImplementedException(); +#pragma warning restore MA0025 // Implement the functionality instead of throwing NotImplementedException } internal override void Process(Session session) diff --git a/src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs b/src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs index 4aa9cda41..9e3227342 100644 --- a/src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs @@ -12,7 +12,7 @@ internal sealed class InformationResponseMessage : Message /// /// Gets authentication responses. /// - public IList Responses { get; private set; } + public List Responses { get; private set; } /// /// Gets the size of the message in bytes. @@ -48,6 +48,7 @@ protected override void LoadData() protected override void SaveData() { Write((uint) Responses.Count); + foreach (var response in Responses) { Write(response); diff --git a/src/Renci.SshNet/Messages/Authentication/RequestMessage.cs b/src/Renci.SshNet/Messages/Authentication/RequestMessage.cs index b535da224..5393df3f7 100644 --- a/src/Renci.SshNet/Messages/Authentication/RequestMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/RequestMessage.cs @@ -108,4 +108,3 @@ internal override void Process(Session session) } } } - diff --git a/src/Renci.SshNet/Messages/Authentication/RequestMessageNone.cs b/src/Renci.SshNet/Messages/Authentication/RequestMessageNone.cs index 1827c3299..1f84f4161 100644 --- a/src/Renci.SshNet/Messages/Authentication/RequestMessageNone.cs +++ b/src/Renci.SshNet/Messages/Authentication/RequestMessageNone.cs @@ -6,7 +6,7 @@ internal sealed class RequestMessageNone : RequestMessage { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Name of the service. /// Authentication username. diff --git a/src/Renci.SshNet/Messages/Connection/ChannelCloseMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelCloseMessage.cs index 09a6ba834..dfb430134 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelCloseMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelCloseMessage.cs @@ -11,7 +11,6 @@ public class ChannelCloseMessage : ChannelMessage /// public ChannelCloseMessage() { - } /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelEofMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelEofMessage.cs index 469b7b60b..0ad028242 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelEofMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelEofMessage.cs @@ -11,7 +11,6 @@ public class ChannelEofMessage : ChannelMessage /// public ChannelEofMessage() { - } /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelFailureMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelFailureMessage.cs index f011f992a..5987534ca 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelFailureMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelFailureMessage.cs @@ -11,7 +11,6 @@ public class ChannelFailureMessage : ChannelMessage /// public ChannelFailureMessage() { - } /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenInfo.cs index c9c334058..5c6e3c406 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenInfo.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Messages.Connection { /// - /// Base class for open channel messages + /// Base class for open channel messages. /// public abstract class ChannelOpenInfo : SshData { diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpen/DirectTcpipChannelInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpen/DirectTcpipChannelInfo.cs index c2ac16c3e..aefb316ad 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpen/DirectTcpipChannelInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpen/DirectTcpipChannelInfo.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Messages.Connection { /// - /// Used to open "direct-tcpip" channel type + /// Used to open "direct-tcpip" channel type. /// internal sealed class DirectTcpipChannelInfo : ChannelOpenInfo { @@ -11,7 +11,7 @@ internal sealed class DirectTcpipChannelInfo : ChannelOpenInfo private byte[] _originatorAddress; /// - /// Specifies channel open type + /// Specifies channel open type. /// public const string NAME = "direct-tcpip"; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfo.cs index b7d1efbf9..f8bb6742d 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpen/ForwardedTcpipChannelInfo.cs @@ -3,10 +3,15 @@ namespace Renci.SshNet.Messages.Connection { /// - /// Used to open "forwarded-tcpip" channel type + /// Used to open "forwarded-tcpip" channel type. /// internal sealed class ForwardedTcpipChannelInfo : ChannelOpenInfo { + /// + /// Specifies channel open type. + /// + public const string NAME = "forwarded-tcpip"; + private byte[] _connectedAddress; private byte[] _originatorAddress; @@ -21,8 +26,8 @@ public ForwardedTcpipChannelInfo(byte[] data) } /// - /// Initializes a new instance with the specified connector - /// address and port, and originator address and port. + /// Initializes a new instance of the class with the + /// specified connector address and port, and originator address and port. /// public ForwardedTcpipChannelInfo(string connectedAddress, uint connectedPort, string originatorAddress, uint originatorPort) { @@ -32,11 +37,6 @@ public ForwardedTcpipChannelInfo(string connectedAddress, uint connectedPort, st OriginatorPort = originatorPort; } - /// - /// Specifies channel open type - /// - public const string NAME = "forwarded-tcpip"; - /// /// Gets the type of the channel to open. /// @@ -51,6 +51,9 @@ public override string ChannelType /// /// Gets the connected address. /// + /// + /// The connected address. + /// public string ConnectedAddress { get { return Utf8.GetString(_connectedAddress, 0, _connectedAddress.Length); } @@ -60,11 +63,17 @@ public string ConnectedAddress /// /// Gets the connected port. /// + /// + /// The connected port. + /// public uint ConnectedPort { get; private set; } /// /// Gets the originator address. /// + /// + /// The originator address. + /// public string OriginatorAddress { get { return Utf8.GetString(_originatorAddress, 0, _originatorAddress.Length); } @@ -74,6 +83,9 @@ public string OriginatorAddress /// /// Gets the originator port. /// + /// + /// The originator port. + /// public uint OriginatorPort { get; private set; } /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpen/SessionChannelOpenInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpen/SessionChannelOpenInfo.cs index c628b33d6..f20df5833 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpen/SessionChannelOpenInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpen/SessionChannelOpenInfo.cs @@ -3,12 +3,12 @@ namespace Renci.SshNet.Messages.Connection { /// - /// Used to open "session" channel type + /// Used to open "session" channel type. /// internal sealed class SessionChannelOpenInfo : ChannelOpenInfo { /// - /// Specifies channel open type + /// Specifies channel open type. /// public const string Name = "session"; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpen/X11ChannelOpenInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpen/X11ChannelOpenInfo.cs index 4ae7237c4..d071799c1 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpen/X11ChannelOpenInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpen/X11ChannelOpenInfo.cs @@ -3,14 +3,14 @@ namespace Renci.SshNet.Messages.Connection { /// - /// Used to open "x11" channel type + /// Used to open "x11" channel type. /// internal sealed class X11ChannelOpenInfo : ChannelOpenInfo { private byte[] _originatorAddress; /// - /// Specifies channel open type + /// Specifies channel open type. /// public const string Name = "x11"; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpenFailureMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpenFailureMessage.cs index 2a2888077..4488f9f5f 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpenFailureMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpenFailureMessage.cs @@ -62,7 +62,6 @@ protected override int BufferCapacity /// public ChannelOpenFailureMessage() { - } /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpenFailureReasons.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpenFailureReasons.cs index 94bbf8d33..0fbeaf4d3 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpenFailureReasons.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpenFailureReasons.cs @@ -6,19 +6,22 @@ internal enum ChannelOpenFailureReasons : uint { /// - /// SSH_OPEN_ADMINISTRATIVELY_PROHIBITED + /// SSH_OPEN_ADMINISTRATIVELY_PROHIBITED. /// AdministativelyProhibited = 1, + /// - /// SSH_OPEN_CONNECT_FAILED + /// SSH_OPEN_CONNECT_FAILED. /// ConnectFailed = 2, + /// - /// SSH_OPEN_UNKNOWN_CHANNEL_TYPE + /// SSH_OPEN_UNKNOWN_CHANNEL_TYPE. /// UnknownChannelType = 3, + /// - /// SSH_OPEN_RESOURCE_SHORTAGE + /// SSH_OPEN_RESOURCE_SHORTAGE. /// ResourceShortage = 4 } diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/BreakRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/BreakRequestInfo.cs index 472f8cb8e..c36655e84 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/BreakRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/BreakRequestInfo.cs @@ -1,12 +1,12 @@ 锘縩amespace Renci.SshNet.Messages.Connection { /// - /// Represents "break" type channel request information + /// Represents "break" type channel request information. /// internal sealed class BreakRequestInfo : RequestInfo { /// - /// Channel request name + /// Channel request name. /// public const string Name = "break"; @@ -43,7 +43,7 @@ protected override int BufferCapacity } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// public BreakRequestInfo() { @@ -51,7 +51,7 @@ public BreakRequestInfo() } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// Length of the break. public BreakRequestInfo(uint breakLength) diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs index ab4d99e96..fd9ad03b6 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs @@ -17,7 +17,10 @@ public class ChannelRequestMessage : ChannelMessage /// public string RequestName { - get { return _requestName; } + get + { + return _requestName; + } private set { _requestName = value; @@ -53,7 +56,7 @@ protected override int BufferCapacity /// public ChannelRequestMessage() { - // Required for dynamically loading request type when it comes from the server + // Required for dynamically loading request type when it comes from the server } /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs index e5e3735a0..ac4fc0ebc 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/EndOfWriteRequestInfo.cs @@ -1,12 +1,12 @@ 锘縩amespace Renci.SshNet.Messages.Connection { /// - /// Represents "eow@openssh.com" type channel request information + /// Represents "eow@openssh.com" type channel request information. /// public class EndOfWriteRequestInfo : RequestInfo { /// - /// Channel request name + /// Channel request name. /// public const string Name = "eow@openssh.com"; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfo.cs index 6901f3241..d04f80ef9 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/EnvironmentVariableRequestInfo.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet.Messages.Connection { /// - /// Represents "env" type channel request information + /// Represents "env" type channel request information. /// internal sealed class EnvironmentVariableRequestInfo : RequestInfo { @@ -9,7 +9,7 @@ internal sealed class EnvironmentVariableRequestInfo : RequestInfo private byte[] _variableValue; /// - /// Channel request name + /// Channel request name. /// public const string Name = "env"; @@ -25,7 +25,7 @@ public override string RequestName } /// - /// Gets or sets the name of the variable. + /// Gets the name of the variable. /// /// /// The name of the variable. @@ -36,7 +36,7 @@ public string VariableName } /// - /// Gets or sets the variable value. + /// Gets the value of the variable. /// /// /// The variable value. diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitSignalRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitSignalRequestInfo.cs index 9518b9e55..da17aee1d 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitSignalRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitSignalRequestInfo.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet.Messages.Connection { /// - /// Represents "exit-signal" type channel request information + /// Represents "exit-signal" type channel request information. /// internal sealed class ExitSignalRequestInfo : RequestInfo { @@ -10,7 +10,7 @@ internal sealed class ExitSignalRequestInfo : RequestInfo private byte[] _language; /// - /// Channel request name + /// Channel request name. /// public const string Name = "exit-signal"; @@ -41,7 +41,7 @@ public string SignalName /// Gets a value indicating whether core is dumped. /// /// - /// if core is dumped; otherwise, . + /// if core is dumped; otherwise, . /// public bool CoreDumped { get; private set; } diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitStatusRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitStatusRequestInfo.cs index 9aa92f96d..3d4651793 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitStatusRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ExitStatusRequestInfo.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet.Messages.Connection { /// - /// Represents "exit-status" type channel request information + /// Represents "exit-status" type channel request information. /// internal sealed class ExitStatusRequestInfo : RequestInfo { @@ -30,7 +30,7 @@ protected override int BufferCapacity { get { - var capacity = base.BufferCapacity; + var capacity = base.BufferCapacity; capacity += 4; // ExitStatus return capacity; } diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/KeepAliveRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/KeepAliveRequestInfo.cs index 9bf303d6e..75b88df84 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/KeepAliveRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/KeepAliveRequestInfo.cs @@ -1,12 +1,12 @@ 锘縩amespace Renci.SshNet.Messages.Connection { /// - /// Represents "keepalive@openssh.com" type channel request information + /// Represents "keepalive@openssh.com" type channel request information. /// public class KeepAliveRequestInfo : RequestInfo { /// - /// Channel request name + /// Channel request name. /// public const string Name = "keepalive@openssh.com"; @@ -22,7 +22,7 @@ public override string RequestName } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// public KeepAliveRequestInfo() { diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalRequestInfo.cs similarity index 98% rename from src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs rename to src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalRequestInfo.cs index fbe5a11dd..82df2712f 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/PseudoTerminalRequestInfo.cs @@ -141,7 +141,7 @@ protected override void SaveData() // write total length of encoded terminal modes, which is 1 bytes for the opcode / terminal mode // and 4 bytes for the uint argument for each entry; the encoded terminal modes are terminated by // opcode TTY_OP_END (which is 1 byte) - Write((uint) TerminalModeValues.Count*(1 + 4) + 1); + Write(((uint) TerminalModeValues.Count*(1 + 4)) + 1); foreach (var item in TerminalModeValues) { diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/RequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/RequestInfo.cs index 103e412b8..546f7ec6b 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/RequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/RequestInfo.cs @@ -19,7 +19,7 @@ public abstract class RequestInfo : SshData /// Gets or sets a value indicating whether reply message is needed. /// /// - /// if reply message is needed; otherwise, . + /// if reply message is needed; otherwise, . /// public bool WantReply { get; protected set; } diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ShellRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ShellRequestInfo.cs index 42fc9cf1d..92ed4fd6b 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ShellRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ShellRequestInfo.cs @@ -1,12 +1,12 @@ 锘縩amespace Renci.SshNet.Messages.Connection { /// - /// Represents "shell" type channel request information + /// Represents "shell" type channel request information. /// internal sealed class ShellRequestInfo : RequestInfo { /// - /// Channel request name + /// Channel request name. /// public const string Name = "shell"; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/SignalRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/SignalRequestInfo.cs index bb69e5ed2..c16c842c8 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/SignalRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/SignalRequestInfo.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet.Messages.Connection { /// - /// Represents "signal" type channel request information + /// Represents "signal" type channel request information. /// internal sealed class SignalRequestInfo : RequestInfo { diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/SubsystemRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/SubsystemRequestInfo.cs index 6871b9fe3..0013792ca 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/SubsystemRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/SubsystemRequestInfo.cs @@ -1,14 +1,14 @@ 锘縩amespace Renci.SshNet.Messages.Connection { /// - /// Represents "subsystem" type channel request information + /// Represents "subsystem" type channel request information. /// internal sealed class SubsystemRequestInfo : RequestInfo { private byte[] _subsystemName; /// - /// Channel request name + /// Channel request name. /// public const string Name = "subsystem"; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/WindowChangeRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/WindowChangeRequestInfo.cs index edcd9af54..34e4c2cb3 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/WindowChangeRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/WindowChangeRequestInfo.cs @@ -1,12 +1,12 @@ 锘縩amespace Renci.SshNet.Messages.Connection { /// - /// Represents "window-change" type channel request information + /// Represents "window-change" type channel request information. /// internal sealed class WindowChangeRequestInfo : RequestInfo { /// - /// Channe request name + /// Channe request name. /// public const string Name = "window-change"; diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/X11ForwardingRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/X11ForwardingRequestInfo.cs index 794c1da53..c7f38c94f 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/X11ForwardingRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/X11ForwardingRequestInfo.cs @@ -32,7 +32,7 @@ public override string RequestName public bool IsSingleConnection { get; set; } /// - /// Gets or sets the authentication protocol. + /// Gets the authentication protocol. /// /// /// The authentication protocol. diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/XonXoffRequestInfo.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/XonXoffRequestInfo.cs index 60924799f..2cf9a19c0 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/XonXoffRequestInfo.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/XonXoffRequestInfo.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet.Messages.Connection { /// - /// Represents "xon-xoff" type channel request information + /// Represents "xon-xoff" type channel request information. /// internal sealed class XonXoffRequestInfo : RequestInfo { @@ -25,7 +25,7 @@ public override string RequestName /// Gets or sets a value indicating whether client can do. /// /// - /// if client can do; otherwise, . + /// if client can do; otherwise, . /// public bool ClientCanDo { get; set; } diff --git a/src/Renci.SshNet/Messages/Connection/ChannelSuccessMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelSuccessMessage.cs index d6f21e9a5..50d302f21 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelSuccessMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelSuccessMessage.cs @@ -11,7 +11,6 @@ public class ChannelSuccessMessage : ChannelMessage /// public ChannelSuccessMessage() { - } /// diff --git a/src/Renci.SshNet/Messages/Connection/GlobalRequestMessage.cs b/src/Renci.SshNet/Messages/Connection/GlobalRequestMessage.cs index cbd72795d..6e0ca3a21 100644 --- a/src/Renci.SshNet/Messages/Connection/GlobalRequestMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/GlobalRequestMessage.cs @@ -23,7 +23,7 @@ public string RequestName /// Gets a value indicating whether message reply should be sent.. /// /// - /// if message reply should be sent; otherwise, . + /// if message reply should be sent; otherwise, . /// public bool WantReply { get; private set; } diff --git a/src/Renci.SshNet/Messages/Connection/GlobalRequestName.cs b/src/Renci.SshNet/Messages/Connection/GlobalRequestName.cs index 6a1d0e279..263278c0a 100644 --- a/src/Renci.SshNet/Messages/Connection/GlobalRequestName.cs +++ b/src/Renci.SshNet/Messages/Connection/GlobalRequestName.cs @@ -6,11 +6,12 @@ public enum GlobalRequestName { /// - /// tcpip-forward + /// tcpip-forward. /// TcpIpForward, + /// - /// cancel-tcpip-forward + /// cancel-tcpip-forward. /// CancelTcpIpForward, } diff --git a/src/Renci.SshNet/Messages/Message.cs b/src/Renci.SshNet/Messages/Message.cs index d2fc3274a..ebe3a2e71 100644 --- a/src/Renci.SshNet/Messages/Message.cs +++ b/src/Renci.SshNet/Messages/Message.cs @@ -8,7 +8,7 @@ namespace Renci.SshNet.Messages { /// - /// Base class for all SSH protocol messages + /// Base class for all SSH protocol messages. /// public abstract class Message : SshData { @@ -29,6 +29,7 @@ protected override int BufferCapacity /// /// Writes the message to the specified . /// + /// The to write the message to. protected override void WriteBytes(SshDataStream stream) { var enumerator = GetType().GetCustomAttributes(inherit: true).GetEnumerator(); @@ -55,58 +56,61 @@ internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor) var messageLength = BufferCapacity; - SshDataStream sshDataStream; - if (messageLength == -1 || compressor != null) { - sshDataStream = new SshDataStream(DefaultCapacity); + using (var sshDataStream = new SshDataStream(DefaultCapacity)) + { + // skip: + // * 4 bytes for the outbound packet sequence + // * 4 bytes for the packet data length + // * one byte for the packet padding length + _ = sshDataStream.Seek(outboundPacketSequenceSize + 4 + 1, SeekOrigin.Begin); - // skip: - // * 4 bytes for the outbound packet sequence - // * 4 bytes for the packet data length - // * one byte for the packet padding length - _ = sshDataStream.Seek(outboundPacketSequenceSize + 4 + 1, SeekOrigin.Begin); + if (compressor != null) + { + // obtain uncompressed message payload + using (var uncompressedDataStream = new SshDataStream(messageLength != -1 ? messageLength : DefaultCapacity)) + { + WriteBytes(uncompressedDataStream); - if (compressor != null) - { - // obtain uncompressed message payload - var uncompressedDataStream = new SshDataStream(messageLength != -1 ? messageLength : DefaultCapacity); - WriteBytes(uncompressedDataStream); + // compress message payload + var compressedMessageData = compressor.Compress(uncompressedDataStream.ToArray()); - // compress message payload - var compressedMessageData = compressor.Compress(uncompressedDataStream.ToArray()); + // add compressed message payload + sshDataStream.Write(compressedMessageData, 0, compressedMessageData.Length); + } + } + else + { + // add message payload + WriteBytes(sshDataStream); + } - // add compressed message payload - sshDataStream.Write(compressedMessageData, 0, compressedMessageData.Length); - } - else - { - // add message payload - WriteBytes(sshDataStream); - } + messageLength = (int) sshDataStream.Length - (outboundPacketSequenceSize + 4 + 1); - messageLength = (int) sshDataStream.Length - (outboundPacketSequenceSize + 4 + 1); + var packetLength = messageLength + 4 + 1; - var packetLength = messageLength + 4 + 1; + // determine the padding length + var paddingLength = GetPaddingLength(paddingMultiplier, packetLength); - // determine the padding length - var paddingLength = GetPaddingLength(paddingMultiplier, packetLength); + // add padding bytes + var paddingBytes = new byte[paddingLength]; + CryptoAbstraction.GenerateRandom(paddingBytes); + sshDataStream.Write(paddingBytes, 0, paddingLength); - // add padding bytes - var paddingBytes = new byte[paddingLength]; - CryptoAbstraction.GenerateRandom(paddingBytes); - sshDataStream.Write(paddingBytes, 0, paddingLength); + var packetDataLength = GetPacketDataLength(messageLength, paddingLength); - var packetDataLength = GetPacketDataLength(messageLength, paddingLength); + // skip bytes for outbound packet sequence + _ = sshDataStream.Seek(outboundPacketSequenceSize, SeekOrigin.Begin); - // skip bytes for outbound packet sequence - _ = sshDataStream.Seek(outboundPacketSequenceSize, SeekOrigin.Begin); + // add packet data length + sshDataStream.Write(packetDataLength); - // add packet data length - sshDataStream.Write(packetDataLength); + // add packet padding length + sshDataStream.WriteByte(paddingLength); - // add packet padding length - sshDataStream.WriteByte(paddingLength); + return sshDataStream.ToArray(); + } } else { @@ -118,27 +122,28 @@ internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor) var packetDataLength = GetPacketDataLength(messageLength, paddingLength); // lets construct an SSH data stream of the exact size required - sshDataStream = new SshDataStream(packetLength + paddingLength + outboundPacketSequenceSize); + using (var sshDataStream = new SshDataStream(packetLength + paddingLength + outboundPacketSequenceSize)) + { + // skip bytes for outbound packet sequenceSize + _ = sshDataStream.Seek(outboundPacketSequenceSize, SeekOrigin.Begin); - // skip bytes for outbound packet sequenceSize - _ = sshDataStream.Seek(outboundPacketSequenceSize, SeekOrigin.Begin); + // add packet data length + sshDataStream.Write(packetDataLength); - // add packet data length - sshDataStream.Write(packetDataLength); + // add packet padding length + sshDataStream.WriteByte(paddingLength); - // add packet padding length - sshDataStream.WriteByte(paddingLength); + // add message payload + WriteBytes(sshDataStream); - // add message payload - WriteBytes(sshDataStream); + // add padding bytes + var paddingBytes = new byte[paddingLength]; + CryptoAbstraction.GenerateRandom(paddingBytes); + sshDataStream.Write(paddingBytes, 0, paddingLength); - // add padding bytes - var paddingBytes = new byte[paddingLength]; - CryptoAbstraction.GenerateRandom(paddingBytes); - sshDataStream.Write(paddingBytes, 0, paddingLength); + return sshDataStream.ToArray(); + } } - - return sshDataStream.ToArray(); } private static uint GetPacketDataLength(int messageLength, byte paddingLength) diff --git a/src/Renci.SshNet/Messages/MessageAttribute.cs b/src/Renci.SshNet/Messages/MessageAttribute.cs index 10c0cdef0..f94d13c32 100644 --- a/src/Renci.SshNet/Messages/MessageAttribute.cs +++ b/src/Renci.SshNet/Messages/MessageAttribute.cs @@ -2,7 +2,6 @@ namespace Renci.SshNet.Messages { - /// /// Indicates that a class represents SSH message. This class cannot be inherited. /// @@ -10,20 +9,20 @@ namespace Renci.SshNet.Messages public sealed class MessageAttribute : Attribute { /// - /// Gets or sets message name as defined in RFC 4250. + /// Gets the message name as defined in RFC 4250. /// /// /// The name. /// - public string Name { get; set; } + public string Name { get; } /// - /// Gets or sets message number as defined in RFC 4250. + /// Gets the message number as defined in RFC 4250. /// /// /// The number. /// - public byte Number { get; set; } + public byte Number { get; } /// /// Initializes a new instance of the class. diff --git a/src/Renci.SshNet/Messages/ServiceName.cs b/src/Renci.SshNet/Messages/ServiceName.cs index 1c63ddbed..bfd6644cd 100644 --- a/src/Renci.SshNet/Messages/ServiceName.cs +++ b/src/Renci.SshNet/Messages/ServiceName.cs @@ -1,17 +1,17 @@ 锘縩amespace Renci.SshNet.Messages { /// - /// Specifies list of supported services + /// Specifies list of supported services. /// public enum ServiceName { /// - /// ssh-userauth + /// ssh-userauth. /// UserAuthentication, /// - /// ssh-connection + /// ssh-connection. /// Connection } diff --git a/src/Renci.SshNet/Messages/Transport/DebugMessage.cs b/src/Renci.SshNet/Messages/Transport/DebugMessage.cs index b7347283f..f550d95fe 100644 --- a/src/Renci.SshNet/Messages/Transport/DebugMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/DebugMessage.cs @@ -13,7 +13,7 @@ public class DebugMessage : Message /// Gets a value indicating whether the message to be always displayed. /// /// - /// if the message always to be displayed; otherwise, . + /// if the message always to be displayed; otherwise, . /// public bool IsAlwaysDisplay { get; private set; } diff --git a/src/Renci.SshNet/Messages/Transport/DisconnectReason.cs b/src/Renci.SshNet/Messages/Transport/DisconnectReason.cs index 35c6f885a..cf4119ba9 100644 --- a/src/Renci.SshNet/Messages/Transport/DisconnectReason.cs +++ b/src/Renci.SshNet/Messages/Transport/DisconnectReason.cs @@ -9,65 +9,82 @@ public enum DisconnectReason /// Disconnect reason is not provided. /// None = 0, + /// - /// SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT + /// SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT. /// HostNotAllowedToConnect = 1, + /// - /// SSH_DISCONNECT_PROTOCOL_ERROR + /// SSH_DISCONNECT_PROTOCOL_ERROR. /// ProtocolError = 2, + /// - /// SSH_DISCONNECT_KEY_EXCHANGE_FAILED + /// SSH_DISCONNECT_KEY_EXCHANGE_FAILED. /// KeyExchangeFailed = 3, + /// - /// SSH_DISCONNECT_RESERVED + /// SSH_DISCONNECT_RESERVED. /// +#pragma warning disable CA1700 // Do not name enum values 'Reserved' Reserved = 4, +#pragma warning restore CA1700 // Do not name enum values 'Reserved' + /// - /// SSH_DISCONNECT_MAC_ERROR + /// SSH_DISCONNECT_MAC_ERROR. /// MacError = 5, + /// - /// SSH_DISCONNECT_COMPRESSION_ERROR + /// SSH_DISCONNECT_COMPRESSION_ERROR. /// CompressionError = 6, + /// - /// SSH_DISCONNECT_SERVICE_NOT_AVAILABLE + /// SSH_DISCONNECT_SERVICE_NOT_AVAILABLE. /// ServiceNotAvailable = 7, + /// - /// SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED + /// SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED. /// ProtocolVersionNotSupported = 8, + /// - /// SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE + /// SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE. /// HostKeyNotVerifiable = 9, + /// - /// SSH_DISCONNECT_CONNECTION_LOST + /// SSH_DISCONNECT_CONNECTION_LOST. /// ConnectionLost = 10, + /// - /// SSH_DISCONNECT_BY_APPLICATION + /// SSH_DISCONNECT_BY_APPLICATION. /// ByApplication = 11, + /// - /// SSH_DISCONNECT_TOO_MANY_CONNECTIONS + /// SSH_DISCONNECT_TOO_MANY_CONNECTIONS. /// TooManyConnections = 12, + /// - /// SSH_DISCONNECT_AUTH_CANCELLED_BY_USER + /// SSH_DISCONNECT_AUTH_CANCELLED_BY_USER. /// AuthenticationCanceledByUser = 13, + /// - /// SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE + /// SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE. /// NoMoreAuthenticationMethodsAvailable = 14, + /// - /// SSH_DISCONNECT_ILLEGAL_USER_NAME + /// SSH_DISCONNECT_ILLEGAL_USER_NAME. /// - IllegalUserName = 15, + IllegalUserName = 15 } } diff --git a/src/Renci.SshNet/Messages/Transport/IKeyExchangedAllowed.cs b/src/Renci.SshNet/Messages/Transport/IKeyExchangedAllowed.cs index b53a09e40..1f06aeb31 100644 --- a/src/Renci.SshNet/Messages/Transport/IKeyExchangedAllowed.cs +++ b/src/Renci.SshNet/Messages/Transport/IKeyExchangedAllowed.cs @@ -1,9 +1,11 @@ 锘縩amespace Renci.SshNet.Messages.Transport { /// - /// Indicates that message that implement this interface is allowed during key exchange phase + /// Indicates that message that implement this interface is allowed during key exchange phase. /// +#pragma warning disable CA1040 // Avoid empty interfaces public interface IKeyExchangedAllowed +#pragma warning restore CA1040 // Avoid empty interfaces { } } diff --git a/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs b/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs index 5fc009a37..5d07f1d00 100644 --- a/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs @@ -18,13 +18,27 @@ public class IgnoreMessage : Message public byte[] Data { get; private set; } /// - /// Initializes a new instance of the class + /// Initializes a new instance of the class. /// public IgnoreMessage() { Data = Array.Empty(); } + /// + /// Initializes a new instance of the class. + /// + /// The data. + public IgnoreMessage(byte[] data) + { + if (data is null) + { + throw new ArgumentNullException(nameof(data)); + } + + Data = data; + } + /// /// Gets the size of the message in bytes. /// @@ -42,20 +56,6 @@ protected override int BufferCapacity } } - /// - /// Initializes a new instance of the class. - /// - /// The data. - public IgnoreMessage(byte[] data) - { - if (data is null) - { - throw new ArgumentNullException(nameof(data)); - } - - Data = data; - } - /// /// Called when type specific data need to be loaded. /// diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs index 6fe1c76ff..f1010a19d 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs @@ -14,7 +14,7 @@ public class KeyExchangeDhGroupExchangeGroup : Message private byte[] _subGroup; /// - /// Gets or sets the safe prime. + /// Gets the safe prime. /// /// /// The safe prime. @@ -25,7 +25,7 @@ public BigInteger SafePrime } /// - /// Gets or sets the generator for subgroup in GF(p). + /// Gets the generator for subgroup in GF(p). /// /// /// The sub group. diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs index 105e5797c..8f0a1489f 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs @@ -7,7 +7,7 @@ public class KeyExchangeDhReplyMessage : Message { /// - /// Gets server public host key and certificates + /// Gets server public host key and certificates. /// /// The host key. public byte[] HostKey { get; private set; } diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs index 4bd508f54..2d02d1480 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs @@ -10,7 +10,7 @@ namespace Renci.SshNet.Messages.Transport internal sealed class KeyExchangeEcdhInitMessage : Message, IKeyExchangedAllowed { /// - /// Gets the client's ephemeral contribution to the ECDH exchange, encoded as an octet string + /// Gets the client's ephemeral contribution to the ECDH exchange, encoded as an octet string. /// public byte[] QC { get; private set; } diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs index a194caf1e..a5626aece 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs @@ -7,7 +7,7 @@ public class KeyExchangeEcdhReplyMessage : Message { /// - /// Gets a string encoding an X.509v3 certificate containing the server's ECDSA public host key + /// Gets a string encoding an X.509v3 certificate containing the server's ECDSA public host key. /// /// The host key. public byte[] KS { get; private set; } @@ -69,4 +69,4 @@ internal override void Process(Session session) session.OnKeyExchangeEcdhReplyMessageReceived(this); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Netconf/INetConfSession.cs b/src/Renci.SshNet/Netconf/INetConfSession.cs index 4dd3e24d4..223cd3e0d 100644 --- a/src/Renci.SshNet/Netconf/INetConfSession.cs +++ b/src/Renci.SshNet/Netconf/INetConfSession.cs @@ -1,25 +1,39 @@ 锘縰sing System.Xml; +using Renci.SshNet.Common; + namespace Renci.SshNet.NetConf { + /// + /// Represents a NETCONF session. + /// internal interface INetConfSession : ISubsystemSession { /// - /// Gets the NetConf server capabilities. + /// Gets the NETCONF server capabilities. /// /// - /// The NetConf server capabilities. + /// The NETCONF server capabilities. /// XmlDocument ServerCapabilities { get; } /// - /// Gets the NetConf client capabilities. + /// Gets the NETCONF client capabilities. /// /// - /// The NetConf client capabilities. + /// The NETCONF client capabilities. /// XmlDocument ClientCapabilities { get; } + /// + /// Sends the specified RPC request and returns the reply sent by the NETCONF server. + /// + /// The RPC request. + /// to automatically increment the message id and verify the message id of the RPC reply. + /// + /// The RPC reply. + /// + /// is and the message id in the RPC reply does not match the message id of the RPC request. XmlDocument SendReceiveRpc(XmlDocument rpc, bool automaticMessageIdHandling); } } diff --git a/src/Renci.SshNet/Netconf/NetConfSession.cs b/src/Renci.SshNet/Netconf/NetConfSession.cs index f1252f539..317b99c1c 100644 --- a/src/Renci.SshNet/Netconf/NetConfSession.cs +++ b/src/Renci.SshNet/Netconf/NetConfSession.cs @@ -156,7 +156,11 @@ protected override void OnDataReceived(byte[] data) position += match.Index + match.Length + fractionLength; } +#if NET7_0_OR_GREATER + if (Regex.IsMatch(chunk.AsSpan(position), @"\n##\n")) +#else if (Regex.IsMatch(chunk.Substring(position), @"\n##\n")) +#endif // NET7_0_OR_GREATER { _ = _rpcReplyReceived.Set(); } diff --git a/src/Renci.SshNet/PasswordAuthenticationMethod.cs b/src/Renci.SshNet/PasswordAuthenticationMethod.cs index d6e6a78a6..f53016240 100644 --- a/src/Renci.SshNet/PasswordAuthenticationMethod.cs +++ b/src/Renci.SshNet/PasswordAuthenticationMethod.cs @@ -105,7 +105,7 @@ public override AuthenticationResult Authenticate(Session session) session.SendMessage(_requestMessage); session.WaitOnHandle(_authenticationCompleted); } - finally + finally { session.UnRegisterMessage("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"); session.UserAuthenticationSuccessReceived -= Session_UserAuthenticationSuccessReceived; diff --git a/src/Renci.SshNet/PasswordConnectionInfo.cs b/src/Renci.SshNet/PasswordConnectionInfo.cs index eb2ad9230..08ef59dea 100644 --- a/src/Renci.SshNet/PasswordConnectionInfo.cs +++ b/src/Renci.SshNet/PasswordConnectionInfo.cs @@ -6,7 +6,7 @@ namespace Renci.SshNet { /// - /// Provides connection information when password authentication method is used + /// Provides connection information when password authentication method is used. /// /// /// @@ -260,7 +260,9 @@ public PasswordConnectionInfo(string host, int port, string username, byte[] pas private void AuthenticationMethod_PasswordExpired(object sender, AuthenticationPasswordChangeEventArgs e) { +#pragma warning disable MA0091 // Sender should be 'this' for instance events PasswordExpired?.Invoke(sender, e); +#pragma warning restore MA0091 // Sender should be 'this' for instance events } /// diff --git a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs index 7acf40ce2..a8f7f4bd3 100644 --- a/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs +++ b/src/Renci.SshNet/PrivateKeyAuthenticationMethod.cs @@ -17,7 +17,9 @@ public class PrivateKeyAuthenticationMethod : AuthenticationMethod, IDisposable { private AuthenticationResult _authenticationResult = AuthenticationResult.Failure; private EventWaitHandle _authenticationCompleted = new ManualResetEvent(initialState: false); +#pragma warning disable S1450 // Private fields only used as local variables in methods should become local variables private bool _isSignatureRequired; +#pragma warning restore S1450 // Private fields only used as local variables in methods should become local variables private bool _isDisposed; /// @@ -168,7 +170,7 @@ public void Dispose() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// to release both managed and unmanaged resources; to release only unmanaged resources. protected virtual void Dispose(bool disposing) diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index e5a3ffa3d..eb7b3767b 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -68,14 +68,14 @@ namespace Renci.SshNet public class PrivateKeyFile : IPrivateKeySource, IDisposable { private static readonly Regex PrivateKeyRegex = new Regex(@"^-+ *BEGIN (?\w+( \w+)*) PRIVATE KEY *-+\r?\n((Proc-Type: 4,ENCRYPTED\r?\nDEK-Info: (?[A-Z0-9-]+),(?[A-F0-9]+)\r?\n\r?\n)|(Comment: ""?[^\r\n]*""?\r?\n))?(?([a-zA-Z0-9/+=]{1,80}\r?\n)+)-+ *END \k PRIVATE KEY *-+", - RegexOptions.Compiled | RegexOptions.Multiline); + RegexOptions.Compiled | RegexOptions.Multiline | RegexOptions.ExplicitCapture); private readonly List _hostAlgorithms = new List(); private Key _key; private bool _isDisposed; /// - /// The supported host algorithms for this key file. + /// Gets the supported host algorithms for this key file. /// public IReadOnlyCollection HostKeyAlgorithms { @@ -235,7 +235,7 @@ private void Open(Stream privateKey, string passPhrase) cipher = new CipherInfo(256, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding())); break; default: - throw new SshException(string.Format(CultureInfo.CurrentCulture, "Private key cipher \"{0}\" is not supported.", cipherName)); + throw new SshException(string.Format(CultureInfo.InvariantCulture, "Private key cipher \"{0}\" is not supported.", cipherName)); } decryptedData = DecryptKey(cipher, binaryData, passPhrase, binarySalt); @@ -250,8 +250,10 @@ private void Open(Stream privateKey, string passPhrase) case "RSA": var rsaKey = new RsaKey(decryptedData); _key = rsaKey; +#pragma warning disable CA2000 // Dispose objects before losing scope _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA512))); _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA256))); +#pragma warning restore CA2000 // Dispose objects before losing scope _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); break; case "DSA": @@ -266,14 +268,17 @@ private void Open(Stream privateKey, string passPhrase) _key = ParseOpenSshV1Key(decryptedData, passPhrase); if (_key is RsaKey parsedRsaKey) { +#pragma warning disable CA2000 // Dispose objects before losing scope _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA512))); _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA256))); +#pragma warning restore CA2000 // Dispose objects before losing scope _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); } else { _hostAlgorithms.Add(new KeyHostAlgorithm(_key.ToString(), _key)); } + break; case "SSH2 ENCRYPTED": var reader = new SshDataReader(decryptedData); @@ -309,7 +314,9 @@ private void Open(Stream privateKey, string passPhrase) throw new SshException(string.Format("Cipher method '{0}' is not supported.", cipherName)); } - // TODO: Create two specific data types to avoid using SshDataReader class + /* + * TODO: Create two specific data types to avoid using SshDataReader class. + */ reader = new SshDataReader(keyData); @@ -330,8 +337,10 @@ private void Open(Stream privateKey, string passPhrase) var p = reader.ReadBigIntWithBits(); // q var decryptedRsaKey = new RsaKey(modulus, exponent, d, p, q, inverseQ); _key = decryptedRsaKey; +#pragma warning disable CA2000 // Dispose objects before losing scope _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(decryptedRsaKey, HashAlgorithmName.SHA512))); _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(decryptedRsaKey, HashAlgorithmName.SHA256))); +#pragma warning restore CA2000 // Dispose objects before losing scope _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); } else if (keyType == "dl-modp{sign{dsa-nist-sha1},dh{plain}}") @@ -341,6 +350,7 @@ private void Open(Stream privateKey, string passPhrase) { throw new SshException("Invalid private key"); } + var p = reader.ReadBigIntWithBits(); var g = reader.ReadBigIntWithBits(); var q = reader.ReadBigIntWithBits(); @@ -353,6 +363,7 @@ private void Open(Stream privateKey, string passPhrase) { throw new NotSupportedException(string.Format("Key type '{0}' is not supported.", keyType)); } + break; default: throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Key '{0}' is not supported.", keyName)); @@ -436,8 +447,8 @@ private static byte[] DecryptKey(CipherInfo cipherInfo, byte[] cipherData, strin /// Parses an OpenSSH V1 key file (i.e. ED25519 key) according to the the key spec: /// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key. /// - /// the key file data (i.e. base64 encoded data between the header/footer) - /// passphrase or null if there isn't one + /// The key file data (i.e. base64 encoded data between the header/footer). + /// Passphrase or if there isn't one. /// /// The OpenSSH V1 key. /// @@ -540,7 +551,10 @@ private static Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) var checkInt2 = (int) privateKeyReader.ReadUInt32(); if (checkInt1 != checkInt2) { - throw new SshException("The random check bytes of the OpenSSH key do not match (" + checkInt1 + " <->" + checkInt2 + ")."); + throw new SshException(string.Format(CultureInfo.InvariantCulture, + "The random check bytes of the OpenSSH key do not match ({0} <-> {1}).", + checkInt1.ToString(CultureInfo.InvariantCulture), + checkInt2.ToString(CultureInfo.InvariantCulture))); } // key type @@ -595,7 +609,8 @@ private static Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) { if ((int) padding[i] != i + 1) { - throw new SshException("Padding of openssh key format contained wrong byte at position: " + i); + throw new SshException("Padding of openssh key format contained wrong byte at position: " + + i.ToString(CultureInfo.InvariantCulture)); } } diff --git a/src/Renci.SshNet/Properties/CommonAssemblyInfo.cs b/src/Renci.SshNet/Properties/CommonAssemblyInfo.cs index d99338feb..7af4c6381 100644 --- a/src/Renci.SshNet/Properties/CommonAssemblyInfo.cs +++ b/src/Renci.SshNet/Properties/CommonAssemblyInfo.cs @@ -14,12 +14,11 @@ [assembly: AssemblyInformationalVersion("2023.0.0")] [assembly: CLSCompliant(false)] -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from // COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] - #if DEBUG [assembly: AssemblyConfiguration("Debug")] #else diff --git a/src/Renci.SshNet/ProxyTypes.cs b/src/Renci.SshNet/ProxyTypes.cs index 9a7fce098..cff5eb247 100644 --- a/src/Renci.SshNet/ProxyTypes.cs +++ b/src/Renci.SshNet/ProxyTypes.cs @@ -5,13 +5,24 @@ /// public enum ProxyTypes { - /// No proxy server. + /// + /// No proxy server. + /// None, - /// A SOCKS4 proxy server. + + /// + /// A SOCKS4 proxy server. + /// Socks4, - /// A SOCKS5 proxy server. + + /// + /// A SOCKS5 proxy server. + /// Socks5, - /// A HTTP proxy server. + + /// + /// An HTTP proxy server. + /// Http, } } diff --git a/src/Renci.SshNet/RemotePathTransformation.cs b/src/Renci.SshNet/RemotePathTransformation.cs index 5e3f74fcb..7404c3e4b 100644 --- a/src/Renci.SshNet/RemotePathTransformation.cs +++ b/src/Renci.SshNet/RemotePathTransformation.cs @@ -27,7 +27,7 @@ public static class RemotePathTransformation private static readonly IRemotePathTransformation DoubleQuoteTransformation = new RemotePathDoubleQuoteTransformation(); /// - /// Quotes a path in a way to be suitable to be used with a shell-based server. + /// Gets a that quotes a path in a way to be suitable to be used with a shell-based server. /// /// /// A quoted path. @@ -85,7 +85,7 @@ public static IRemotePathTransformation ShellQuote } /// - /// Performs no transformation. + /// Gets a that performs no transformation. /// /// /// Recommended for servers that do not require any character to be escaped or enclosed in quotes, @@ -97,7 +97,7 @@ public static IRemotePathTransformation None } /// - /// Encloses a path in double quotes, and escapes any embedded double quote with a backslash. + /// Gets a that encloses a path in double quotes, and escapes any embedded double quote with a backslash. /// /// /// A transformation that encloses a path in double quotes, and escapes any embedded double quote with diff --git a/src/Renci.SshNet/ScpClient.cs b/src/Renci.SshNet/ScpClient.cs index 1413a12d9..8121c9702 100644 --- a/src/Renci.SshNet/ScpClient.cs +++ b/src/Renci.SshNet/ScpClient.cs @@ -632,7 +632,11 @@ private string ReadString(Stream stream) /// The file or directory to upload. private void UploadTimes(IChannelSession channel, Stream input, FileSystemInfo fileOrDirectory) { +#if NET ||NETSTANDARD2_1_OR_GREATER + var zeroTime = DateTime.UnixEpoch; +#else var zeroTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); +#endif var modificationSeconds = (long) (fileOrDirectory.LastWriteTimeUtc - zeroTime).TotalSeconds; var accessSeconds = (long) (fileOrDirectory.LastAccessTimeUtc - zeroTime).TotalSeconds; SendData(channel, string.Format(CultureInfo.InvariantCulture, "T{0} 0 {1} 0\n", modificationSeconds, accessSeconds)); @@ -805,7 +809,11 @@ private void InternalDownload(IChannelSession channel, Stream input, FileSystemI var mtime = long.Parse(match.Result("${mtime}"), CultureInfo.InvariantCulture); var atime = long.Parse(match.Result("${atime}"), CultureInfo.InvariantCulture); +#if NET || NETSTANDARD2_1_OR_GREATER + var zeroTime = DateTime.UnixEpoch; +#else var zeroTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); +#endif modifiedTime = zeroTime.AddSeconds(mtime); accessedTime = zeroTime.AddSeconds(atime); continue; diff --git a/src/Renci.SshNet/Security/BouncyCastle/math/BigInteger.cs b/src/Renci.SshNet/Security/BouncyCastle/math/BigInteger.cs index 635a25409..a98959efe 100644 --- a/src/Renci.SshNet/Security/BouncyCastle/math/BigInteger.cs +++ b/src/Renci.SshNet/Security/BouncyCastle/math/BigInteger.cs @@ -648,7 +648,9 @@ public BigInteger( int nBytes = GetByteLength(sizeInBits); byte[] b = new byte[nBytes]; +#pragma warning disable CA5394 // Do not use insecure randomness random.NextBytes(b); +#pragma warning restore CA5394 // Do not use insecure randomness // strip off any excess bits in the MSB int xBits = BitsPerByte * nBytes - sizeInBits; @@ -658,6 +660,7 @@ public BigInteger( this.sign = this.magnitude.Length < 1 ? 0 : 1; } +#pragma warning disable CA5394 // Do not use insecure randomness public BigInteger( int bitLength, int certainty, @@ -716,6 +719,7 @@ public BigInteger( } } } +#pragma warning restore CA5394 // Do not use insecure randomness public BigInteger Abs() { diff --git a/src/Renci.SshNet/Security/BouncyCastle/security/SecureRandom.cs b/src/Renci.SshNet/Security/BouncyCastle/security/SecureRandom.cs index 377817e01..6e86c47ca 100644 --- a/src/Renci.SshNet/Security/BouncyCastle/security/SecureRandom.cs +++ b/src/Renci.SshNet/Security/BouncyCastle/security/SecureRandom.cs @@ -58,7 +58,9 @@ public SecureRandom() /// /// The source to generate all random bytes from. public SecureRandom(IRandomGenerator generator) +#pragma warning disable CA5394 // Do not use insecure randomness : base(0) +#pragma warning restore CA5394 // Do not use insecure randomness { this.generator = generator; } diff --git a/src/Renci.SshNet/Security/CertificateHostAlgorithm.cs b/src/Renci.SshNet/Security/CertificateHostAlgorithm.cs index 6110e3215..41d5f4103 100644 --- a/src/Renci.SshNet/Security/CertificateHostAlgorithm.cs +++ b/src/Renci.SshNet/Security/CertificateHostAlgorithm.cs @@ -29,7 +29,7 @@ public CertificateHostAlgorithm(string name) /// /// The data. /// Signed data. - /// + /// Always. public override byte[] Sign(byte[] data) { throw new NotImplementedException(); @@ -41,7 +41,7 @@ public override byte[] Sign(byte[] data) /// The data. /// The signature. /// if signature was successfully verified; otherwise . - /// + /// Always. public override bool VerifySignature(byte[] data, byte[] signature) { throw new NotImplementedException(); diff --git a/src/Renci.SshNet/Security/Cryptography/AsymmetricCipher.cs b/src/Renci.SshNet/Security/Cryptography/AsymmetricCipher.cs index 91d0c77ff..74e4a733b 100644 --- a/src/Renci.SshNet/Security/Cryptography/AsymmetricCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/AsymmetricCipher.cs @@ -3,7 +3,7 @@ /// /// Base class for asymmetric cipher implementations. /// - public abstract class AsymmetricCipher : Cipher + public abstract class AsymmetricCipher : Cipher { /// /// Gets the minimum data size. diff --git a/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs b/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs index 00c66f6c1..b9f7dde58 100644 --- a/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/BlockCipher.cs @@ -69,7 +69,9 @@ protected BlockCipher(byte[] key, byte blockSize, CipherMode mode, CipherPadding /// The data. /// The zero-based offset in at which to begin encrypting. /// The number of bytes to encrypt from . - /// Encrypted data + /// + /// The encrypted data. + /// public override byte[] Encrypt(byte[] input, int offset, int length) { if (length % _blockSize > 0) @@ -112,7 +114,9 @@ public override byte[] Encrypt(byte[] input, int offset, int length) /// Decrypts the specified data. /// /// The data. - /// Decrypted data + /// + /// The decrypted data. + /// public override byte[] Decrypt(byte[] input) { return Decrypt(input, 0, input.Length); diff --git a/src/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs index ed37e4346..e61b5d655 100644 --- a/src/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/CipherDigitalSignature.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Security.Cryptography { /// - /// Implements digital signature where where asymmetric cipher is used, + /// Implements digital signature where where asymmetric cipher is used. /// public abstract class CipherDigitalSignature : DigitalSignature { @@ -33,7 +33,7 @@ protected CipherDigitalSignature(ObjectIdentifier oid, AsymmetricCipher cipher) /// The input. /// The signature. /// - /// if signature was successfully verified; otherwise . + /// if signature was successfully verified; otherwise . /// public override bool Verify(byte[] input, byte[] signature) { diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs index 09e8ab90c..517f2b463 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs @@ -17,7 +17,10 @@ public sealed class AesCipher : BlockCipher private int _rounds; private uint[] _encryptionKey; private uint[] _decryptionKey; - private uint _c0, _c1, _c2, _c3; + private uint _c0; + private uint _c1; + private uint _c2; + private uint _c3; #region Static Definition Tables @@ -583,7 +586,7 @@ public AesCipher(byte[] key, CipherMode mode, CipherPadding padding) /// The number of bytes encrypted. /// /// or is . - /// or is too short. + /// or is too short. public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if (inputBuffer is null) @@ -598,12 +601,12 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC if ((inputOffset + (32 / 2)) > inputBuffer.Length) { - throw new IndexOutOfRangeException("input buffer too short"); + throw new ArgumentException("input buffer too short"); } if ((outputOffset + (32 / 2)) > outputBuffer.Length) { - throw new IndexOutOfRangeException("output buffer too short"); + throw new ArgumentException("output buffer too short"); } _encryptionKey ??= GenerateWorkingKey(isEncryption: true, Key); @@ -644,12 +647,12 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC if ((inputOffset + (32 / 2)) > inputBuffer.Length) { - throw new IndexOutOfRangeException("input buffer too short"); + throw new ArgumentException("input buffer too short"); } if ((outputOffset + (32 / 2)) > outputBuffer.Length) { - throw new IndexOutOfRangeException("output buffer too short"); + throw new ArgumentException("output buffer too short"); } _decryptionKey ??= GenerateWorkingKey(isEncryption: false, Key); @@ -675,26 +678,26 @@ private uint[] GenerateWorkingKey(bool isEncryption, byte[] key) _rounds = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes var W = new uint[(_rounds + 1) * 4]; // 4 words in a block - // - // copy the key into the round key array - // + /* + * Copy the key into the round key array. + */ var t = 0; for (var i = 0; i < key.Length; t++) { - W[(t >> 2) * 4 + (t & 3)] = Pack.LittleEndianToUInt32(key, i); + W[((t >> 2) * 4) + (t & 3)] = Pack.LittleEndianToUInt32(key, i); i += 4; } - // - // while not enough round key material calculated - // calculate new values - // + /* + * Calculate new values while not enough round key material is calculated. + */ + var k = (_rounds + 1) << 2; for (var i = KC; i < k; i++) { - var temp = W[((i - 1) >> 2) * 4 + ((i - 1) & 3)]; + var temp = W[(((i - 1) >> 2) * 4) + ((i - 1) & 3)]; if ((i % KC) == 0) { temp = SubWord(Shift(temp, 8)) ^ Rcon[(i / KC) - 1]; @@ -704,7 +707,7 @@ private uint[] GenerateWorkingKey(bool isEncryption, byte[] key) temp = SubWord(temp); } - W[(i >> 2) * 4 + (i & 3)] = W[((i - KC) >> 2) * 4 + ((i - KC) & 3)] ^ temp; + W[((i >> 2) * 4) + (i & 3)] = W[(((i - KC) >> 2) * 4) + ((i - KC) & 3)] ^ temp; } if (!isEncryption) @@ -713,7 +716,7 @@ private uint[] GenerateWorkingKey(bool isEncryption, byte[] key) { for (var i = 0; i < 4; i++) { - W[j * 4 + i] = InvMcol(W[j * 4 + i]); + W[(j * 4) + i] = InvMcol(W[(j * 4) + i]); } } } @@ -765,74 +768,82 @@ private void PackBlock(byte[] bytes, int off) Pack.UInt32ToLittleEndian(_c3, bytes, off + 12); } +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter private void EncryptBlock(uint[] KW) +#pragma warning restore SA1313 // Parameter names should begin with lower-case letter { int r; uint r0, r1, r2, r3; - _c0 ^= KW[0 * 4 + 0]; - _c1 ^= KW[0 * 4 + 1]; - _c2 ^= KW[0 * 4 + 2]; - _c3 ^= KW[0 * 4 + 3]; + _c0 ^= KW[(0 * 4) + 0]; + _c1 ^= KW[(0 * 4) + 1]; + _c2 ^= KW[(0 * 4) + 2]; + _c3 ^= KW[(0 * 4) + 3]; for (r = 1; r < _rounds - 1;) { - r0 = T0[_c0 & 255] ^ T1[(_c1 >> 8) & 255] ^ T2[(_c2 >> 16) & 255] ^ T3[_c3 >> 24] ^ KW[r * 4 + 0]; - r1 = T0[_c1 & 255] ^ T1[(_c2 >> 8) & 255] ^ T2[(_c3 >> 16) & 255] ^ T3[_c0 >> 24] ^ KW[r * 4 + 1]; - r2 = T0[_c2 & 255] ^ T1[(_c3 >> 8) & 255] ^ T2[(_c0 >> 16) & 255] ^ T3[_c1 >> 24] ^ KW[r * 4 + 2]; - r3 = T0[_c3 & 255] ^ T1[(_c0 >> 8) & 255] ^ T2[(_c1 >> 16) & 255] ^ T3[_c2 >> 24] ^ KW[r++ * 4 + 3]; - _c0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[r3 >> 24] ^ KW[r * 4 + 0]; - _c1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[r0 >> 24] ^ KW[r * 4 + 1]; - _c2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[r1 >> 24] ^ KW[r * 4 + 2]; - _c3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[r2 >> 24] ^ KW[r++ * 4 + 3]; + r0 = T0[_c0 & 255] ^ T1[(_c1 >> 8) & 255] ^ T2[(_c2 >> 16) & 255] ^ T3[_c3 >> 24] ^ KW[(r * 4) + 0]; + r1 = T0[_c1 & 255] ^ T1[(_c2 >> 8) & 255] ^ T2[(_c3 >> 16) & 255] ^ T3[_c0 >> 24] ^ KW[(r * 4) + 1]; + r2 = T0[_c2 & 255] ^ T1[(_c3 >> 8) & 255] ^ T2[(_c0 >> 16) & 255] ^ T3[_c1 >> 24] ^ KW[(r * 4) + 2]; + r3 = T0[_c3 & 255] ^ T1[(_c0 >> 8) & 255] ^ T2[(_c1 >> 16) & 255] ^ T3[_c2 >> 24] ^ KW[(r++ * 4) + 3]; + _c0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[r3 >> 24] ^ KW[(r * 4) + 0]; + _c1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[r0 >> 24] ^ KW[(r * 4) + 1]; + _c2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[r1 >> 24] ^ KW[(r * 4) + 2]; + _c3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[r2 >> 24] ^ KW[(r++ * 4) + 3]; } - r0 = T0[_c0 & 255] ^ T1[(_c1 >> 8) & 255] ^ T2[(_c2 >> 16) & 255] ^ T3[_c3 >> 24] ^ KW[r * 4 + 0]; - r1 = T0[_c1 & 255] ^ T1[(_c2 >> 8) & 255] ^ T2[(_c3 >> 16) & 255] ^ T3[_c0 >> 24] ^ KW[r * 4 + 1]; - r2 = T0[_c2 & 255] ^ T1[(_c3 >> 8) & 255] ^ T2[(_c0 >> 16) & 255] ^ T3[_c1 >> 24] ^ KW[r * 4 + 2]; - r3 = T0[_c3 & 255] ^ T1[(_c0 >> 8) & 255] ^ T2[(_c1 >> 16) & 255] ^ T3[_c2 >> 24] ^ KW[r++ * 4 + 3]; + r0 = T0[_c0 & 255] ^ T1[(_c1 >> 8) & 255] ^ T2[(_c2 >> 16) & 255] ^ T3[_c3 >> 24] ^ KW[(r * 4) + 0]; + r1 = T0[_c1 & 255] ^ T1[(_c2 >> 8) & 255] ^ T2[(_c3 >> 16) & 255] ^ T3[_c0 >> 24] ^ KW[(r * 4) + 1]; + r2 = T0[_c2 & 255] ^ T1[(_c3 >> 8) & 255] ^ T2[(_c0 >> 16) & 255] ^ T3[_c1 >> 24] ^ KW[(r * 4) + 2]; + r3 = T0[_c3 & 255] ^ T1[(_c0 >> 8) & 255] ^ T2[(_c1 >> 16) & 255] ^ T3[_c2 >> 24] ^ KW[(r++ * 4) + 3]; - // the final round's table is a simple function of S so we don't use a whole other four tables for it + /* + * The final round's table is a simple function of S so we don't use a whole other four tables for it. + */ - _c0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[r3 >> 24]) << 24) ^ KW[r * 4 + 0]; - _c1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[r0 >> 24]) << 24) ^ KW[r * 4 + 1]; - _c2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[r1 >> 24]) << 24) ^ KW[r * 4 + 2]; - _c3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[r2 >> 24]) << 24) ^ KW[r * 4 + 3]; + _c0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[r3 >> 24]) << 24) ^ KW[(r * 4) + 0]; + _c1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[r0 >> 24]) << 24) ^ KW[(r * 4) + 1]; + _c2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[r1 >> 24]) << 24) ^ KW[(r * 4) + 2]; + _c3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[r2 >> 24]) << 24) ^ KW[(r * 4) + 3]; } +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter private void DecryptBlock(uint[] KW) +#pragma warning restore SA1313 // Parameter names should begin with lower-case letter { int r; uint r0, r1, r2, r3; - _c0 ^= KW[_rounds * 4 + 0]; - _c1 ^= KW[_rounds * 4 + 1]; - _c2 ^= KW[_rounds * 4 + 2]; - _c3 ^= KW[_rounds * 4 + 3]; + _c0 ^= KW[(_rounds * 4) + 0]; + _c1 ^= KW[(_rounds * 4) + 1]; + _c2 ^= KW[(_rounds * 4) + 2]; + _c3 ^= KW[(_rounds * 4) + 3]; for (r = _rounds - 1; r > 1;) { - r0 = Tinv0[_c0 & 255] ^ Tinv1[(_c3 >> 8) & 255] ^ Tinv2[(_c2 >> 16) & 255] ^ Tinv3[_c1 >> 24] ^ KW[r * 4 + 0]; - r1 = Tinv0[_c1 & 255] ^ Tinv1[(_c0 >> 8) & 255] ^ Tinv2[(_c3 >> 16) & 255] ^ Tinv3[_c2 >> 24] ^ KW[r * 4 + 1]; - r2 = Tinv0[_c2 & 255] ^ Tinv1[(_c1 >> 8) & 255] ^ Tinv2[(_c0 >> 16) & 255] ^ Tinv3[_c3 >> 24] ^ KW[r * 4 + 2]; - r3 = Tinv0[_c3 & 255] ^ Tinv1[(_c2 >> 8) & 255] ^ Tinv2[(_c1 >> 16) & 255] ^ Tinv3[_c0 >> 24] ^ KW[r-- * 4 + 3]; - _c0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[r1 >> 24] ^ KW[r * 4 + 0]; - _c1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[r2 >> 24] ^ KW[r * 4 + 1]; - _c2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ KW[r * 4 + 2]; - _c3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[r0 >> 24] ^ KW[r-- * 4 + 3]; + r0 = Tinv0[_c0 & 255] ^ Tinv1[(_c3 >> 8) & 255] ^ Tinv2[(_c2 >> 16) & 255] ^ Tinv3[_c1 >> 24] ^ KW[(r * 4) + 0]; + r1 = Tinv0[_c1 & 255] ^ Tinv1[(_c0 >> 8) & 255] ^ Tinv2[(_c3 >> 16) & 255] ^ Tinv3[_c2 >> 24] ^ KW[(r * 4) + 1]; + r2 = Tinv0[_c2 & 255] ^ Tinv1[(_c1 >> 8) & 255] ^ Tinv2[(_c0 >> 16) & 255] ^ Tinv3[_c3 >> 24] ^ KW[(r * 4) + 2]; + r3 = Tinv0[_c3 & 255] ^ Tinv1[(_c2 >> 8) & 255] ^ Tinv2[(_c1 >> 16) & 255] ^ Tinv3[_c0 >> 24] ^ KW[(r-- * 4) + 3]; + _c0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[r1 >> 24] ^ KW[(r * 4) + 0]; + _c1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[r2 >> 24] ^ KW[(r * 4) + 1]; + _c2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ KW[(r * 4) + 2]; + _c3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[r0 >> 24] ^ KW[(r-- * 4) + 3]; } - r0 = Tinv0[_c0 & 255] ^ Tinv1[(_c3 >> 8) & 255] ^ Tinv2[(_c2 >> 16) & 255] ^ Tinv3[_c1 >> 24] ^ KW[r * 4 + 0]; - r1 = Tinv0[_c1 & 255] ^ Tinv1[(_c0 >> 8) & 255] ^ Tinv2[(_c3 >> 16) & 255] ^ Tinv3[_c2 >> 24] ^ KW[r * 4 + 1]; - r2 = Tinv0[_c2 & 255] ^ Tinv1[(_c1 >> 8) & 255] ^ Tinv2[(_c0 >> 16) & 255] ^ Tinv3[_c3 >> 24] ^ KW[r * 4 + 2]; - r3 = Tinv0[_c3 & 255] ^ Tinv1[(_c2 >> 8) & 255] ^ Tinv2[(_c1 >> 16) & 255] ^ Tinv3[_c0 >> 24] ^ KW[r * 4 + 3]; + r0 = Tinv0[_c0 & 255] ^ Tinv1[(_c3 >> 8) & 255] ^ Tinv2[(_c2 >> 16) & 255] ^ Tinv3[_c1 >> 24] ^ KW[(r * 4) + 0]; + r1 = Tinv0[_c1 & 255] ^ Tinv1[(_c0 >> 8) & 255] ^ Tinv2[(_c3 >> 16) & 255] ^ Tinv3[_c2 >> 24] ^ KW[(r * 4) + 1]; + r2 = Tinv0[_c2 & 255] ^ Tinv1[(_c1 >> 8) & 255] ^ Tinv2[(_c0 >> 16) & 255] ^ Tinv3[_c3 >> 24] ^ KW[(r * 4) + 2]; + r3 = Tinv0[_c3 & 255] ^ Tinv1[(_c2 >> 8) & 255] ^ Tinv2[(_c1 >> 16) & 255] ^ Tinv3[_c0 >> 24] ^ KW[(r * 4) + 3]; - // the final round's table is a simple function of Si so we don't use a whole other four tables for it + /* + * The final round's table is a simple function of Si so we don't use a whole other four tables for it. + */ - _c0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[r1 >> 24]) << 24) ^ KW[0 * 4 + 0]; - _c1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[r2 >> 24]) << 24) ^ KW[0 * 4 + 1]; - _c2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[r3 >> 24]) << 24) ^ KW[0 * 4 + 2]; - _c3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[r0 >> 24]) << 24) ^ KW[0 * 4 + 3]; + _c0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[r1 >> 24]) << 24) ^ KW[(0 * 4) + 0]; + _c1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[r2 >> 24]) << 24) ^ KW[(0 * 4) + 1]; + _c2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[r3 >> 24]) << 24) ^ KW[(0 * 4) + 2]; + _c3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[r0 >> 24]) << 24) ^ KW[(0 * 4) + 3]; } } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs index 5bfbd011e..41387ee02 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Arc4Cipher.cs @@ -3,14 +3,16 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers { /// - /// Implements ARCH4 cipher algorithm + /// Implements ARCH4 cipher algorithm. /// public sealed class Arc4Cipher : StreamCipher { - private static readonly int STATE_LENGTH = 256; +#pragma warning disable SA1310 // Field names should not contain underscore + private const int STATE_LENGTH = 256; +#pragma warning restore SA1310 // Field names should not contain underscore /// - /// Holds the state of the RC4 engine + /// Holds the state of the RC4 engine. /// private byte[] _engineState; @@ -119,21 +121,19 @@ public override byte[] Decrypt(byte[] input) /// public override byte[] Decrypt(byte[] input, int offset, int length) { - var output = new byte[length]; - _ = ProcessBytes(input, offset, length, output, 0); - return output; + return Encrypt(input, offset, length); } private int ProcessBytes(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { if ((inputOffset + inputCount) > inputBuffer.Length) { - throw new IndexOutOfRangeException("input buffer too short"); + throw new ArgumentException("input buffer too short"); } if ((outputOffset + inputCount) > outputBuffer.Length) { - throw new IndexOutOfRangeException("output buffer too short"); + throw new ArgumentException("output buffer too short"); } for (var i = 0; i < inputCount; i++) diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs index b2e082058..6e04c999c 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/BlowfishCipher.cs @@ -8,6 +8,12 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers /// public sealed class BlowfishCipher : BlockCipher { + private const int Rounds = 16; + + private const int SboxSk = 256; + + private const int PSize = Rounds + 2; + #region Static reference tables private static readonly uint[] KP = @@ -293,19 +299,16 @@ public sealed class BlowfishCipher : BlockCipher #endregion - private const int Rounds = 16; - - private const int SboxSk = 256; - - private const int PSize = Rounds + 2; - /// - /// The s-boxes + /// The s-boxes. /// - private readonly uint[] _s0, _s1, _s2, _s3; + private readonly uint[] _s0; + private readonly uint[] _s1; + private readonly uint[] _s2; + private readonly uint[] _s3; /// - /// The p-array + /// The p-array. /// private readonly uint[] _p; diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs index fa114bfeb..d23887856 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/CastCipher.cs @@ -4,21 +4,21 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers { /// - /// Implements CAST cipher algorithm + /// Implements CAST cipher algorithm. /// public sealed class CastCipher : BlockCipher { - private static readonly int MaxRounds = 16; + private const int MaxRounds = 16; - private static readonly int RedRounds = 12; + private const int RedRounds = 12; /// - /// The rotating round key + /// The rotating round key. /// private readonly int[] _kr = new int[17]; /// - /// The masking round key + /// The masking round key. /// private readonly uint[] _km = new uint[17]; @@ -58,9 +58,11 @@ public CastCipher(byte[] key, CipherMode mode, CipherPadding padding) /// public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - // process the input block - // batch the units up into a 32 bit chunk and go for it - // the array is in bytes, the increment is 8x8 bits = 64 + /* + * process the input block + * batch the units up into a 32 bit chunk and go for it + * the array is in bytes, the increment is 8x8 bits = 64 + */ var l0 = Pack.BigEndianToUInt32(inputBuffer, inputOffset); var r0 = Pack.BigEndianToUInt32(inputBuffer, inputOffset + 4); @@ -575,7 +577,6 @@ private void SetKey(byte[] key) /// The input to be processed. /// The mask to be used from Km[n]. /// The rotation value to be used. - /// private static uint F1(uint d, uint kmi, int kri) { var I = kmi + d; @@ -589,7 +590,6 @@ private static uint F1(uint d, uint kmi, int kri) /// The input to be processed. /// The mask to be used from Km[n]. /// The rotation value to be used. - /// private static uint F2(uint d, uint kmi, int kri) { var I = kmi ^ d; @@ -603,7 +603,6 @@ private static uint F2(uint d, uint kmi, int kri) /// The input to be processed. /// The mask to be used from Km[n]. /// The rotation value to be used. - /// private static uint F3(uint d, uint kmi, int kri) { var I = kmi - d; diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/CipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/CipherMode.cs index 7352a12f0..490756aff 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/CipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/CipherMode.cs @@ -3,10 +3,12 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers { /// - /// Base class for cipher mode implementations + /// Base class for cipher mode implementations. /// public abstract class CipherMode { +#pragma warning disable SA1401 // Fields should be private +#pragma warning disable SA1306 // Field names should begin with lower-case letter /// /// Gets the cipher. /// @@ -21,6 +23,8 @@ public abstract class CipherMode /// Holds block size of the cipher. /// protected int _blockSize; +#pragma warning restore SA1306 // Field names should begin with lower-case letter +#pragma warning restore SA1401 // Fields should be private /// /// Initializes a new instance of the class. diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/CipherPadding.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/CipherPadding.cs index 5013865cb..914babc11 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/CipherPadding.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/CipherPadding.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet.Security.Cryptography.Ciphers { /// - /// Base class for cipher padding implementations + /// Base class for cipher padding implementations. /// public abstract class CipherPadding { diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs index aac593534..f2d2e4035 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/DesCipher.cs @@ -12,7 +12,7 @@ public class DesCipher : BlockCipher private int[] _decryptionKey; - private static readonly short[] Bytebit = {128, 64, 32, 16, 8, 4, 2, 1}; + private static readonly short[] Bytebit = { 128, 64, 32, 16, 8, 4, 2, 1 }; private static readonly int[] Bigbyte = { @@ -237,12 +237,12 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC { if ((inputOffset + BlockSize) > inputBuffer.Length) { - throw new IndexOutOfRangeException("input buffer too short"); + throw new ArgumentException("input buffer too short"); } if ((outputOffset + BlockSize) > outputBuffer.Length) { - throw new IndexOutOfRangeException("output buffer too short"); + throw new ArgumentException("output buffer too short"); } _encryptionKey ??= GenerateWorkingKey(encrypting: true, Key); @@ -267,12 +267,12 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC { if ((inputOffset + BlockSize) > inputBuffer.Length) { - throw new IndexOutOfRangeException("input buffer too short"); + throw new ArgumentException("input buffer too short"); } if ((outputOffset + BlockSize) > outputBuffer.Length) { - throw new IndexOutOfRangeException("output buffer too short"); + throw new ArgumentException("output buffer too short"); } _decryptionKey ??= GenerateWorkingKey(encrypting: false, Key); @@ -300,7 +300,7 @@ protected int[] GenerateWorkingKey(bool encrypting, byte[] key) { int l = Pc1[j]; - pc1m[j] = ((key[(uint)l >> 3] & Bytebit[l & 07]) != 0); + pc1m[j] = (key[(uint) l >> 3] & Bytebit[l & 07]) != 0; } for (var i = 0; i < 16; i++) @@ -359,9 +359,10 @@ protected int[] GenerateWorkingKey(bool encrypting, byte[] key) } } - // - // store the processed key - // + /* + * store the processed key + */ + for (var i = 0; i != 32; i += 2) { var i1 = newKey[i]; @@ -428,24 +429,24 @@ protected static void DesFunc(int[] wKey, byte[] input, int inOff, byte[] outByt for (var round = 0; round < 8; round++) { work = (right << 28) | (right >> 4); - work ^= (uint)wKey[round * 4 + 0]; + work ^= (uint)wKey[(round * 4) + 0]; var fval = Sp7[work & 0x3f]; fval |= Sp5[(work >> 8) & 0x3f]; fval |= Sp3[(work >> 16) & 0x3f]; fval |= Sp1[(work >> 24) & 0x3f]; - work = right ^ (uint) wKey[round * 4 + 1]; + work = right ^ (uint) wKey[(round * 4) + 1]; fval |= Sp8[work & 0x3f]; fval |= Sp6[(work >> 8) & 0x3f]; fval |= Sp4[(work >> 16) & 0x3f]; fval |= Sp2[(work >> 24) & 0x3f]; left ^= fval; work = (left << 28) | (left >> 4); - work ^= (uint)wKey[round * 4 + 2]; + work ^= (uint)wKey[(round * 4) + 2]; fval = Sp7[work & 0x3f]; fval |= Sp5[(work >> 8) & 0x3f]; fval |= Sp3[(work >> 16) & 0x3f]; fval |= Sp1[(work >> 24) & 0x3f]; - work = left ^ (uint)wKey[round * 4 + 3]; + work = left ^ (uint)wKey[(round * 4) + 3]; fval |= Sp8[work & 0x3f]; fval |= Sp6[(work >> 8) & 0x3f]; fval |= Sp4[(work >> 16) & 0x3f]; diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CbcCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CbcCipherMode.cs index de07141c3..a2b9243d4 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CbcCipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CbcCipherMode.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers.Modes { /// - /// Implements CBC cipher mode + /// Implements CBC cipher mode. /// public class CbcCipherMode : CipherMode { diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CfbCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CfbCipherMode.cs index ae889e875..23a4bb2f7 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CfbCipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CfbCipherMode.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers.Modes { /// - /// Implements CFB cipher mode + /// Implements CFB cipher mode. /// public class CfbCipherMode : CipherMode { diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CtrCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CtrCipherMode.cs index 90149f575..a0ae5010b 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CtrCipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/CtrCipherMode.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers.Modes { /// - /// Implements CTR cipher mode + /// Implements CTR cipher mode. /// public class CtrCipherMode : CipherMode { @@ -77,35 +77,7 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC /// public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - if (inputBuffer.Length - inputOffset < _blockSize) - { - throw new ArgumentException("Invalid input buffer"); - } - - if (outputBuffer.Length - outputOffset < _blockSize) - { - throw new ArgumentException("Invalid output buffer"); - } - - if (inputCount != _blockSize) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); - } - - _ = Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); - - for (var i = 0; i < _blockSize; i++) - { - outputBuffer[outputOffset + i] = (byte)(_ivOutput[i] ^ inputBuffer[inputOffset + i]); - } - - var j = IV.Length; - while (--j >= 0 && ++IV[j] == 0) - { - // Intentionally empty block - } - - return _blockSize; + return EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); } } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs index 1f321f454..e87dc9d32 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs @@ -4,7 +4,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers.Modes { /// - /// Implements OFB cipher mode + /// Implements OFB cipher mode. /// public class OfbCipherMode : CipherMode { @@ -74,32 +74,7 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC /// public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - if (inputBuffer.Length - inputOffset < _blockSize) - { - throw new ArgumentException("Invalid input buffer"); - } - - if (outputBuffer.Length - outputOffset < _blockSize) - { - throw new ArgumentException("Invalid output buffer"); - } - - if (inputCount != _blockSize) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "inputCount must be {0}.", _blockSize)); - } - - _ = Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); - - for (var i = 0; i < _blockSize; i++) - { - outputBuffer[outputOffset + i] = (byte)(_ivOutput[i] ^ inputBuffer[inputOffset + i]); - } - - Buffer.BlockCopy(IV, _blockSize, IV, 0, IV.Length - _blockSize); - Buffer.BlockCopy(outputBuffer, outputOffset, IV, IV.Length - _blockSize, _blockSize); - - return _blockSize; + return EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); } } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS7Padding.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS7Padding.cs index cfe0ae9a3..eb950abf4 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS7Padding.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Paddings/PKCS7Padding.cs @@ -3,7 +3,7 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers.Paddings { /// - /// Implements PKCS7 cipher padding + /// Implements PKCS7 cipher padding. /// public class PKCS7Padding : CipherPadding { diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs index 749083c03..8cb58a93e 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/RsaCipher.cs @@ -36,7 +36,7 @@ public override byte[] Encrypt(byte[] input, int offset, int length) // Calculate signature var bitLength = _key.Modulus.BitLength; - var paddedBlock = new byte[bitLength / 8 + (bitLength % 8 > 0 ? 1 : 0) - 1]; + var paddedBlock = new byte[(bitLength / 8) + (bitLength % 8 > 0 ? 1 : 0) - 1]; paddedBlock[0] = 0x01; for (var i = 1; i < paddedBlock.Length - length - 1; i++) @@ -141,7 +141,7 @@ private byte[] Transform(byte[] data, int offset, int length) var h = BigInteger.PositiveMod((mP - mQ) * _key.InverseQ, _key.P); - var m = h * _key.Q + mQ; + var m = (h * _key.Q) + mQ; var rInv = BigInteger.ModInverse(random, _key.Modulus); diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs index c8032b00b..6f19e176d 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/SerpentCipher.cs @@ -871,7 +871,7 @@ private void Sb3(int a, int b, int c, int d) } /// - /// InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms + /// InvS3 - { 0, 9,10, 7,11,14, 6,13, 3, 5,12, 2, 4, 8,15, 1 } - 15 terms. /// /// A. /// The b. diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs index eef40c0e6..eb1c0839d 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/TripleDesCipher.cs @@ -41,12 +41,12 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC { if ((inputOffset + BlockSize) > inputBuffer.Length) { - throw new IndexOutOfRangeException("input buffer too short"); + throw new ArgumentException("input buffer too short"); } if ((outputOffset + BlockSize) > outputBuffer.Length) { - throw new IndexOutOfRangeException("output buffer too short"); + throw new ArgumentException("output buffer too short"); } if (_encryptionKey1 is null || _encryptionKey2 is null || _encryptionKey3 is null) @@ -97,12 +97,12 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC { if ((inputOffset + BlockSize) > inputBuffer.Length) { - throw new IndexOutOfRangeException("input buffer too short"); + throw new ArgumentException("input buffer too short"); } if ((outputOffset + BlockSize) > outputBuffer.Length) { - throw new IndexOutOfRangeException("output buffer too short"); + throw new ArgumentException("output buffer too short"); } if (_decryptionKey1 is null || _decryptionKey2 is null || _decryptionKey3 is null) diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs index 8ecf6793a..7ef039cc3 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/TwofishCipher.cs @@ -7,6 +7,72 @@ namespace Renci.SshNet.Security.Cryptography.Ciphers /// public sealed class TwofishCipher : BlockCipher { + /** + * Define the fixed p0/p1 permutations used in keyed S-box lookup. + * By changing the following constant definitions, the S-boxes will + * automatically Get changed in the Twofish engine. + */ +#pragma warning disable SA1310 // Field names should not contain underscore + private const int P_00 = 1; + private const int P_01 = 0; + private const int P_02 = 0; + private const int P_03 = P_01 ^ 1; + private const int P_04 = 1; + + private const int P_10 = 0; + private const int P_11 = 0; + private const int P_12 = 1; + private const int P_13 = P_11 ^ 1; + private const int P_14 = 0; + + private const int P_20 = 1; + private const int P_21 = 1; + private const int P_22 = 0; + private const int P_23 = P_21 ^ 1; + private const int P_24 = 0; + + private const int P_30 = 0; + private const int P_31 = 1; + private const int P_32 = 1; + private const int P_33 = P_31 ^ 1; + private const int P_34 = 1; + + /* Primitive polynomial for GF(256) */ + private const int GF256_FDBK = 0x169; + private const int GF256_FDBK_2 = GF256_FDBK / 2; + private const int GF256_FDBK_4 = GF256_FDBK / 4; + + private const int RS_GF_FDBK = 0x14D; // field generator + + private const int ROUNDS = 16; + private const int MAX_ROUNDS = 16; // bytes = 128 bits + private const int MAX_KEY_BITS = 256; + + private const int INPUT_WHITEN = 0; + private const int OUTPUT_WHITEN = INPUT_WHITEN + (16 / 4); // 4 + private const int ROUND_SUBKEYS = OUTPUT_WHITEN + (16 / 4); // 8 + + private const int TOTAL_SUBKEYS = ROUND_SUBKEYS + (2 * MAX_ROUNDS); // 40 + + private const int SK_STEP = 0x02020202; + private const int SK_BUMP = 0x01010101; + private const int SK_ROTL = 9; +#pragma warning restore SA1310 // Field names should not contain underscore + + private readonly int[] _gMDS0 = new int[MAX_KEY_BITS]; + private readonly int[] _gMDS1 = new int[MAX_KEY_BITS]; + private readonly int[] _gMDS2 = new int[MAX_KEY_BITS]; + private readonly int[] _gMDS3 = new int[MAX_KEY_BITS]; + + private readonly int _k64Cnt; + + /* + * _gSubKeys[] and _gSBox[] are eventually used in the + * encryption and decryption methods. + */ + private int[] _gSubKeys; + private int[] _gSBox; + /// /// Initializes a new instance of the class. /// @@ -80,13 +146,13 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC var t1 = Fe32_3(_gSBox, x1); x2 ^= t0 + t1 + _gSubKeys[k++]; x2 = (int)((uint)x2 >> 1) | x2 << 31; - x3 = (x3 << 1 | (int)((uint)x3 >> 31)) ^ (t0 + 2 * t1 + _gSubKeys[k++]); + x3 = (x3 << 1 | (int)((uint)x3 >> 31)) ^ (t0 + (2 * t1) + _gSubKeys[k++]); t0 = Fe32_0(_gSBox, x2); t1 = Fe32_3(_gSBox, x3); x0 ^= t0 + t1 + _gSubKeys[k++]; x0 = (int)((uint)x0 >> 1) | x0 << 31; - x1 = (x1 << 1 | (int)((uint)x1 >> 31)) ^ (t0 + 2 * t1 + _gSubKeys[k++]); + x1 = (x1 << 1 | (int)((uint)x1 >> 31)) ^ (t0 + (2 * t1) + _gSubKeys[k++]); } Bits32ToBytes(x2 ^ _gSubKeys[OUTPUT_WHITEN], outputBuffer, outputOffset); @@ -115,20 +181,20 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC var x0 = BytesTo32Bits(inputBuffer, inputOffset + 8) ^ _gSubKeys[OUTPUT_WHITEN + 2]; var x1 = BytesTo32Bits(inputBuffer, inputOffset + 12) ^ _gSubKeys[OUTPUT_WHITEN + 3]; - var k = ROUND_SUBKEYS + 2 * ROUNDS - 1; + var k = ROUND_SUBKEYS + (2 * ROUNDS) - 1; for (var r = 0; r < ROUNDS; r += 2) { var t0 = Fe32_0(_gSBox, x2); var t1 = Fe32_3(_gSBox, x3); - x1 ^= t0 + 2 * t1 + _gSubKeys[k--]; - x0 = (x0 << 1 | (int)((uint)x0 >> 31)) ^ (t0 + t1 + _gSubKeys[k--]); - x1 = (int)((uint)x1 >> 1) | x1 << 31; + x1 ^= t0 + (2 * t1) + _gSubKeys[k--]; + x0 = (x0 << 1 | (int) ((uint) x0 >> 31)) ^ (t0 + t1 + _gSubKeys[k--]); + x1 = (int) ((uint) x1 >> 1) | x1 << 31; t0 = Fe32_0(_gSBox, x0); t1 = Fe32_3(_gSBox, x1); - x3 ^= t0 + 2 * t1 + _gSubKeys[k--]; - x2 = (x2 << 1 | (int)((uint)x2 >> 31)) ^ (t0 + t1 + _gSubKeys[k--]); - x3 = (int)((uint)x3 >> 1) | x3 << 31; + x3 ^= t0 + (2 * t1) + _gSubKeys[k--]; + x2 = (x2 << 1 | (int) ((uint) x2 >> 31)) ^ (t0 + t1 + _gSubKeys[k--]); + x3 = (int) ((uint) x3 >> 1) | x3 << 31; } Bits32ToBytes(x0 ^ _gSubKeys[INPUT_WHITEN], outputBuffer, outputOffset); @@ -178,70 +244,6 @@ public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputC 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56, 0x55, 0x09, 0xBE, 0x91 }; - /** - * Define the fixed p0/p1 permutations used in keyed S-box lookup. - * By changing the following constant definitions, the S-boxes will - * automatically Get changed in the Twofish engine. - */ - private const int P_00 = 1; - private const int P_01 = 0; - private const int P_02 = 0; - private const int P_03 = P_01 ^ 1; - private const int P_04 = 1; - - private const int P_10 = 0; - private const int P_11 = 0; - private const int P_12 = 1; - private const int P_13 = P_11 ^ 1; - private const int P_14 = 0; - - private const int P_20 = 1; - private const int P_21 = 1; - private const int P_22 = 0; - private const int P_23 = P_21 ^ 1; - private const int P_24 = 0; - - private const int P_30 = 0; - private const int P_31 = 1; - private const int P_32 = 1; - private const int P_33 = P_31 ^ 1; - private const int P_34 = 1; - - /* Primitive polynomial for GF(256) */ - private const int GF256_FDBK = 0x169; - private const int GF256_FDBK_2 = GF256_FDBK / 2; - private const int GF256_FDBK_4 = GF256_FDBK / 4; - - private const int RS_GF_FDBK = 0x14D; // field generator - - private const int ROUNDS = 16; - private const int MAX_ROUNDS = 16; // bytes = 128 bits - private const int MAX_KEY_BITS = 256; - - private const int INPUT_WHITEN = 0; - private const int OUTPUT_WHITEN = INPUT_WHITEN + 16 / 4; // 4 - private const int ROUND_SUBKEYS = OUTPUT_WHITEN + 16 / 4;// 8 - - private const int TOTAL_SUBKEYS = ROUND_SUBKEYS + 2 * MAX_ROUNDS;// 40 - - private const int SK_STEP = 0x02020202; - private const int SK_BUMP = 0x01010101; - private const int SK_ROTL = 9; - - private readonly int[] _gMDS0 = new int[MAX_KEY_BITS]; - private readonly int[] _gMDS1 = new int[MAX_KEY_BITS]; - private readonly int[] _gMDS2 = new int[MAX_KEY_BITS]; - private readonly int[] _gMDS3 = new int[MAX_KEY_BITS]; - - private readonly int _k64Cnt; - - /** - * _gSubKeys[] and _gSBox[] are eventually used in the - * encryption and decryption methods. - */ - private int[] _gSubKeys; - private int[] _gSBox; - private void SetKey(byte[] key) { var k32e = new int[MAX_KEY_BITS / 64]; // 4 @@ -285,7 +287,7 @@ private void SetKey(byte[] key) a += b; _gSubKeys[i * 2] = a; a += b; - _gSubKeys[i * 2 + 1] = a << SK_ROTL | (int)((uint)a >> (32 - SK_ROTL)); + _gSubKeys[(i * 2) + 1] = a << SK_ROTL | (int)((uint)a >> (32 - SK_ROTL)); } /* @@ -305,28 +307,28 @@ private void SetKey(byte[] key) switch (_k64Cnt & 3) { case 1: - _gSBox[i * 2] = _gMDS0[(P[P_01 * 256 + b0] & 0xff) ^ M_b0(k0)]; - _gSBox[i * 2 + 1] = _gMDS1[(P[P_11 * 256 + b1] & 0xff) ^ M_b1(k0)]; - _gSBox[i * 2 + 0x200] = _gMDS2[(P[P_21 * 256 + b2] & 0xff) ^ M_b2(k0)]; - _gSBox[i * 2 + 0x201] = _gMDS3[(P[P_31 * 256 + b3] & 0xff) ^ M_b3(k0)]; + _gSBox[i * 2] = _gMDS0[(P[(P_01 * 256) + b0] & 0xff) ^ M_b0(k0)]; + _gSBox[(i * 2) + 1] = _gMDS1[(P[(P_11 * 256) + b1] & 0xff) ^ M_b1(k0)]; + _gSBox[(i * 2) + 0x200] = _gMDS2[(P[(P_21 * 256) + b2] & 0xff) ^ M_b2(k0)]; + _gSBox[(i * 2) + 0x201] = _gMDS3[(P[(P_31 * 256) + b3] & 0xff) ^ M_b3(k0)]; break; case 0: /* 256 bits of key */ - b0 = (P[P_04 * 256 + b0] & 0xff) ^ M_b0(k3); - b1 = (P[P_14 * 256 + b1] & 0xff) ^ M_b1(k3); - b2 = (P[P_24 * 256 + b2] & 0xff) ^ M_b2(k3); - b3 = (P[P_34 * 256 + b3] & 0xff) ^ M_b3(k3); + b0 = (P[(P_04 * 256) + b0] & 0xff) ^ M_b0(k3); + b1 = (P[(P_14 * 256) + b1] & 0xff) ^ M_b1(k3); + b2 = (P[(P_24 * 256) + b2] & 0xff) ^ M_b2(k3); + b3 = (P[(P_34 * 256) + b3] & 0xff) ^ M_b3(k3); goto case 3; case 3: - b0 = (P[P_03 * 256 + b0] & 0xff) ^ M_b0(k2); - b1 = (P[P_13 * 256 + b1] & 0xff) ^ M_b1(k2); - b2 = (P[P_23 * 256 + b2] & 0xff) ^ M_b2(k2); - b3 = (P[P_33 * 256 + b3] & 0xff) ^ M_b3(k2); + b0 = (P[(P_03 * 256) + b0] & 0xff) ^ M_b0(k2); + b1 = (P[(P_13 * 256) + b1] & 0xff) ^ M_b1(k2); + b2 = (P[(P_23 * 256) + b2] & 0xff) ^ M_b2(k2); + b3 = (P[(P_33 * 256) + b3] & 0xff) ^ M_b3(k2); goto case 2; case 2: - _gSBox[i * 2] = _gMDS0[(P[P_01 * 256 + (P[P_02 * 256 + b0] & 0xff) ^ M_b0(k1)] & 0xff) ^ M_b0(k0)]; - _gSBox[i * 2 + 1] = _gMDS1[(P[P_11 * 256 + (P[P_12 * 256 + b1] & 0xff) ^ M_b1(k1)] & 0xff) ^ M_b1(k0)]; - _gSBox[i * 2 + 0x200] = _gMDS2[(P[P_21 * 256 + (P[P_22 * 256 + b2] & 0xff) ^ M_b2(k1)] & 0xff) ^ M_b2(k0)]; - _gSBox[i * 2 + 0x201] = _gMDS3[(P[P_31 * 256 + (P[P_32 * 256 + b3] & 0xff) ^ M_b3(k1)] & 0xff) ^ M_b3(k0)]; + _gSBox[i * 2] = _gMDS0[(P[(P_01 * 256) + (P[(P_02 * 256) + b0] & 0xff) ^ M_b0(k1)] & 0xff) ^ M_b0(k0)]; + _gSBox[(i * 2) + 1] = _gMDS1[(P[(P_11 * 256) + (P[(P_12 * 256) + b1] & 0xff) ^ M_b1(k1)] & 0xff) ^ M_b1(k0)]; + _gSBox[(i * 2) + 0x200] = _gMDS2[(P[(P_21 * 256) + (P[(P_22 * 256) + b2] & 0xff) ^ M_b2(k1)] & 0xff) ^ M_b2(k0)]; + _gSBox[(i * 2) + 0x201] = _gMDS3[(P[(P_31 * 256) + (P[(P_32 * 256) + b3] & 0xff) ^ M_b3(k1)] & 0xff) ^ M_b3(k0)]; break; } #pragma warning restore IDE0010 // Add missing cases @@ -360,29 +362,29 @@ private int F32(int x, int[] k32) switch (_k64Cnt & 3) { case 1: - result = _gMDS0[(P[P_01 * 256 + b0] & 0xff) ^ M_b0(k0)] ^ - _gMDS1[(P[P_11 * 256 + b1] & 0xff) ^ M_b1(k0)] ^ - _gMDS2[(P[P_21 * 256 + b2] & 0xff) ^ M_b2(k0)] ^ - _gMDS3[(P[P_31 * 256 + b3] & 0xff) ^ M_b3(k0)]; + result = _gMDS0[(P[(P_01 * 256) + b0] & 0xff) ^ M_b0(k0)] ^ + _gMDS1[(P[(P_11 * 256) + b1] & 0xff) ^ M_b1(k0)] ^ + _gMDS2[(P[(P_21 * 256) + b2] & 0xff) ^ M_b2(k0)] ^ + _gMDS3[(P[(P_31 * 256) + b3] & 0xff) ^ M_b3(k0)]; break; case 0: /* 256 bits of key */ - b0 = (P[P_04 * 256 + b0] & 0xff) ^ M_b0(k3); - b1 = (P[P_14 * 256 + b1] & 0xff) ^ M_b1(k3); - b2 = (P[P_24 * 256 + b2] & 0xff) ^ M_b2(k3); - b3 = (P[P_34 * 256 + b3] & 0xff) ^ M_b3(k3); + b0 = (P[(P_04 * 256) + b0] & 0xff) ^ M_b0(k3); + b1 = (P[(P_14 * 256) + b1] & 0xff) ^ M_b1(k3); + b2 = (P[(P_24 * 256) + b2] & 0xff) ^ M_b2(k3); + b3 = (P[(P_34 * 256) + b3] & 0xff) ^ M_b3(k3); goto case 3; case 3: - b0 = (P[P_03 * 256 + b0] & 0xff) ^ M_b0(k2); - b1 = (P[P_13 * 256 + b1] & 0xff) ^ M_b1(k2); - b2 = (P[P_23 * 256 + b2] & 0xff) ^ M_b2(k2); - b3 = (P[P_33 * 256 + b3] & 0xff) ^ M_b3(k2); + b0 = (P[(P_03 * 256) + b0] & 0xff) ^ M_b0(k2); + b1 = (P[(P_13 * 256) + b1] & 0xff) ^ M_b1(k2); + b2 = (P[(P_23 * 256) + b2] & 0xff) ^ M_b2(k2); + b3 = (P[(P_33 * 256) + b3] & 0xff) ^ M_b3(k2); goto case 2; case 2: result = - _gMDS0[(P[P_01 * 256 + (P[P_02 * 256 + b0] & 0xff) ^ M_b0(k1)] & 0xff) ^ M_b0(k0)] ^ - _gMDS1[(P[P_11 * 256 + (P[P_12 * 256 + b1] & 0xff) ^ M_b1(k1)] & 0xff) ^ M_b1(k0)] ^ - _gMDS2[(P[P_21 * 256 + (P[P_22 * 256 + b2] & 0xff) ^ M_b2(k1)] & 0xff) ^ M_b2(k0)] ^ - _gMDS3[(P[P_31 * 256 + (P[P_32 * 256 + b3] & 0xff) ^ M_b3(k1)] & 0xff) ^ M_b3(k0)]; + _gMDS0[(P[(P_01 * 256) + (P[(P_02 * 256) + b0] & 0xff) ^ M_b0(k1)] & 0xff) ^ M_b0(k0)] ^ + _gMDS1[(P[(P_11 * 256) + (P[(P_12 * 256) + b1] & 0xff) ^ M_b1(k1)] & 0xff) ^ M_b1(k0)] ^ + _gMDS2[(P[(P_21 * 256) + (P[(P_22 * 256) + b2] & 0xff) ^ M_b2(k1)] & 0xff) ^ M_b2(k0)] ^ + _gMDS3[(P[(P_31 * 256) + (P[(P_32 * 256) + b3] & 0xff) ^ M_b3(k1)] & 0xff) ^ M_b3(k0)]; break; } #pragma warning restore IDE0010 // Add missing cases @@ -423,14 +425,14 @@ private static int RS_MDS_Encode(int k0, int k1) *
         * G(x) = x^4 + (a+1/a)x^3 + ax^2 + (a+1/a)x + 1
         * 
- * where a = primitive root of field generator 0x14D + * where a = primitive root of field generator 0x14D. *

*/ private static int RS_rem(int x) { - var b = (int)(((uint)x >> 24) & 0xff); + var b = (int) (((uint) x >> 24) & 0xff); var g2 = ((b << 1) ^ ((b & 0x80) != 0 ? RS_GF_FDBK : 0)) & 0xff; - var g3 = ((int)((uint)b >> 1) ^ ((b & 0x01) != 0 ? (int)((uint)RS_GF_FDBK >> 1) : 0)) ^ g2; + var g3 = ((int) ((uint) b >> 1) ^ ((b & 0x01) != 0 ? (int) ((uint) RS_GF_FDBK >> 1) : 0)) ^ g2; return (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b; } @@ -484,18 +486,18 @@ private static int M_b3(int x) private static int Fe32_0(int[] gSBox1, int x) { - return gSBox1[0x000 + 2 * (x & 0xff)] ^ - gSBox1[0x001 + 2 * ((int)((uint)x >> 8) & 0xff)] ^ - gSBox1[0x200 + 2 * ((int)((uint)x >> 16) & 0xff)] ^ - gSBox1[0x201 + 2 * ((int)((uint)x >> 24) & 0xff)]; + return gSBox1[0x000 + (2 * (x & 0xff))] ^ + gSBox1[0x001 + (2 * ((int)((uint)x >> 8) & 0xff))] ^ + gSBox1[0x200 + (2 * ((int)((uint)x >> 16) & 0xff))] ^ + gSBox1[0x201 + (2 * ((int)((uint)x >> 24) & 0xff))]; } private static int Fe32_3(int[] gSBox1, int x) { - return gSBox1[0x000 + 2 * ((int)((uint)x >> 24) & 0xff)] ^ - gSBox1[0x001 + 2 * (x & 0xff)] ^ - gSBox1[0x200 + 2 * ((int)((uint)x >> 8) & 0xff)] ^ - gSBox1[0x201 + 2 * ((int)((uint)x >> 16) & 0xff)]; + return gSBox1[0x000 + (2 * ((int) ((uint) x >> 24) & 0xff))] ^ + gSBox1[0x001 + (2 * (x & 0xff))] ^ + gSBox1[0x200 + (2 * ((int)((uint)x >> 8) & 0xff))] ^ + gSBox1[0x201 + (2 * ((int)((uint)x >> 16) & 0xff))]; } private static int BytesTo32Bits(byte[] b, int p) diff --git a/src/Renci.SshNet/Security/Cryptography/DigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/DigitalSignature.cs index e675fe325..3e7cee7db 100644 --- a/src/Renci.SshNet/Security/Cryptography/DigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/DigitalSignature.cs @@ -1,7 +1,7 @@ 锘縩amespace Renci.SshNet.Security.Cryptography { /// - /// Base class for signature implementations + /// Base class for signature implementations. /// public abstract class DigitalSignature { @@ -10,7 +10,9 @@ public abstract class DigitalSignature ///
/// The input. /// The signature. - /// if signature was successfully verified; otherwise . + /// + /// if signature was successfully verified; otherwise . + /// public abstract bool Verify(byte[] input, byte[] signature); /// diff --git a/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs index 03b4d0169..a5aae17c0 100644 --- a/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/DsaDigitalSignature.cs @@ -80,10 +80,10 @@ public override bool Verify(byte[] input, byte[] signature) var w = BigInteger.ModInverse(s, _key.Q); // Calculate u1 = H(m)路w mod q - var u1 = hm * w % _key.Q; + var u1 = (hm * w) % _key.Q; // Calculate u2 = r * w mod q - var u2 = r * w % _key.Q; + var u2 = (r * w) % _key.Q; u1 = BigInteger.ModPow(_key.G, u1, _key.P); u2 = BigInteger.ModPow(_key.Y, u2, _key.P); diff --git a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs index cdd0c4def..65c6fceec 100644 --- a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs @@ -160,7 +160,7 @@ public void Dispose() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// to release both managed and unmanaged resources; to release only unmanaged resources. protected virtual void Dispose(bool disposing) diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs index 1e8e21bce..2d3cdb956 100644 --- a/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/ED25519DigitalSignature.cs @@ -64,7 +64,7 @@ public void Dispose() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// to release both managed and unmanaged resources; to release only unmanaged resources. protected virtual void Dispose(bool disposing) diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs index 48c3a74b4..bb0037945 100644 --- a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs @@ -11,17 +11,21 @@ namespace Renci.SshNet.Security /// public class ED25519Key : Key, IDisposable { - private ED25519DigitalSignature _digitalSignature; - - private byte[] _publicKey = new byte[Ed25519.PublicKeySizeInBytes]; #pragma warning disable IDE1006 // Naming Styles +#pragma warning disable SX1309 // Field names should begin with underscore private readonly byte[] privateKey = new byte[Ed25519.ExpandedPrivateKeySizeInBytes]; +#pragma warning restore SX1309 // Field names should begin with underscore #pragma warning restore IDE1006 // Naming Styles + private ED25519DigitalSignature _digitalSignature; + private byte[] _publicKey = new byte[Ed25519.PublicKeySizeInBytes]; private bool _isDisposed; /// - /// Gets the Key String. + /// Gets the name of the key. /// + /// + /// The name of the key. + /// public override string ToString() { return "ssh-ed25519"; @@ -132,7 +136,7 @@ public void Dispose() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// to release both managed and unmanaged resources; to release only unmanaged resources. protected virtual void Dispose(bool disposing) diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs index 5c9025d54..74f114341 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaDigitalSignature.cs @@ -83,7 +83,7 @@ public void Dispose() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// to release both managed and unmanaged resources; to release only unmanaged resources. protected virtual void Dispose(bool disposing) @@ -106,81 +106,81 @@ protected virtual void Dispose(bool disposing) { Dispose(disposing: false); } - } - internal sealed class SshDataSignature : SshData - { - private readonly int _signature_size; + private sealed class SshDataSignature : SshData + { + private readonly int _signature_size; - private byte[] _signature_r; - private byte[] _signature_s; + private byte[] _signature_r; + private byte[] _signature_s; - public byte[] Signature - { - get + public byte[] Signature { - var signature = new byte[_signature_size]; - Buffer.BlockCopy(_signature_r, 0, signature, 0, _signature_r.Length); - Buffer.BlockCopy(_signature_s, 0, signature, _signature_r.Length, _signature_s.Length); - return signature; + get + { + var signature = new byte[_signature_size]; + Buffer.BlockCopy(_signature_r, 0, signature, 0, _signature_r.Length); + Buffer.BlockCopy(_signature_s, 0, signature, _signature_r.Length, _signature_s.Length); + return signature; + } + set + { + var signed_r = new byte[_signature_size / 2]; + Buffer.BlockCopy(value, 0, signed_r, 0, signed_r.Length); + _signature_r = signed_r.ToBigInteger2().ToByteArray().Reverse(); + + var signed_s = new byte[_signature_size / 2]; + Buffer.BlockCopy(value, signed_r.Length, signed_s, 0, signed_s.Length); + _signature_s = signed_s.ToBigInteger2().ToByteArray().Reverse(); + } } - set - { - var signed_r = new byte[_signature_size / 2]; - Buffer.BlockCopy(value, 0, signed_r, 0, signed_r.Length); - _signature_r = signed_r.ToBigInteger2().ToByteArray().Reverse(); - var signed_s = new byte[_signature_size / 2]; - Buffer.BlockCopy(value, signed_r.Length, signed_s, 0, signed_s.Length); - _signature_s = signed_s.ToBigInteger2().ToByteArray().Reverse(); + public SshDataSignature(int sig_size) + { + _signature_size = sig_size; } - } - public SshDataSignature(int sig_size) - { - _signature_size = sig_size; - } + public SshDataSignature(byte[] data, int sig_size) + { + _signature_size = sig_size; + Load(data); + } - public SshDataSignature(byte[] data, int sig_size) - { - _signature_size = sig_size; - Load(data); - } + protected override void LoadData() + { + _signature_r = ReadBinary().TrimLeadingZeros().Pad(_signature_size / 2); + _signature_s = ReadBinary().TrimLeadingZeros().Pad(_signature_size / 2); + } - protected override void LoadData() - { - _signature_r = ReadBinary().TrimLeadingZeros().Pad(_signature_size / 2); - _signature_s = ReadBinary().TrimLeadingZeros().Pad(_signature_size / 2); - } + protected override void SaveData() + { + WriteBinaryString(_signature_r.ToBigInteger2().ToByteArray().Reverse()); + WriteBinaryString(_signature_s.ToBigInteger2().ToByteArray().Reverse()); + } - protected override void SaveData() - { - WriteBinaryString(_signature_r.ToBigInteger2().ToByteArray().Reverse()); - WriteBinaryString(_signature_s.ToBigInteger2().ToByteArray().Reverse()); - } + public new byte[] ReadBinary() + { + var length = ReadUInt32(); - public new byte[] ReadBinary() - { - var length = ReadUInt32(); + if (length > int.MaxValue) + { + throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Strings longer than {0} is not supported.", int.MaxValue)); + } - if (length > int.MaxValue) - { - throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Strings longer than {0} is not supported.", int.MaxValue)); + return ReadBytes((int) length); } - return ReadBytes((int)length); - } - - protected override int BufferCapacity - { - get + protected override int BufferCapacity { - var capacity = base.BufferCapacity; - capacity += 4; // r length - capacity += _signature_r.Length; // signature r - capacity += 4; // s length - capacity += _signature_s.Length; // signature s - return capacity; + get + { + var capacity = base.BufferCapacity; + capacity += 4; // r length + capacity += _signature_r.Length; // signature r + capacity += 4; // s length + capacity += _signature_s.Length; // signature s + return capacity; + } } } } diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs index fe38dfec2..455bb1363 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -1,12 +1,11 @@ 锘縰sing System; #if NETFRAMEWORK +using System.Globalization; using System.IO; -#endif // NETFRAMEWORK -using System.Text; -#if NETFRAMEWORK using System.Runtime.InteropServices; #endif // NETFRAMEWORK using System.Security.Cryptography; +using System.Text; using Renci.SshNet.Common; using Renci.SshNet.Security.Cryptography; @@ -18,9 +17,11 @@ namespace Renci.SshNet.Security ///
public class EcdsaKey : Key, IDisposable { - internal const string ECDSA_P256_OID_VALUE = "1.2.840.10045.3.1.7"; // Also called nistP256 or secP256r1 - internal const string ECDSA_P384_OID_VALUE = "1.3.132.0.34"; // Also called nistP384 or secP384r1 - internal const string ECDSA_P521_OID_VALUE = "1.3.132.0.35"; // Also called nistP521or secP521r1 +#pragma warning disable SA1310 // Field names should not contain underscore + private const string ECDSA_P256_OID_VALUE = "1.2.840.10045.3.1.7"; // Also called nistP256 or secP256r1 + private const string ECDSA_P384_OID_VALUE = "1.3.132.0.34"; // Also called nistP384 or secP384r1 + private const string ECDSA_P521_OID_VALUE = "1.3.132.0.35"; // Also called nistP521or secP521r1 +#pragma warning restore SA1310 // Field names should not contain underscore private EcdsaDigitalSignature _digitalSignature; private bool _isDisposed; @@ -52,7 +53,7 @@ internal enum KeyBlobMagicNumber internal struct BCRYPT_ECCKEY_BLOB { internal KeyBlobMagicNumber Magic; - internal int cbKey; + internal int CbKey; } #endif @@ -69,7 +70,7 @@ public override string ToString() #if NETFRAMEWORK /// - /// Gets the HashAlgorithm to use + /// Gets the HashAlgorithm to use. /// public CngAlgorithm HashAlgorithm { @@ -84,7 +85,7 @@ public CngAlgorithm HashAlgorithm case 521: return CngAlgorithm.Sha512; default: - throw new SshException("Unknown KeySize: " + Ecdsa.KeySize); + throw new SshException("Unknown KeySize: " + Ecdsa.KeySize.ToString(CultureInfo.InvariantCulture)); } } } @@ -380,6 +381,7 @@ private void Import(string curve_oid, byte[] publickey, byte[] privatekey) bw.Write(privatekey); // d } } + _key = CngKey.Import(blob, privatekey is null ? CngKeyBlobFormat.EccPublicBlob : CngKeyBlobFormat.EccPrivateBlob); Ecdsa = new ECDsaCng(_key); @@ -413,13 +415,13 @@ private void Import(string curve_oid, byte[] publickey, byte[] privatekey) private static string GetCurveOid(string curve_s) { - switch (curve_s.ToLower()) + switch (curve_s.ToUpperInvariant()) { - case "nistp256": + case "NISTP256": return ECDSA_P256_OID_VALUE; - case "nistp384": + case "NISTP384": return ECDSA_P384_OID_VALUE; - case "nistp521": + case "NISTP521": return ECDSA_P521_OID_VALUE; default: throw new SshException("Unexpected Curve Name: " + curve_s); diff --git a/src/Renci.SshNet/Security/Cryptography/HMACMD5.cs b/src/Renci.SshNet/Security/Cryptography/HMACMD5.cs index cd129fe69..bd9585448 100644 --- a/src/Renci.SshNet/Security/Cryptography/HMACMD5.cs +++ b/src/Renci.SshNet/Security/Cryptography/HMACMD5.cs @@ -11,22 +11,29 @@ public class HMACMD5 : System.Security.Cryptography.HMACMD5 private readonly int _hashSize; /// - /// Initializes a with the specified key. + /// Initializes a new instance of the class with the specified key. /// /// The key. public HMACMD5(byte[] key) +#pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms : base(key) +#pragma warning restore CA5351 // Do Not Use Broken Cryptographic Algorithms { +#pragma warning disable MA0056 // Do not call overridable members in constructor _hashSize = base.HashSize; +#pragma warning restore MA0056 // Do not call overridable members in constructor } /// - /// Initializes a with the specified key and size of the computed hash code. + /// Initializes a new instance of the class with the specified key + /// and size of the computed hash code. /// /// The key. /// The size, in bits, of the computed hash code. public HMACMD5(byte[] key, int hashSize) +#pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms : base(key) +#pragma warning restore CA5351 // Do Not Use Broken Cryptographic Algorithms { _hashSize = hashSize; } @@ -50,7 +57,9 @@ public override int HashSize /// protected override byte[] HashFinal() { +#pragma warning disable CA5351 // Do Not Use Broken Cryptographic Algorithms var hash = base.HashFinal(); +#pragma warning restore CA5351 // Do Not Use Broken Cryptographic Algorithms return hash.Take(HashSize / 8); } } diff --git a/src/Renci.SshNet/Security/Cryptography/HMACSHA1.cs b/src/Renci.SshNet/Security/Cryptography/HMACSHA1.cs index 05a9730ed..ca4adfdaf 100644 --- a/src/Renci.SshNet/Security/Cryptography/HMACSHA1.cs +++ b/src/Renci.SshNet/Security/Cryptography/HMACSHA1.cs @@ -16,9 +16,13 @@ public class HMACSHA1 : System.Security.Cryptography.HMACSHA1 ///
/// The key. public HMACSHA1(byte[] key) +#pragma warning disable CA5350 // Do Not Use Weak Cryptographic Algorithms : base(key) +#pragma warning restore CA5350 // Do Not Use Weak Cryptographic Algorithms { +#pragma warning disable MA0056 // Do not call overridable members in constructor _hashSize = base.HashSize; +#pragma warning restore MA0056 // Do not call overridable members in constructor } /// @@ -27,7 +31,9 @@ public HMACSHA1(byte[] key) /// The key. /// The size, in bits, of the computed hash code. public HMACSHA1(byte[] key, int hashSize) +#pragma warning disable CA5350 // Do Not Use Weak Cryptographic Algorithms : base(key) +#pragma warning restore CA5350 // Do Not Use Weak Cryptographic Algorithms { _hashSize = hashSize; } @@ -51,7 +57,9 @@ public override int HashSize /// protected override byte[] HashFinal() { +#pragma warning disable CA5350 // Do Not Use Weak Cryptographic Algorithms var hash = base.HashFinal(); +#pragma warning restore CA5350 // Do Not Use Weak Cryptographic Algorithms return hash.Take(HashSize / 8); } } diff --git a/src/Renci.SshNet/Security/Cryptography/HMACSHA256.cs b/src/Renci.SshNet/Security/Cryptography/HMACSHA256.cs index 2598704e4..20f752a86 100644 --- a/src/Renci.SshNet/Security/Cryptography/HMACSHA256.cs +++ b/src/Renci.SshNet/Security/Cryptography/HMACSHA256.cs @@ -11,17 +11,20 @@ public class HMACSHA256 : System.Security.Cryptography.HMACSHA256 private readonly int _hashSize; /// - /// Initializes a with the specified key. + /// Initializes a new instance of the class with the specified key. /// /// The key. public HMACSHA256(byte[] key) : base(key) { +#pragma warning disable MA0056 // Do not call overridable members in constructor _hashSize = base.HashSize; +#pragma warning restore MA0056 // Do not call overridable members in constructor } /// - /// Initializes a with the specified key and size of the computed hash code. + /// Initializes a new instance of the class with the specified key + /// and size of the computed hash code. /// /// The key. /// The size, in bits, of the computed hash code. @@ -48,7 +51,6 @@ public override int HashSize /// /// The computed hash code. /// - protected override byte[] HashFinal() { var hash = base.HashFinal(); diff --git a/src/Renci.SshNet/Security/Cryptography/HMACSHA384.cs b/src/Renci.SshNet/Security/Cryptography/HMACSHA384.cs index f5f0b26c5..e13d720c8 100644 --- a/src/Renci.SshNet/Security/Cryptography/HMACSHA384.cs +++ b/src/Renci.SshNet/Security/Cryptography/HMACSHA384.cs @@ -11,17 +11,20 @@ public class HMACSHA384 : System.Security.Cryptography.HMACSHA384 private readonly int _hashSize; /// - /// Initializes a with the specified key. + /// Initializes a new instance of the class with the specified key. /// /// The key. public HMACSHA384(byte[] key) : base(key) { +#pragma warning disable MA0056 // Do not call overridable members in constructor _hashSize = base.HashSize; +#pragma warning restore MA0056 // Do not call overridable members in constructor } /// - /// Initializes a with the specified key and size of the computed hash code. + /// Initializes a new instance of the class with the specified key + /// and size of the computed hash code. /// /// The key. /// The size, in bits, of the computed hash code. diff --git a/src/Renci.SshNet/Security/Cryptography/HMACSHA512.cs b/src/Renci.SshNet/Security/Cryptography/HMACSHA512.cs index 72e758155..8d756efef 100644 --- a/src/Renci.SshNet/Security/Cryptography/HMACSHA512.cs +++ b/src/Renci.SshNet/Security/Cryptography/HMACSHA512.cs @@ -11,17 +11,20 @@ public class HMACSHA512 : System.Security.Cryptography.HMACSHA512 private readonly int _hashSize; /// - /// Initializes a with the specified key. + /// Initializes a new instance of the class with the specified key. /// /// The key. public HMACSHA512(byte[] key) : base(key) { +#pragma warning disable MA0056 // Do not call overridable members in constructor _hashSize = base.HashSize; +#pragma warning restore MA0056 // Do not call overridable members in constructor } /// - /// Initializes a with the specified key and size of the computed hash code. + /// Initializes a new instance of the class with the specified key + /// and size of the computed hash code. /// /// The key. /// The size, in bits, of the computed hash code. diff --git a/src/Renci.SshNet/Security/Cryptography/Key.cs b/src/Renci.SshNet/Security/Cryptography/Key.cs index 3110a2b91..81580a1ab 100644 --- a/src/Renci.SshNet/Security/Cryptography/Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/Key.cs @@ -14,7 +14,9 @@ public abstract class Key /// /// Specifies array of big integers that represent private key. /// +#pragma warning disable SA1401 // Fields should be private protected BigInteger[] _privateKey; +#pragma warning restore SA1401 // Fields should be private /// /// Gets the default digital signature implementation for this key. diff --git a/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs b/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs index ccb252efd..00a4898f9 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaDigitalSignature.cs @@ -18,7 +18,8 @@ public class RsaDigitalSignature : CipherDigitalSignature, IDisposable /// The RSA key. public RsaDigitalSignature(RsaKey rsaKey) : this(rsaKey, HashAlgorithmName.SHA1) - { } + { + } /// /// Initializes a new instance of the class. @@ -58,7 +59,7 @@ public void Dispose() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// to release both managed and unmanaged resources; to release only unmanaged resources. protected virtual void Dispose(bool disposing) diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs index 2f1367a29..19c8bedc7 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs @@ -5,15 +5,19 @@ namespace Renci.SshNet.Security { /// - /// Contains RSA private and public key + /// Contains the RSA private and public key. /// public class RsaKey : Key, IDisposable { private bool _isDisposed; + private RsaDigitalSignature _digitalSignature; /// - /// Gets the Key String. + /// Gets the name of the key. /// + /// + /// The name of the key. + /// public override string ToString() { return "ssh-rsa"; @@ -22,6 +26,9 @@ public override string ToString() /// /// Gets the modulus. /// + /// + /// The modulus. + /// public BigInteger Modulus { get @@ -33,6 +40,9 @@ public BigInteger Modulus /// /// Gets the exponent. /// + /// + /// The exponent. + /// public BigInteger Exponent { get @@ -44,6 +54,9 @@ public BigInteger Exponent /// /// Gets the D. /// + /// + /// The D. + /// public BigInteger D { get @@ -60,6 +73,9 @@ public BigInteger D /// /// Gets the P. /// + /// + /// The P. + /// public BigInteger P { get @@ -69,7 +85,6 @@ public BigInteger P return _privateKey[3]; } - return BigInteger.Zero; } } @@ -77,6 +92,9 @@ public BigInteger P /// /// Gets the Q. /// + /// + /// The Q. + /// public BigInteger Q { get @@ -93,6 +111,9 @@ public BigInteger Q /// /// Gets the DP. /// + /// + /// The DP. + /// public BigInteger DP { get @@ -109,6 +130,9 @@ public BigInteger DP /// /// Gets the DQ. /// + /// + /// The DQ. + /// public BigInteger DQ { get @@ -125,6 +149,9 @@ public BigInteger DQ /// /// Gets the inverse Q. /// + /// + /// The inverse Q. + /// public BigInteger InverseQ { get @@ -152,10 +179,8 @@ public override int KeyLength } } - private RsaDigitalSignature _digitalSignature; - /// - /// + /// Gets the digital signature implementation for this key. /// /// /// An implementation of an RSA digital signature using the SHA-1 hash algorithm. @@ -253,7 +278,7 @@ public void Dispose() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// to release both managed and unmanaged resources; to release only unmanaged resources. protected virtual void Dispose(bool disposing) diff --git a/src/Renci.SshNet/Security/GroupExchangeHashData.cs b/src/Renci.SshNet/Security/GroupExchangeHashData.cs index 82b889bb8..921841094 100644 --- a/src/Renci.SshNet/Security/GroupExchangeHashData.cs +++ b/src/Renci.SshNet/Security/GroupExchangeHashData.cs @@ -16,7 +16,6 @@ public string ServerVersion set { _serverVersion = Utf8.GetBytes(value); } } - public string ClientVersion { private get { return Utf8.GetString(_clientVersion, 0, _clientVersion.Length); } diff --git a/src/Renci.SshNet/Security/KeyExchange.cs b/src/Renci.SshNet/Security/KeyExchange.cs index 6d8c53748..5024941bf 100644 --- a/src/Renci.SshNet/Security/KeyExchange.cs +++ b/src/Renci.SshNet/Security/KeyExchange.cs @@ -13,7 +13,7 @@ namespace Renci.SshNet.Security { /// - /// Represents base class for different key exchange algorithm implementations + /// Represents base class for different key exchange algorithm implementations. /// public abstract class KeyExchange : Algorithm, IKeyExchange { @@ -511,7 +511,7 @@ public void Dispose() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// to release both managed and unmanaged resources; to release only unmanaged resources. protected virtual void Dispose(bool disposing) diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs index 5cdba5b4d..4f31514a7 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs @@ -6,10 +6,11 @@ namespace Renci.SshNet.Security { /// - /// Represents base class for Diffie Hellman key exchange algorithm + /// Represents base class for Diffie Hellman key exchange algorithm. /// internal abstract class KeyExchangeDiffieHellman : KeyExchange { +#pragma warning disable SA1401 // Fields should be private /// /// Specifies key exchange group number. /// @@ -26,7 +27,7 @@ internal abstract class KeyExchangeDiffieHellman : KeyExchange protected byte[] _clientPayload; /// - /// Specifies server payload + /// Specifies server payload. /// protected byte[] _serverPayload; @@ -54,6 +55,7 @@ internal abstract class KeyExchangeDiffieHellman : KeyExchange /// Specifies signature data. /// protected byte[] _signature; +#pragma warning restore SA1401 // Fields should be private /// /// Gets the size, in bits, of the computed hash code. diff --git a/src/Renci.SshNet/Security/KeyExchangeEC.cs b/src/Renci.SshNet/Security/KeyExchangeEC.cs index f2ae22fb7..4368affbf 100644 --- a/src/Renci.SshNet/Security/KeyExchangeEC.cs +++ b/src/Renci.SshNet/Security/KeyExchangeEC.cs @@ -4,13 +4,14 @@ namespace Renci.SshNet.Security { internal abstract class KeyExchangeEC : KeyExchange { +#pragma warning disable SA1401 // Fields should be private /// - /// Specifies client payload + /// Specifies client payload. /// protected byte[] _clientPayload; /// - /// Specifies server payload + /// Specifies server payload. /// protected byte[] _serverPayload; @@ -33,6 +34,7 @@ internal abstract class KeyExchangeEC : KeyExchange /// Specifies signature data. /// protected byte[] _signature; +#pragma warning restore SA1401 // Fields should be private /// /// Gets the size, in bits, of the computed hash code. diff --git a/src/Renci.SshNet/Security/KeyExchangeHash.cs b/src/Renci.SshNet/Security/KeyExchangeHashData.cs similarity index 100% rename from src/Renci.SshNet/Security/KeyExchangeHash.cs rename to src/Renci.SshNet/Security/KeyExchangeHashData.cs diff --git a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs index f0d2b41d8..0a0232a58 100644 --- a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs +++ b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs @@ -13,18 +13,27 @@ namespace Renci.SshNet.Security public class KeyHostAlgorithm : HostAlgorithm { /// - /// The key used in this host key algorithm. + /// Gets the key used in this host key algorithm. /// + /// + /// The key used in this host key algorithm. + /// public Key Key { get; private set; } /// - /// The signature implementation used in this host key algorithm. + /// Gets the signature implementation used in this host key algorithm. /// + /// + /// The signature implementation used in this host key algorithm. + /// public DigitalSignature DigitalSignature { get; private set; } /// /// Gets the encoded public key data. /// + /// + /// The encoded public key data. + /// public override byte[] Data { get @@ -202,11 +211,13 @@ protected override int BufferCapacity var capacity = base.BufferCapacity; capacity += 4; // Name length capacity += _name.Length; // Name + foreach (var key in _keys) { capacity += 4; // Key length capacity += key.Length; // Key } + return capacity; } } @@ -246,8 +257,11 @@ protected override void SaveData() internal sealed class SignatureKeyData : SshData { /// - /// Gets or sets the signature format identifier + /// Gets or sets the signature format identifier. /// + /// + /// The signature format identifier. + /// public string AlgorithmName { get; set; } /// diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index 23eef6f78..2d913d072 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -121,6 +121,12 @@ public class Session : ISession /// private readonly object _socketDisposeLock = new object(); + /// + /// Holds an object that is used to ensure only a single thread can connect + /// and lazy initialize the at any given time. + /// + private readonly object _connectAndLazySemaphoreInitLock = new object(); + /// /// Holds metadata about session messages. /// @@ -192,6 +198,10 @@ public class Session : ISession private SemaphoreLight _sessionSemaphore; + private bool _isDisconnectMessageSent; + + private uint _nextChannelNumber; + /// /// Holds connection socket. /// @@ -209,7 +219,7 @@ public SemaphoreLight SessionSemaphore { if (_sessionSemaphore is null) { - lock (this) + lock (_connectAndLazySemaphoreInitLock) { _sessionSemaphore ??= new SemaphoreLight(ConnectionInfo.MaxSessions); } @@ -219,10 +229,6 @@ public SemaphoreLight SessionSemaphore } } - private bool _isDisconnectMessageSent; - - private uint _nextChannelNumber; - /// /// Gets the next channel number. /// @@ -235,7 +241,7 @@ private uint NextChannelNumber { uint result; - lock (this) + lock (_connectAndLazySemaphoreInitLock) { result = _nextChannelNumber++; } @@ -586,7 +592,7 @@ public void Connect() return; } - lock (this) + lock (_connectAndLazySemaphoreInitLock) { // If connected don't connect again if (IsConnected) @@ -635,7 +641,7 @@ public void Connect() // Start incoming request listener // ToDo: Make message pump async, to not consume a thread for every session - ThreadAbstraction.ExecuteThreadLongRunning(MessageListener); + _ = ThreadAbstraction.ExecuteThreadLongRunning(MessageListener); // Wait for key exchange to be completed WaitOnHandle(_keyExchangeCompletedWaitHandle); @@ -747,7 +753,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken) // Start incoming request listener // ToDo: Make message pump async, to not consume a thread for every session - ThreadAbstraction.ExecuteThreadLongRunning(MessageListener); + _ = ThreadAbstraction.ExecuteThreadLongRunning(MessageListener); // Wait for key exchange to be completed WaitOnHandle(_keyExchangeCompletedWaitHandle); @@ -1257,8 +1263,8 @@ private Message ReceiveMessage(Socket socket) var clientHash = _serverMac.ComputeHash(data, 0, data.Length - serverMacLength); var serverHash = data.Take(data.Length - serverMacLength, serverMacLength); - // TODO add IsEqualTo overload that takes left+right index and number of bytes to compare; - // TODO that way we can eliminate the extra allocation of the Take above + // TODO Add IsEqualTo overload that takes left+right index and number of bytes to compare. + // TODO That way we can eliminate the extra allocation of the Take above. if (!serverHash.IsEqualTo(clientHash)) { throw new SshConnectionException("MAC error", DisconnectReason.MacError); @@ -1269,10 +1275,10 @@ private Message ReceiveMessage(Socket socket) { data = _serverDecompression.Decompress(data, messagePayloadOffset, messagePayloadLength); - // data now only contains the decompressed payload, and as such the offset is reset to zero + // Data now only contains the decompressed payload, and as such the offset is reset to zero messagePayloadOffset = 0; - // the length of the payload is now the complete decompressed content + // The length of the payload is now the complete decompressed content messagePayloadLength = data.Length; } @@ -1285,10 +1291,10 @@ private void TrySendDisconnect(DisconnectReason reasonCode, string message) { var disconnectMessage = new DisconnectMessage(reasonCode, message); - // send the disconnect message, but ignore the outcome + // Send the disconnect message, but ignore the outcome _ = TrySendMessage(disconnectMessage); - // mark disconnect message sent regardless of whether the send sctually succeeded + // Mark disconnect message sent regardless of whether the send sctually succeeded _isDisconnectMessageSent = true; } @@ -1440,12 +1446,9 @@ internal void OnNewKeysReceived(NewKeysMessage message) _serverDecompression = _keyExchange.CreateDecompressor(); // Dispose of old KeyExchange object as it is no longer needed. - if (_keyExchange != null) - { - _keyExchange.HostKeyReceived -= KeyExchange_HostKeyReceived; - _keyExchange.Dispose(); - _keyExchange = null; - } + _keyExchange.HostKeyReceived -= KeyExchange_HostKeyReceived; + _keyExchange.Dispose(); + _keyExchange = null; // Enable activated messages that are not key exchange related _sshMessageFactory.EnableActivatedMessages(); @@ -2059,6 +2062,13 @@ IConnectionInfo ISession.ConnectionInfo get { return ConnectionInfo; } } + /// + /// Gets a that can be used to wait for the message listener loop to complete. + /// + /// + /// A that can be used to wait for the message listener loop to complete, or + /// when the session has not been connected. + /// WaitHandle ISession.MessageListenerCompleted { get { return _messageListenerCompleted; } @@ -2089,6 +2099,9 @@ IChannelDirectTcpip ISession.CreateChannelDirectTcpip() /// /// Creates a "forwarded-tcpip" SSH channel. /// + /// The number of the remote channel. + /// The window size of the remote channel. + /// The data packet size of the remote channel. /// /// A new "forwarded-tcpip" SSH channel. /// diff --git a/src/Renci.SshNet/Sftp/Flags.cs b/src/Renci.SshNet/Sftp/Flags.cs index 68ae5b10b..6f0a0e6ca 100644 --- a/src/Renci.SshNet/Sftp/Flags.cs +++ b/src/Renci.SshNet/Sftp/Flags.cs @@ -3,31 +3,44 @@ namespace Renci.SshNet.Sftp { [Flags] +#pragma warning disable S2344 // Enumeration type names should not have "Flags" or "Enum" suffixes +#pragma warning disable MA0062 // Non-flags enums should not be marked with "FlagsAttribute" internal enum Flags +#pragma warning restore MA0062 // Non-flags enums should not be marked with "FlagsAttribute" +#pragma warning restore S2344 // Enumeration type names should not have "Flags" or "Enum" suffixes { + /// + /// None. + /// None = 0x00000000, + /// - /// SSH_FXF_READ + /// SSH_FXF_READ. /// Read = 0x00000001, + /// - /// SSH_FXF_WRITE + /// SSH_FXF_WRITE. /// Write = 0x00000002, + /// - /// SSH_FXF_APPEND + /// SSH_FXF_APPEND. /// Append = 0x00000004, + /// - /// SSH_FXF_CREAT + /// SSH_FXF_CREAT. /// CreateNewOrOpen = 0x00000008, + /// - /// SSH_FXF_TRUNC + /// SSH_FXF_TRUNC. /// Truncate = 0x00000010, + /// - /// SSH_FXF_EXCL + /// SSH_FXF_EXCL. /// CreateNew = 0x00000028 } diff --git a/src/Renci.SshNet/Sftp/ISftpFile.cs b/src/Renci.SshNet/Sftp/ISftpFile.cs index a74e8fbf9..02dff7215 100644 --- a/src/Renci.SshNet/Sftp/ISftpFile.cs +++ b/src/Renci.SshNet/Sftp/ISftpFile.cs @@ -156,7 +156,7 @@ public interface ISftpFile /// Gets or sets a value indicating whether the owner can write into this file. /// /// - /// if owner can write into this file; otherwise, . + /// if owner can write into this file; otherwise, . /// bool OwnerCanWrite { get; set; } @@ -164,7 +164,7 @@ public interface ISftpFile /// Gets or sets a value indicating whether the owner can execute this file. /// /// - /// if owner can execute this file; otherwise, . + /// if owner can execute this file; otherwise, . /// bool OwnerCanExecute { get; set; } @@ -172,7 +172,7 @@ public interface ISftpFile /// Gets or sets a value indicating whether the group members can read from this file. /// /// - /// if group members can read from this file; otherwise, . + /// if group members can read from this file; otherwise, . /// bool GroupCanRead { get; set; } @@ -180,7 +180,7 @@ public interface ISftpFile /// Gets or sets a value indicating whether the group members can write into this file. /// /// - /// if group members can write into this file; otherwise, . + /// if group members can write into this file; otherwise, . /// bool GroupCanWrite { get; set; } @@ -188,7 +188,7 @@ public interface ISftpFile /// Gets or sets a value indicating whether the group members can execute this file. ///
/// - /// if group members can execute this file; otherwise, . + /// if group members can execute this file; otherwise, . /// bool GroupCanExecute { get; set; } @@ -196,7 +196,7 @@ public interface ISftpFile /// Gets or sets a value indicating whether the others can read from this file. ///
/// - /// if others can read from this file; otherwise, . + /// if others can read from this file; otherwise, . /// bool OthersCanRead { get; set; } @@ -204,7 +204,7 @@ public interface ISftpFile /// Gets or sets a value indicating whether the others can write into this file. ///
/// - /// if others can write into this file; otherwise, . + /// if others can write into this file; otherwise, . /// bool OthersCanWrite { get; set; } @@ -212,7 +212,7 @@ public interface ISftpFile /// Gets or sets a value indicating whether the others can execute this file. ///
/// - /// if others can execute this file; otherwise, . + /// if others can execute this file; otherwise, . /// bool OthersCanExecute { get; set; } diff --git a/src/Renci.SshNet/Sftp/ISftpFileReader.cs b/src/Renci.SshNet/Sftp/ISftpFileReader.cs index 684cc4187..823b2e23a 100644 --- a/src/Renci.SshNet/Sftp/ISftpFileReader.cs +++ b/src/Renci.SshNet/Sftp/ISftpFileReader.cs @@ -1,9 +1,23 @@ 锘縰sing System; +using Renci.SshNet.Common; + namespace Renci.SshNet.Sftp { + /// + /// Reads a given file. + /// internal interface ISftpFileReader : IDisposable { + /// + /// Reads a sequence of bytes from the current file and advances the position within the file by the number of bytes read. + /// + /// + /// The sequence of bytes read from the file, or a zero-length array if the end of the file + /// has been reached. + /// + /// The current is disposed. + /// Attempting to read beyond the end of the file. byte[] Read(); } } diff --git a/src/Renci.SshNet/Sftp/ISftpResponseFactory.cs b/src/Renci.SshNet/Sftp/ISftpResponseFactory.cs index afb440c10..ae57110fc 100644 --- a/src/Renci.SshNet/Sftp/ISftpResponseFactory.cs +++ b/src/Renci.SshNet/Sftp/ISftpResponseFactory.cs @@ -2,8 +2,21 @@ namespace Renci.SshNet.Sftp { + /// + /// Represents a factory for creating SFTP response messages. + /// internal interface ISftpResponseFactory { + /// + /// Creates a SFTP response message for the specified protocol version and message type, and + /// with the specified . + /// + /// The protocol version. + /// The message type. + /// The . + /// + /// A . + /// SftpMessage Create(uint protocolVersion, byte messageType, Encoding encoding); } } diff --git a/src/Renci.SshNet/Sftp/ISftpSession.cs b/src/Renci.SshNet/Sftp/ISftpSession.cs index 31b091fac..ed9b72369 100644 --- a/src/Renci.SshNet/Sftp/ISftpSession.cs +++ b/src/Renci.SshNet/Sftp/ISftpSession.cs @@ -7,6 +7,9 @@ namespace Renci.SshNet.Sftp { + /// + /// Represents an SFTP session. + /// internal interface ISftpSession : ISubsystemSession { /// @@ -40,25 +43,44 @@ internal interface ISftpSession : ISubsystemSession /// string GetCanonicalPath(string path); + /// + /// Asynchronously resolves a given path into an absolute path on the server. + /// + /// The path to resolve. + /// The token to monitor for cancellation requests. + /// + /// A task that represents an asynchronous operation to resolve into + /// an absolute path. The value of its contains the absolute + /// path of the specified path. + /// Task GetCanonicalPathAsync(string path, CancellationToken cancellationToken); /// - /// Performs SSH_FXP_FSTAT request. + /// Asynchronously performs a SSH_FXP_FSTAT request. /// /// The handle. - /// if set to returns instead of throwing an exception. + /// If set to , is returned in case of an error. /// - /// File attributes + /// The file attributes. /// SftpFileAttributes RequestFStat(byte[] handle, bool nullOnError); + /// + /// Asynchronously performs a SSH_FXP_FSTAT request. + /// + /// The handle. + /// The token to monitor for cancellation requests. + /// + /// A task the represents the asynchronous SSH_FXP_FSTAT request. The value of its + /// contains the file attributes of the specified handle. + /// Task RequestFStatAsync(byte[] handle, CancellationToken cancellationToken); /// /// Performs SSH_FXP_STAT request. /// /// The path. - /// if set to returns null instead of throwing an exception. + /// If set to , is returned in case of an error. /// /// File attributes. /// @@ -90,7 +112,7 @@ internal interface ISftpSession : ISubsystemSession /// /// The path. /// - /// File attributes + /// File attributes. /// SftpFileAttributes RequestLStat(string path); @@ -122,14 +144,26 @@ internal interface ISftpSession : ISubsystemSession void RequestMkDir(string path); /// - /// Performs SSH_FXP_OPEN request. + /// Performs a SSH_FXP_OPEN request. /// /// The path. /// The flags. - /// if set to returns instead of throwing an exception. - /// File handle. + /// If set to , is returned in case of an error. + /// + /// The file handle for the specified path. + /// byte[] RequestOpen(string path, Flags flags, bool nullOnError = false); + /// + /// Asynchronously performs a SSH_FXP_OPEN request. + /// + /// The path. + /// The flags. + /// The token to monitor for cancellation requests. + /// + /// A task the represents the asynchronous SSH_FXP_OPEN request. The value of its + /// contains the file handle of the specified path. + /// Task RequestOpenAsync(string path, Flags flags, CancellationToken cancellationToken); /// @@ -159,13 +193,24 @@ internal interface ISftpSession : ISubsystemSession byte[] EndOpen(SftpOpenAsyncResult asyncResult); /// - /// Performs SSH_FXP_OPENDIR request. + /// Performs a SSH_FXP_OPENDIR request. /// /// The path. - /// if set to returns null instead of throwing an exception. - /// File handle. + /// If set to , is returned in case of an error. + /// + /// A file handle for the specified path. + /// byte[] RequestOpenDir(string path, bool nullOnError = false); + /// + /// Asynchronously performs a SSH_FXP_OPENDIR request. + /// + /// The path. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_OPENDIR request. The value of its + /// contains the handle of the specified path. + /// Task RequestOpenDirAsync(string path, CancellationToken cancellationToken); /// @@ -181,7 +226,7 @@ internal interface ISftpSession : ISubsystemSession /// The handle. /// The offset. /// The length. - /// data array; null if EOF + /// data array; null if EOF. byte[] RequestRead(byte[] handle, ulong offset, uint length); /// @@ -211,15 +256,41 @@ internal interface ISftpSession : ISubsystemSession /// is . byte[] EndRead(SftpReadAsyncResult asyncResult); + /// + /// Asynchronously performs a SSH_FXP_READ request. + /// + /// The handle to the file to read from. + /// The offset in the file to start reading from. + /// The number of bytes to read. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_READ request. The value of + /// its contains the data read from the file, or an empty + /// array when the end of the file is reached. + /// Task RequestReadAsync(byte[] handle, ulong offset, uint length, CancellationToken cancellationToken); /// - /// Performs SSH_FXP_READDIR request. + /// Performs a SSH_FXP_READDIR request. /// - /// The handle. - /// + /// The handle of the directory to read. + /// + /// A where the key is the name of a file in the directory + /// and the value is the of the file. + /// KeyValuePair[] RequestReadDir(byte[] handle); + /// + /// Performs a SSH_FXP_READDIR request. + /// + /// The handle of the directory to read. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_READDIR request. The value of its + /// contains a where the + /// key is the name of a file in the directory and the value is the + /// of the file. + /// Task[]> RequestReadDirAsync(byte[] handle, CancellationToken cancellationToken); /// @@ -244,20 +315,37 @@ internal interface ISftpSession : ISubsystemSession string EndRealPath(SftpRealPathAsyncResult asyncResult); /// - /// Performs SSH_FXP_REMOVE request. + /// Performs a SSH_FXP_REMOVE request. /// /// The path. void RequestRemove(string path); + /// + /// Asynchronously performs a SSH_FXP_REMOVE request. + /// + /// The path. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_REMOVE request. + /// Task RequestRemoveAsync(string path, CancellationToken cancellationToken); /// - /// Performs SSH_FXP_RENAME request. + /// Performs a SSH_FXP_RENAME request. /// /// The old path. /// The new path. void RequestRename(string oldPath, string newPath); + /// + /// Asynchronously performs a SSH_FXP_RENAME request. + /// + /// The old path. + /// The new path. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_RENAME request. + /// Task RequestRenameAsync(string oldPath, string newPath, CancellationToken cancellationToken); /// @@ -274,13 +362,26 @@ internal interface ISftpSession : ISubsystemSession void RequestSetStat(string path, SftpFileAttributes attributes); /// - /// Performs statvfs@openssh.com extended request. + /// Performs a statvfs@openssh.com extended request. /// /// The path. - /// if set to [null on error]. - /// + /// If set to , is returned in case of an error. + /// + /// The file system information for the specified path, or when + /// the request failed and is . + /// SftpFileSytemInformation RequestStatVfs(string path, bool nullOnError = false); + /// + /// Asynchronously performs a statvfs@openssh.com extended request. + /// + /// The path. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the statvfs@openssh.com extended request. The value of its + /// contains the file system information for the specified + /// path. + /// Task RequestStatVfsAsync(string path, CancellationToken cancellationToken); /// @@ -315,14 +416,34 @@ void RequestWrite(byte[] handle, AutoResetEvent wait, Action writeCompleted = null); + /// + /// Asynchronouly performs a SSH_FXP_WRITE request. + /// + /// The handle. + /// The the zero-based offset (in bytes) relative to the beginning of the file that the write must start at. + /// The buffer holding the data to write. + /// the zero-based offset in at which to begin taking bytes to write. + /// The length (in bytes) of the data to write. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_WRITE request. + /// Task RequestWriteAsync(byte[] handle, ulong serverOffset, byte[] data, int offset, int length, CancellationToken cancellationToken); /// - /// Performs SSH_FXP_CLOSE request. + /// Performs a SSH_FXP_CLOSE request. /// /// The handle. void RequestClose(byte[] handle); + /// + /// Performs a SSH_FXP_CLOSE request. + /// + /// The handle. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_CLOSE request. + /// Task RequestCloseAsync(byte[] handle, CancellationToken cancellationToken); /// @@ -365,6 +486,18 @@ void RequestWrite(byte[] handle, /// uint CalculateOptimalWriteLength(uint bufferSize, byte[] handle); + /// + /// Creates an for reading the content of the file represented by a given . + /// + /// The handle of the file to read. + /// The SFTP session. + /// The maximum number of bytes to read with each chunk. + /// The maximum number of pending reads. + /// The size of the file or when the size could not be determined. + /// + /// An for reading the content of the file represented by the + /// specified . + /// ISftpFileReader CreateFileReader(byte[] handle, ISftpSession sftpSession, uint chunkSize, int maxPendingReads, long? fileSize); } } diff --git a/src/Renci.SshNet/Sftp/Requests/SftpExtendedRequest.cs b/src/Renci.SshNet/Sftp/Requests/SftpExtendedRequest.cs index 8693929d5..59da98af5 100644 --- a/src/Renci.SshNet/Sftp/Requests/SftpExtendedRequest.cs +++ b/src/Renci.SshNet/Sftp/Requests/SftpExtendedRequest.cs @@ -15,7 +15,10 @@ public override SftpMessageTypes SftpMessageType public string Name { - get { return _name; } + get + { + return _name; + } private set { _name = value; @@ -52,4 +55,4 @@ protected override void SaveData() WriteBinaryString(_nameBytes); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Sftp/Responses/ExtendedReplies/StatVfsReplyInfo.cs b/src/Renci.SshNet/Sftp/Responses/ExtendedReplies/StatVfsReplyInfo.cs index 768764419..d7cecf8f9 100644 --- a/src/Renci.SshNet/Sftp/Responses/ExtendedReplies/StatVfsReplyInfo.cs +++ b/src/Renci.SshNet/Sftp/Responses/ExtendedReplies/StatVfsReplyInfo.cs @@ -18,8 +18,7 @@ public override void LoadData(SshDataStream stream) stream.ReadUInt64(), // AvailableNodes stream.ReadUInt64(), // Sid stream.ReadUInt64(), // Flags - stream.ReadUInt64() // MaxNameLenght - ); + stream.ReadUInt64()); // MaxNameLenght } } } diff --git a/src/Renci.SshNet/Sftp/Responses/SftpDataResponse.cs b/src/Renci.SshNet/Sftp/Responses/SftpDataResponse.cs index ce0d414c5..04a7d4d82 100644 --- a/src/Renci.SshNet/Sftp/Responses/SftpDataResponse.cs +++ b/src/Renci.SshNet/Sftp/Responses/SftpDataResponse.cs @@ -17,7 +17,7 @@ public SftpDataResponse(uint protocolVersion) protected override void LoadData() { base.LoadData(); - + Data = ReadBinary(); } diff --git a/src/Renci.SshNet/Sftp/Responses/SftpExtendedReplyResponse.cs b/src/Renci.SshNet/Sftp/Responses/SftpExtendedReplyResponse.cs index bbd41680f..84fe93d35 100644 --- a/src/Renci.SshNet/Sftp/Responses/SftpExtendedReplyResponse.cs +++ b/src/Renci.SshNet/Sftp/Responses/SftpExtendedReplyResponse.cs @@ -12,7 +12,8 @@ public SftpExtendedReplyResponse(uint protocolVersion) { } - public T GetReply() where T : ExtendedReplyInfo, new() + public T GetReply() + where T : ExtendedReplyInfo, new() { var result = new T(); result.LoadData(DataStream); diff --git a/src/Renci.SshNet/Sftp/Responses/SftpHandleResponse.cs b/src/Renci.SshNet/Sftp/Responses/SftpHandleResponse.cs index 31da2e937..21af8f835 100644 --- a/src/Renci.SshNet/Sftp/Responses/SftpHandleResponse.cs +++ b/src/Renci.SshNet/Sftp/Responses/SftpHandleResponse.cs @@ -17,7 +17,7 @@ public SftpHandleResponse(uint protocolVersion) protected override void LoadData() { base.LoadData(); - + Handle = ReadBinary(); } diff --git a/src/Renci.SshNet/Sftp/Responses/SftpResponse.cs b/src/Renci.SshNet/Sftp/Responses/SftpResponse.cs index 3b784bf09..5e3ac145b 100644 --- a/src/Renci.SshNet/Sftp/Responses/SftpResponse.cs +++ b/src/Renci.SshNet/Sftp/Responses/SftpResponse.cs @@ -14,7 +14,7 @@ protected SftpResponse(uint protocolVersion) protected override void LoadData() { base.LoadData(); - + ResponseId = ReadUInt32(); } diff --git a/src/Renci.SshNet/Sftp/SftpDownloadAsyncResult.cs b/src/Renci.SshNet/Sftp/SftpDownloadAsyncResult.cs index b2505b20a..9e706d9e0 100644 --- a/src/Renci.SshNet/Sftp/SftpDownloadAsyncResult.cs +++ b/src/Renci.SshNet/Sftp/SftpDownloadAsyncResult.cs @@ -6,7 +6,7 @@ namespace Renci.SshNet.Sftp /// /// Encapsulates the results of an asynchronous download operation. /// - public class SftpDownloadAsyncResult : AsyncResult + public class SftpDownloadAsyncResult : AsyncResult { /// /// Gets or sets a value indicating whether to cancel asynchronous download operation. diff --git a/src/Renci.SshNet/Sftp/SftpFileAttributes.cs b/src/Renci.SshNet/Sftp/SftpFileAttributes.cs index 824a3a0fb..2f32b4796 100644 --- a/src/Renci.SshNet/Sftp/SftpFileAttributes.cs +++ b/src/Renci.SshNet/Sftp/SftpFileAttributes.cs @@ -13,6 +13,7 @@ namespace Renci.SshNet.Sftp public class SftpFileAttributes { #pragma warning disable IDE1006 // Naming Styles +#pragma warning disable SA1310 // Field names should not contain underscore private const uint S_IFMT = 0xF000; // bitmask for the file type bitfields private const uint S_IFSOCK = 0xC000; // socket private const uint S_IFLNK = 0xA000; // symbolic link @@ -33,6 +34,7 @@ public class SftpFileAttributes private const uint S_IROTH = 0x0004; // others have read permission private const uint S_IWOTH = 0x0002; // others have write permission private const uint S_IXOTH = 0x0001; // others have execute permission +#pragma warning restore SA1310 // Field names should not contain underscore #pragma warning restore IDE1006 // Naming Styles private readonly DateTime _originalLastAccessTimeUtc; @@ -165,7 +167,7 @@ public DateTime LastWriteTime /// Gets a value indicating whether file represents a socket. /// /// - /// if file represents a socket; otherwise, . + /// if file represents a socket; otherwise, . /// public bool IsSocket { get; private set; } @@ -477,7 +479,7 @@ public void SetPermissions(short mode) var modeBytes = mode.ToString(CultureInfo.InvariantCulture).PadLeft(3, '0').ToCharArray(); - var permission = (modeBytes[0] & 0x0F) * 8 * 8 + (modeBytes[1] & 0x0F) * 8 + (modeBytes[2] & 0x0F); + var permission = ((modeBytes[0] & 0x0F) * 8 * 8) + ((modeBytes[1] & 0x0F) * 8) + (modeBytes[2] & 0x0F); OwnerCanRead = (permission & S_IRUSR) == S_IRUSR; OwnerCanWrite = (permission & S_IWUSR) == S_IWUSR; @@ -500,79 +502,88 @@ public void SetPermissions(short mode) /// public byte[] GetBytes() { - var stream = new SshDataStream(4); - - uint flag = 0; - - if (IsSizeChanged && IsRegularFile) + using (var stream = new SshDataStream(4)) { - flag |= 0x00000001; - } + uint flag = 0; - if (IsUserIdChanged || IsGroupIdChanged) - { - flag |= 0x00000002; - } + if (IsSizeChanged && IsRegularFile) + { + flag |= 0x00000001; + } - if (IsPermissionsChanged) - { - flag |= 0x00000004; - } + if (IsUserIdChanged || IsGroupIdChanged) + { + flag |= 0x00000002; + } - if (IsLastAccessTimeChanged || IsLastWriteTimeChanged) - { - flag |= 0x00000008; - } + if (IsPermissionsChanged) + { + flag |= 0x00000004; + } - if (IsExtensionsChanged) - { - flag |= 0x80000000; - } + if (IsLastAccessTimeChanged || IsLastWriteTimeChanged) + { + flag |= 0x00000008; + } - stream.Write(flag); + if (IsExtensionsChanged) + { + flag |= 0x80000000; + } - if (IsSizeChanged && IsRegularFile) - { - stream.Write((ulong) Size); - } + stream.Write(flag); - if (IsUserIdChanged || IsGroupIdChanged) - { - stream.Write((uint) UserId); - stream.Write((uint) GroupId); - } + if (IsSizeChanged && IsRegularFile) + { + stream.Write((ulong) Size); + } - if (IsPermissionsChanged) - { - stream.Write(Permissions); - } + if (IsUserIdChanged || IsGroupIdChanged) + { + stream.Write((uint) UserId); + stream.Write((uint) GroupId); + } - if (IsLastAccessTimeChanged || IsLastWriteTimeChanged) - { - var time = (uint)(LastAccessTimeUtc.ToFileTimeUtc() / 10000000 - 11644473600); - stream.Write(time); - time = (uint)(LastWriteTimeUtc.ToFileTimeUtc() / 10000000 - 11644473600); - stream.Write(time); - } + if (IsPermissionsChanged) + { + stream.Write(Permissions); + } - if (IsExtensionsChanged) - { - foreach (var item in Extensions) + if (IsLastAccessTimeChanged || IsLastWriteTimeChanged) { - // TODO: we write as ASCII but read as UTF8 !!! + var time = (uint) ((LastAccessTimeUtc.ToFileTimeUtc() / 10000000) - 11644473600); + stream.Write(time); + time = (uint) ((LastWriteTimeUtc.ToFileTimeUtc() / 10000000) - 11644473600); + stream.Write(time); + } - stream.Write(item.Key, SshData.Ascii); - stream.Write(item.Value, SshData.Ascii); + if (IsExtensionsChanged) + { + foreach (var item in Extensions) + { + /* + * TODO: we write as ASCII but read as UTF8 !!! + */ + + stream.Write(item.Key, SshData.Ascii); + stream.Write(item.Value, SshData.Ascii); + } } - } - return stream.ToArray(); + return stream.ToArray(); + } } internal static readonly SftpFileAttributes Empty = new SftpFileAttributes(); internal static SftpFileAttributes FromBytes(SshDataStream stream) { + const uint SSH_FILEXFER_ATTR_SIZE = 0x00000001; + const uint SSH_FILEXFER_ATTR_UIDGID = 0x00000002; + const uint SSH_FILEXFER_ATTR_PERMISSIONS = 0x00000004; + const uint SSH_FILEXFER_ATTR_ACMODTIME = 0x00000008; + const uint SSH_FILEXFER_ATTR_EXTENDED = 0x80000000; + var flag = stream.ReadUInt32(); long size = -1; @@ -583,24 +594,24 @@ internal static SftpFileAttributes FromBytes(SshDataStream stream) DateTime modifyTime; Dictionary extensions = null; - if ((flag & 0x00000001) == 0x00000001) // SSH_FILEXFER_ATTR_SIZE + if ((flag & SSH_FILEXFER_ATTR_SIZE) == SSH_FILEXFER_ATTR_SIZE) { size = (long) stream.ReadUInt64(); } - if ((flag & 0x00000002) == 0x00000002) // SSH_FILEXFER_ATTR_UIDGID + if ((flag & SSH_FILEXFER_ATTR_UIDGID) == SSH_FILEXFER_ATTR_UIDGID) { userId = (int) stream.ReadUInt32(); groupId = (int) stream.ReadUInt32(); } - if ((flag & 0x00000004) == 0x00000004) // SSH_FILEXFER_ATTR_PERMISSIONS + if ((flag & SSH_FILEXFER_ATTR_PERMISSIONS) == SSH_FILEXFER_ATTR_PERMISSIONS) { permissions = stream.ReadUInt32(); } - if ((flag & 0x00000008) == 0x00000008) // SSH_FILEXFER_ATTR_ACMODTIME + if ((flag & SSH_FILEXFER_ATTR_ACMODTIME) == SSH_FILEXFER_ATTR_ACMODTIME) { // The incoming times are "Unix times", so they're already in UTC. We need to preserve that // to avoid losing information in a local time conversion during the "fall back" hour in DST. @@ -615,7 +626,7 @@ internal static SftpFileAttributes FromBytes(SshDataStream stream) modifyTime = DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc); } - if ((flag & 0x80000000) == 0x80000000) // SSH_FILEXFER_ATTR_EXTENDED + if ((flag & SSH_FILEXFER_ATTR_EXTENDED) == SSH_FILEXFER_ATTR_EXTENDED) { var extendedCount = (int) stream.ReadUInt32(); extensions = new Dictionary(extendedCount); diff --git a/src/Renci.SshNet/Sftp/SftpFileReader.cs b/src/Renci.SshNet/Sftp/SftpFileReader.cs index e10107b15..af32f87a7 100644 --- a/src/Renci.SshNet/Sftp/SftpFileReader.cs +++ b/src/Renci.SshNet/Sftp/SftpFileReader.cs @@ -74,10 +74,14 @@ public SftpFileReader(byte[] handle, ISftpSession sftpSession, uint chunkSize, i public byte[] Read() { +#if NET7_0_OR_GREATER + ObjectDisposedException.ThrowIf(_disposingOrDisposed, this); +#else if (_disposingOrDisposed) { throw new ObjectDisposedException(GetType().FullName); } +#endif // NET7_0_OR_GREATER if (_exception is not null) { @@ -168,7 +172,9 @@ public byte[] Read() var bytesToCatchUp = nextChunk.Offset - _offset; - // TODO: break loop and interrupt blocking wait in case of exception + /* + * TODO: break loop and interrupt blocking wait in case of exception + */ var read = _sftpSession.RequestRead(_handle, _offset, (uint) bytesToCatchUp); if (read.Length == 0) diff --git a/src/Renci.SshNet/Sftp/SftpFileStream.cs b/src/Renci.SshNet/Sftp/SftpFileStream.cs index be1e756ac..03b9e088f 100644 --- a/src/Renci.SshNet/Sftp/SftpFileStream.cs +++ b/src/Renci.SshNet/Sftp/SftpFileStream.cs @@ -1,5 +1,6 @@ 锘縰sing System; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -12,7 +13,9 @@ namespace Renci.SshNet.Sftp /// Exposes a around a remote SFTP file, supporting both synchronous and asynchronous read and write operations. /// /// +#pragma warning disable CA1844 // Provide memory-based overrides of async methods when subclassing 'Stream' public class SftpFileStream : Stream +#pragma warning restore CA1844 // Provide memory-based overrides of async methods when subclassing 'Stream' { private readonly object _lock = new object(); private readonly int _readBufferSize; @@ -181,9 +184,9 @@ private SftpFileStream(ISftpSession session, string path, FileAccess access, int Name = path; _session = session; - _canRead = (access & FileAccess.Read) != 0; + _canRead = (access & FileAccess.Read) == FileAccess.Read; _canSeek = true; - _canWrite = (access & FileAccess.Write) != 0; + _canWrite = (access & FileAccess.Write) == FileAccess.Write; _handle = handle; @@ -221,9 +224,9 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc // Initialize the object state. _session = session; - _canRead = (access & FileAccess.Read) != 0; + _canRead = (access & FileAccess.Read) == FileAccess.Read; _canSeek = true; - _canWrite = (access & FileAccess.Write) != 0; + _canWrite = (access & FileAccess.Write) == FileAccess.Write; var flags = Flags.None; @@ -243,20 +246,25 @@ internal SftpFileStream(ISftpSession session, string path, FileMode mode, FileAc throw new ArgumentOutOfRangeException(nameof(access)); } - if ((access & FileAccess.Read) != 0 && mode == FileMode.Append) + if ((access & FileAccess.Read) == FileAccess.Read && mode == FileMode.Append) { - throw new ArgumentException(string.Format("{0} mode can be requested only when combined with write-only access.", mode.ToString("G"))); + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, + "{0} mode can be requested only when combined with write-only access.", + mode.ToString("G")), + nameof(mode)); } - if ((access & FileAccess.Write) == 0) + if ((access & FileAccess.Write) != FileAccess.Write) { if (mode is FileMode.Create or FileMode.CreateNew or FileMode.Truncate or FileMode.Append) { - throw new ArgumentException(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, + "Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), mode, nameof(FileAccess), - access)); + access), + nameof(mode)); } } @@ -345,20 +353,25 @@ internal static async Task OpenAsync(ISftpSession session, strin throw new ArgumentOutOfRangeException(nameof(access)); } - if ((access & FileAccess.Read) != 0 && mode == FileMode.Append) + if ((access & FileAccess.Read) == FileAccess.Read && mode == FileMode.Append) { - throw new ArgumentException(string.Format("{0} mode can be requested only when combined with write-only access.", mode.ToString("G"))); + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, + "{0} mode can be requested only when combined with write-only access.", + mode.ToString("G")), + nameof(mode)); } - if ((access & FileAccess.Write) == 0) + if ((access & FileAccess.Write) != FileAccess.Write) { if (mode is FileMode.Create or FileMode.CreateNew or FileMode.Truncate or FileMode.Append) { - throw new ArgumentException(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, + "Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), mode, nameof(FileAccess), - access)); + access), + nameof(mode)); } } @@ -1318,10 +1331,14 @@ private void SetupWrite() private void CheckSessionIsOpen() { +#if NET7_0_OR_GREATER + ObjectDisposedException.ThrowIf(_session is null, this); +#else if (_session is null) { throw new ObjectDisposedException(GetType().FullName); } +#endif // NET7_0_OR_GREATER if (!_session.IsOpen) { diff --git a/src/Renci.SshNet/Sftp/SftpFileSystemInformation.cs b/src/Renci.SshNet/Sftp/SftpFileSystemInformation.cs index 61f32e1de..89d24a727 100644 --- a/src/Renci.SshNet/Sftp/SftpFileSystemInformation.cs +++ b/src/Renci.SshNet/Sftp/SftpFileSystemInformation.cs @@ -5,10 +5,14 @@ namespace Renci.SshNet.Sftp /// /// Contains File system information exposed by statvfs@openssh.com request. /// +#pragma warning disable SA1649 // File name should match first type name public class SftpFileSytemInformation +#pragma warning restore SA1649 // File name should match first type name { +#pragma warning disable SA1310 // Field names should not contain underscore internal const ulong SSH_FXE_STATVFS_ST_RDONLY = 0x1; internal const ulong SSH_FXE_STATVFS_ST_NOSUID = 0x2; +#pragma warning restore SA1310 // Field names should not contain underscore private readonly ulong _flag; @@ -99,7 +103,7 @@ public bool IsReadOnly /// Gets a value indicating whether [supports set uid]. /// /// - /// if [supports set uid]; otherwise, . + /// if [supports set uid]; otherwise, . /// public bool SupportsSetUid { @@ -158,4 +162,4 @@ internal void SaveData(SshDataStream stream) stream.Write(MaxNameLenght); } } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Sftp/SftpSession.cs b/src/Renci.SshNet/Sftp/SftpSession.cs index efca5d06f..0fec92230 100644 --- a/src/Renci.SshNet/Sftp/SftpSession.cs +++ b/src/Renci.SshNet/Sftp/SftpSession.cs @@ -11,6 +11,9 @@ namespace Renci.SshNet.Sftp { + /// + /// Represents an SFTP session. + /// internal sealed class SftpSession : SubsystemSession, ISftpSession { internal const int MaximumSupportedVersion = 3; @@ -114,14 +117,22 @@ public string GetCanonicalPath(string path) if (fullPath.EndsWith("/.", StringComparison.OrdinalIgnoreCase) || fullPath.EndsWith("/..", StringComparison.OrdinalIgnoreCase) || fullPath.Equals("/", StringComparison.OrdinalIgnoreCase) || +#if NET || NETSTANDARD2_1_OR_GREATER + fullPath.IndexOf('/', StringComparison.OrdinalIgnoreCase) < 0) +#else fullPath.IndexOf('/') < 0) +#endif // NET || NETSTANDARD2_1_OR_GREATER { return fullPath; } var pathParts = fullPath.Split('/'); +#if NET || NETSTANDARD2_1_OR_GREATER + var partialFullPath = string.Join('/', pathParts, 0, pathParts.Length - 1); +#else var partialFullPath = string.Join("/", pathParts, 0, pathParts.Length - 1); +#endif // NET || NETSTANDARD2_1_OR_GREATER if (string.IsNullOrEmpty(partialFullPath)) { @@ -149,6 +160,14 @@ public string GetCanonicalPath(string path) return string.Format(CultureInfo.InvariantCulture, "{0}{1}{2}", canonizedPath, slash, pathParts[pathParts.Length - 1]); } + /// + /// Asynchronously resolves a given path into an absolute path on the server. + /// + /// The path to resolve. + /// The token to monitor for cancellation requests. + /// + /// A task representing the absolute path. + /// public async Task GetCanonicalPathAsync(string path, CancellationToken cancellationToken) { var fullPath = GetFullRemotePath(path); @@ -169,14 +188,22 @@ public async Task GetCanonicalPathAsync(string path, CancellationToken c if (fullPath.EndsWith("/.", StringComparison.Ordinal) || fullPath.EndsWith("/..", StringComparison.Ordinal) || fullPath.Equals("/", StringComparison.Ordinal) || +#if NET || NETSTANDARD2_1_OR_GREATER + fullPath.IndexOf('/', StringComparison.Ordinal) < 0) +#else fullPath.IndexOf('/') < 0) +#endif // NET || NETSTANDARD2_1_OR_GREATER { return fullPath; } var pathParts = fullPath.Split('/'); - var partialFullPath = string.Join("/", pathParts, 0, pathParts.Length - 1); +#if NET || NETSTANDARD2_1_OR_GREATER + var partialFullPath = string.Join('/', pathParts); +#else + var partialFullPath = string.Join("/", pathParts); +#endif // NET || NETSTANDARD2_1_OR_GREATER if (string.IsNullOrEmpty(partialFullPath)) { @@ -204,6 +231,18 @@ public async Task GetCanonicalPathAsync(string path, CancellationToken c return canonizedPath + slash + pathParts[pathParts.Length - 1]; } + /// + /// Creates an for reading the content of the file represented by a given . + /// + /// The handle of the file to read. + /// The SFTP session. + /// The maximum number of bytes to read with each chunk. + /// The maximum number of pending reads. + /// The size of the file or when the size could not be determined. + /// + /// An for reading the content of the file represented by the + /// specified . + /// public ISftpFileReader CreateFileReader(byte[] handle, ISftpSession sftpSession, uint chunkSize, int maxPendingReads, long? fileSize) { return new SftpFileReader(handle, sftpSession, chunkSize, maxPendingReads, fileSize); @@ -224,6 +263,7 @@ internal string GetFullRemotePath(string path) fullPath = WorkingDirectory + '/' + path; } } + return fullPath; } @@ -417,7 +457,7 @@ private void SendRequest(SftpRequest request) /// /// The path. /// The flags. - /// if set to returns instead of throwing an exception. + /// If set to returns instead of throwing an exception. /// File handle. public byte[] RequestOpen(string path, Flags flags, bool nullOnError = false) { @@ -432,44 +472,61 @@ public byte[] RequestOpen(string path, Flags flags, bool nullOnError = false) _encoding, flags, response => - { - handle = response.Handle; - _ = wait.Set(); - }, + { + handle = response.Handle; + _ = wait.Set(); + }, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (!nullOnError && exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (!nullOnError && exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } +#pragma warning restore CA1508 // Avoid dead conditional code return handle; } + /// + /// Asynchronously performs a SSH_FXP_OPEN request. + /// + /// The path. + /// The flags. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_OPEN request. The value of its + /// contains the file handle of the specified path. + /// public async Task RequestOpenAsync(string path, Flags flags, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { SendRequest(new SftpOpenRequest(ProtocolVersion, - NextRequestId, - path, - _encoding, - flags, - response => tcs.TrySetResult(response.Handle), - response => tcs.TrySetException(GetSftpException(response)))); + NextRequestId, + path, + _encoding, + flags, + response => tcs.TrySetResult(response.Handle), + response => tcs.TrySetException(GetSftpException(response)))); return await tcs.Task.ConfigureAwait(false); } @@ -495,13 +552,13 @@ public SftpOpenAsyncResult BeginOpen(string path, Flags flags, AsyncCallback cal _encoding, flags, response => - { - asyncResult.SetAsCompleted(response.Handle, completedSynchronously: false); - }, + { + asyncResult.SetAsCompleted(response.Handle, completedSynchronously: false); + }, response => - { - asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false); - }); + { + asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false); + }); SendRequest(request); @@ -558,22 +615,32 @@ public void RequestClose(byte[] handle) NextRequestId, handle, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } } + /// + /// Performs a SSH_FXP_CLOSE request. + /// + /// The handle. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_CLOSE request. + /// public async Task RequestCloseAsync(byte[] handle, CancellationToken cancellationToken) { var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); @@ -582,21 +649,25 @@ public async Task RequestCloseAsync(byte[] handle, CancellationToken cancellatio NextRequestId, handle, response => + { + if (response.StatusCode == StatusCodes.Ok) { - if (response.StatusCode == StatusCodes.Ok) - { - _ = tcs.TrySetResult(true); - } - else - { - _ = tcs.TrySetException(GetSftpException(response)); - } - })); + _ = tcs.TrySetResult(true); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } + })); // Only check for cancellation after the SftpCloseRequest was sent cancellationToken.ThrowIfCancellationRequested(); - using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { _ = await tcs.Task.ConfigureAwait(false); } @@ -619,9 +690,9 @@ public SftpCloseAsyncResult BeginClose(byte[] handle, AsyncCallback callback, ob NextRequestId, handle, response => - { - asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false); - }); + { + asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false); + }); SendRequest(request); return asyncResult; @@ -740,7 +811,9 @@ public byte[] EndRead(SftpReadAsyncResult asyncResult) /// The handle. /// The offset. /// The length. - /// data array; null if EOF + /// + /// The data that was read, or an empty array when the end of the file was reached. + /// public byte[] RequestRead(byte[] handle, ulong offset, uint length) { SshException exception = null; @@ -755,30 +828,32 @@ public byte[] RequestRead(byte[] handle, ulong offset, uint length) offset, length, response => - { - data = response.Data; - _ = wait.Set(); - }, + { + data = response.Data; + _ = wait.Set(); + }, response => + { + if (response.StatusCode != StatusCodes.Eof) { - if (response.StatusCode != StatusCodes.Eof) - { - exception = GetSftpException(response); - } - else - { - data = Array.Empty(); - } + exception = GetSftpException(response); + } + else + { + data = Array.Empty(); + } - _ = wait.Set(); - }); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -786,13 +861,29 @@ public byte[] RequestRead(byte[] handle, ulong offset, uint length) return data; } + /// + /// Asynchronously performs a SSH_FXP_READ request. + /// + /// The handle to the file to read from. + /// The offset in the file to start reading from. + /// The number of bytes to read. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_READ request. The value of + /// its contains the data read from the file, or an empty + /// array when the end of the file is reached. + /// public async Task RequestReadAsync(byte[] handle, ulong offset, uint length, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { SendRequest(new SftpReadRequest(ProtocolVersion, NextRequestId, @@ -844,36 +935,54 @@ public void RequestWrite(byte[] handle, offset, length, response => - { - writeCompleted?.Invoke(response); + { + writeCompleted?.Invoke(response); - exception = GetSftpException(response); - if (wait != null) - { - _ = wait.Set(); - } - }); + exception = GetSftpException(response); + if (wait != null) + { + _ = wait.Set(); + } + }); SendRequest(request); - if (wait != null) + if (wait is not null) { WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } } + /// + /// Asynchronouly performs a SSH_FXP_WRITE request. + /// + /// The handle. + /// The the zero-based offset (in bytes) relative to the beginning of the file that the write must start at. + /// The buffer holding the data to write. + /// the zero-based offset in at which to begin taking bytes to write. + /// The length (in bytes) of the data to write. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_WRITE request. + /// public async Task RequestWriteAsync(byte[] handle, ulong serverOffset, byte[] data, int offset, int length, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { SendRequest(new SftpWriteRequest(ProtocolVersion, NextRequestId, @@ -883,16 +992,16 @@ public async Task RequestWriteAsync(byte[] handle, ulong serverOffset, byte[] da offset, length, response => + { + if (response.StatusCode == StatusCodes.Ok) { - if (response.StatusCode == StatusCodes.Ok) - { - _ = tcs.TrySetResult(true); - } - else - { - _ = tcs.TrySetException(GetSftpException(response)); - } - })); + _ = tcs.TrySetResult(true); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } + })); _ = await tcs.Task.ConfigureAwait(false); } @@ -917,22 +1026,24 @@ public SftpFileAttributes RequestLStat(string path) path, _encoding, response => - { - attributes = response.Attributes; - _ = wait.Set(); - }, + { + attributes = response.Attributes; + _ = wait.Set(); + }, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -958,13 +1069,13 @@ public SFtpStatAsyncResult BeginLStat(string path, AsyncCallback callback, objec path, _encoding, response => - { - asyncResult.SetAsCompleted(response.Attributes, completedSynchronously: false); - }, + { + asyncResult.SetAsCompleted(response.Attributes, completedSynchronously: false); + }, response => - { - asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false); - }); + { + asyncResult.SetAsCompleted(GetSftpException(response), completedSynchronously: false); + }); SendRequest(request); return asyncResult; @@ -1006,7 +1117,7 @@ public SftpFileAttributes EndLStat(SFtpStatAsyncResult asyncResult) /// Performs SSH_FXP_FSTAT request. /// /// The handle. - /// if set to returns instead of throwing an exception. + /// If set to , returns instead of throwing an exception. /// /// File attributes. /// @@ -1021,22 +1132,24 @@ public SftpFileAttributes RequestFStat(byte[] handle, bool nullOnError) NextRequestId, handle, response => - { - attributes = response.Attributes; - _ = wait.Set(); - }, + { + attributes = response.Attributes; + _ = wait.Set(); + }, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (exception != null && !nullOnError) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (!nullOnError && exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1044,13 +1157,26 @@ public SftpFileAttributes RequestFStat(byte[] handle, bool nullOnError) return attributes; } + /// + /// Asynchronously performs a SSH_FXP_FSTAT request. + /// + /// The handle. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_FSTAT request. The value of its + /// contains the file attributes of the specified handle. + /// public async Task RequestFStatAsync(byte[] handle, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { SendRequest(new SftpFStatRequest(ProtocolVersion, NextRequestId, @@ -1079,17 +1205,19 @@ public void RequestSetStat(string path, SftpFileAttributes attributes) _encoding, attributes, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1111,17 +1239,19 @@ public void RequestFSetStat(byte[] handle, SftpFileAttributes attributes) handle, attributes, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1131,7 +1261,7 @@ public void RequestFSetStat(byte[] handle, SftpFileAttributes attributes) /// Performs SSH_FXP_OPENDIR request. /// /// The path. - /// if set to returns instead of throwing an exception. + /// If set to , returns instead of throwing an exception. /// File handle. public byte[] RequestOpenDir(string path, bool nullOnError = false) { @@ -1146,22 +1276,24 @@ public byte[] RequestOpenDir(string path, bool nullOnError = false) path, _encoding, response => - { - handle = response.Handle; - _ = wait.Set(); - }, + { + handle = response.Handle; + _ = wait.Set(); + }, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (!nullOnError && exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (!nullOnError && exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1169,13 +1301,26 @@ public byte[] RequestOpenDir(string path, bool nullOnError = false) return handle; } + /// + /// Asynchronously performs a SSH_FXP_OPENDIR request. + /// + /// The path. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_OPENDIR request. The value of its + /// contains the handle of the specified path. + /// public async Task RequestOpenDirAsync(string path, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { SendRequest(new SftpOpenDirRequest(ProtocolVersion, NextRequestId, @@ -1191,8 +1336,11 @@ public async Task RequestOpenDirAsync(string path, CancellationToken can /// /// Performs SSH_FXP_READDIR request. /// - /// The handle. - /// + /// The handle of the directory to read. + /// + /// A where the key is the name of a file in + /// the directory and the value is the of the file. + /// public KeyValuePair[] RequestReadDir(byte[] handle) { SshException exception = null; @@ -1205,26 +1353,28 @@ public KeyValuePair[] RequestReadDir(byte[] handle) NextRequestId, handle, response => - { - result = response.Files; - _ = wait.Set(); - }, + { + result = response.Files; + _ = wait.Set(); + }, response => + { + if (response.StatusCode != StatusCodes.Eof) { - if (response.StatusCode != StatusCodes.Eof) - { - exception = GetSftpException(response); - } + exception = GetSftpException(response); + } - _ = wait.Set(); - }); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1232,29 +1382,44 @@ public KeyValuePair[] RequestReadDir(byte[] handle) return result; } + /// + /// Performs a SSH_FXP_READDIR request. + /// + /// The handle of the directory to read. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_READDIR request. The value of its + /// contains a where the + /// key is the name of a file in the directory and the value is the + /// of the file. + /// public async Task[]> RequestReadDirAsync(byte[] handle, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var tcs = new TaskCompletionSource[]>(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource[]>) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(s => ((TaskCompletionSource[]>) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(s => ((TaskCompletionSource[]>) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { SendRequest(new SftpReadDirRequest(ProtocolVersion, NextRequestId, handle, response => tcs.TrySetResult(response.Files), response => + { + if (response.StatusCode == StatusCodes.Eof) { - if (response.StatusCode == StatusCodes.Eof) - { - _ = tcs.TrySetResult(null); - } - else - { - _ = tcs.TrySetException(GetSftpException(response)); - } - })); + _ = tcs.TrySetResult(null); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } + })); return await tcs.Task.ConfigureAwait(false); } @@ -1275,45 +1440,59 @@ public void RequestRemove(string path) path, _encoding, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } } + /// + /// Asynchronously performs a SSH_FXP_REMOVE request. + /// + /// The path. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_REMOVE request. + /// public async Task RequestRemoveAsync(string path, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { SendRequest(new SftpRemoveRequest(ProtocolVersion, NextRequestId, path, _encoding, response => + { + if (response.StatusCode == StatusCodes.Ok) { - if (response.StatusCode == StatusCodes.Ok) - { - _ = tcs.TrySetResult(true); - } - else - { - _ = tcs.TrySetException(GetSftpException(response)); - } - })); + _ = tcs.TrySetResult(true); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } + })); _ = await tcs.Task.ConfigureAwait(false); } @@ -1334,17 +1513,19 @@ public void RequestMkDir(string path) path, _encoding, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1365,17 +1546,19 @@ public void RequestRmDir(string path) path, _encoding, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1402,22 +1585,24 @@ internal KeyValuePair[] RequestRealPath(string path, path, _encoding, response => - { - result = response.Files; - _ = wait.Set(); - }, + { + result = response.Files; + _ = wait.Set(); + }, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (!nullOnError && exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (!nullOnError && exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1431,7 +1616,11 @@ internal async Task[]> RequestRealPathA var tcs = new TaskCompletionSource[]>(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource[]>) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(s => ((TaskCompletionSource[]>) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(s => ((TaskCompletionSource[]>) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { SendRequest(new SftpRealPathRequest(ProtocolVersion, NextRequestId, @@ -1439,15 +1628,15 @@ internal async Task[]> RequestRealPathA _encoding, response => tcs.TrySetResult(response.Files), response => + { + if (nullOnError) { - if (nullOnError) - { - _ = tcs.TrySetResult(null); - } - else - { - _ = tcs.TrySetException(GetSftpException(response)); - } + _ = tcs.TrySetResult(null); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } })); return await tcs.Task.ConfigureAwait(false); @@ -1531,22 +1720,24 @@ public SftpFileAttributes RequestStat(string path, bool nullOnError = false) path, _encoding, response => - { - attributes = response.Attributes; - _ = wait.Set(); - }, + { + attributes = response.Attributes; + _ = wait.Set(); + }, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (!nullOnError && exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (!nullOnError && exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1632,29 +1823,44 @@ public void RequestRename(string oldPath, string newPath) newPath, _encoding, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } } + /// + /// Asynchronously performs a SSH_FXP_RENAME request. + /// + /// The old path. + /// The new path. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the asynchronous SSH_FXP_RENAME request. + /// public async Task RequestRenameAsync(string oldPath, string newPath, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { SendRequest(new SftpRenameRequest(ProtocolVersion, NextRequestId, @@ -1662,16 +1868,16 @@ public async Task RequestRenameAsync(string oldPath, string newPath, Cancellatio newPath, _encoding, response => + { + if (response.StatusCode == StatusCodes.Ok) { - if (response.StatusCode == StatusCodes.Ok) - { - _ = tcs.TrySetResult(true); - } - else - { - _ = tcs.TrySetException(GetSftpException(response)); - } - })); + _ = tcs.TrySetResult(true); + } + else + { + _ = tcs.TrySetException(GetSftpException(response)); + } + })); _ = await tcs.Task.ConfigureAwait(false); } @@ -1681,8 +1887,11 @@ public async Task RequestRenameAsync(string oldPath, string newPath, Cancellatio /// Performs SSH_FXP_READLINK request. /// /// The path. - /// if set to returns null instead of throwing an exception. - /// + /// if set to returns instead of throwing an exception. + /// + /// An array of where the key is the name of + /// a file and the value is the of the file. + /// internal KeyValuePair[] RequestReadLink(string path, bool nullOnError = false) { if (ProtocolVersion < 3) @@ -1701,22 +1910,24 @@ internal KeyValuePair[] RequestReadLink(string path, path, _encoding, response => - { - result = response.Files; - _ = wait.Set(); - }, + { + result = response.Files; + _ = wait.Set(); + }, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (!nullOnError && exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (!nullOnError && exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1746,17 +1957,19 @@ public void RequestSymLink(string linkpath, string targetpath) targetpath, _encoding, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); SendRequest(request); WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1784,10 +1997,10 @@ public void RequestPosixRename(string oldPath, string newPath) newPath, _encoding, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); if (!_supportedExtensions.ContainsKey(request.Name)) { @@ -1799,7 +2012,9 @@ public void RequestPosixRename(string oldPath, string newPath) WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1831,15 +2046,15 @@ public SftpFileSytemInformation RequestStatVfs(string path, bool nullOnError = f path, _encoding, response => - { - information = response.GetReply().Information; - _ = wait.Set(); - }, + { + information = response.GetReply().Information; + _ = wait.Set(); + }, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); if (!_supportedExtensions.ContainsKey(request.Name)) { @@ -1851,7 +2066,9 @@ public SftpFileSytemInformation RequestStatVfs(string path, bool nullOnError = f WaitOnHandle(wait, OperationTimeout); } - if (!nullOnError && exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (!nullOnError && exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1859,6 +2076,16 @@ public SftpFileSytemInformation RequestStatVfs(string path, bool nullOnError = f return information; } + /// + /// Asynchronously performs a statvfs@openssh.com extended request. + /// + /// The path. + /// The token to monitor for cancellation requests. + /// + /// A task that represents the statvfs@openssh.com extended request. The value of its + /// contains the file system information for the specified + /// path. + /// public async Task RequestStatVfsAsync(string path, CancellationToken cancellationToken) { if (ProtocolVersion < 3) @@ -1870,7 +2097,11 @@ public async Task RequestStatVfsAsync(string path, Can var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - using (cancellationToken.Register((s) => ((TaskCompletionSource) s).TrySetCanceled(), tcs, useSynchronizationContext: false)) +#if NET || NETSTANDARD2_1_OR_GREATER + await using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false).ConfigureAwait(continueOnCapturedContext: false)) +#else + using (cancellationToken.Register(s => ((TaskCompletionSource) s).TrySetCanceled(cancellationToken), tcs, useSynchronizationContext: false)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { SendRequest(new StatVfsRequest(ProtocolVersion, NextRequestId, @@ -1909,15 +2140,15 @@ internal SftpFileSytemInformation RequestFStatVfs(byte[] handle, bool nullOnErro NextRequestId, handle, response => - { - information = response.GetReply().Information; - _ = wait.Set(); - }, + { + information = response.GetReply().Information; + _ = wait.Set(); + }, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); if (!_supportedExtensions.ContainsKey(request.Name)) { @@ -1929,7 +2160,9 @@ internal SftpFileSytemInformation RequestFStatVfs(byte[] handle, bool nullOnErro WaitOnHandle(wait, OperationTimeout); } - if (!nullOnError && exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (!nullOnError && exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -1958,10 +2191,10 @@ internal void HardLink(string oldPath, string newPath) oldPath, newPath, response => - { - exception = GetSftpException(response); - _ = wait.Set(); - }); + { + exception = GetSftpException(response); + _ = wait.Set(); + }); if (!_supportedExtensions.ContainsKey(request.Name)) { @@ -1973,7 +2206,9 @@ internal void HardLink(string oldPath, string newPath) WaitOnHandle(wait, OperationTimeout); } - if (exception != null) +#pragma warning disable CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed + if (exception is not null) +#pragma warning restore CA1508 // Avoid dead conditional code; Remove when we upgrade to newer SDK in which bug is fixed { throw exception; } @@ -2033,7 +2268,7 @@ public uint CalculateOptimalWriteLength(uint bufferSize, byte[] handle) * WinSCP uses data length of 32739 bytes (total 32768 bytes; 32739 + 25 + 4 bytes for handle) */ - var lengthOfNonDataProtocolFields = 25u + (uint)handle.Length; + var lengthOfNonDataProtocolFields = 25u + (uint) handle.Length; var maximumPacketSize = Channel.RemotePacketSize; return Math.Min(bufferSize, maximumPacketSize) - lengthOfNonDataProtocolFields; } @@ -2061,7 +2296,7 @@ private void HandleResponse(SftpResponse response) lock (_requests) { _ = _requests.TryGetValue(response.ResponseId, out request); - if (request != null) + if (request is not null) { _ = _requests.Remove(response.ResponseId); } diff --git a/src/Renci.SshNet/Sftp/StatusCodes.cs b/src/Renci.SshNet/Sftp/StatusCodes.cs index 101b8c0bc..12997a47e 100644 --- a/src/Renci.SshNet/Sftp/StatusCodes.cs +++ b/src/Renci.SshNet/Sftp/StatusCodes.cs @@ -1,135 +1,165 @@ -锘 -namespace Renci.SshNet.Sftp +锘縩amespace Renci.SshNet.Sftp { internal enum StatusCodes : uint { /// - /// SSH_FX_OK + /// SSH_FX_OK. /// Ok = 0, + /// - /// SSH_FX_EOF + /// SSH_FX_EOF. /// Eof = 1, + /// - /// SSH_FX_NO_SUCH_FILE + /// SSH_FX_NO_SUCH_FILE. /// NoSuchFile = 2, + /// - /// SSH_FX_PERMISSION_DENIED + /// SSH_FX_PERMISSION_DENIED. /// PermissionDenied = 3, + /// - /// SSH_FX_FAILURE + /// SSH_FX_FAILURE. /// Failure = 4, + /// - /// SSH_FX_BAD_MESSAGE + /// SSH_FX_BAD_MESSAGE. /// BadMessage = 5, + /// - /// SSH_FX_NO_CONNECTION + /// SSH_FX_NO_CONNECTION. /// NoConnection = 6, + /// - /// SSH_FX_CONNECTION_LOST + /// SSH_FX_CONNECTION_LOST. /// ConnectionLost = 7, + /// - /// SSH_FX_OP_UNSUPPORTED + /// SSH_FX_OP_UNSUPPORTED. /// OperationUnsupported = 8, + /// - /// SSH_FX_INVALID_HANDLE + /// SSH_FX_INVALID_HANDLE. /// InvalidHandle = 9, + /// - /// SSH_FX_NO_SUCH_PATH + /// SSH_FX_NO_SUCH_PATH. /// NoSuchPath = 10, + /// - /// SSH_FX_FILE_ALREADY_EXISTS + /// SSH_FX_FILE_ALREADY_EXISTS. /// FileAlreadyExists = 11, + /// - /// SSH_FX_WRITE_PROTECT + /// SSH_FX_WRITE_PROTECT. /// WriteProtect = 12, + /// - /// SSH_FX_NO_MEDIA + /// SSH_FX_NO_MEDIA. /// NoMedia = 13, + /// - /// SSH_FX_NO_SPACE_ON_FILESYSTEM + /// SSH_FX_NO_SPACE_ON_FILESYSTEM. /// NoSpaceOnFilesystem = 14, + /// - /// SSH_FX_QUOTA_EXCEEDED + /// SSH_FX_QUOTA_EXCEEDED. /// QuotaExceeded = 15, + /// - /// SSH_FX_UNKNOWN_PRINCIPAL + /// SSH_FX_UNKNOWN_PRINCIPAL. /// UnknownPrincipal = 16, + /// - /// SSH_FX_LOCK_CONFLICT + /// SSH_FX_LOCK_CONFLICT. /// LockConflict = 17, + /// - /// SSH_FX_DIR_NOT_EMPTY + /// SSH_FX_DIR_NOT_EMPTY. /// DirNotEmpty = 18, + /// - /// SSH_FX_NOT_A_DIRECTORY + /// SSH_FX_NOT_A_DIRECTORY. /// NotDirectory = 19, + /// - /// SSH_FX_INVALID_FILENAME + /// SSH_FX_INVALID_FILENAME. /// InvalidFilename = 20, + /// - /// SSH_FX_LINK_LOOP + /// SSH_FX_LINK_LOOP. /// LinkLoop = 21, + /// - /// SSH_FX_CANNOT_DELETE + /// SSH_FX_CANNOT_DELETE. /// CannotDelete = 22, + /// - /// SSH_FX_INVALID_PARAMETER + /// SSH_FX_INVALID_PARAMETER. /// InvalidParameter = 23, + /// - /// SSH_FX_FILE_IS_A_DIRECTORY + /// SSH_FX_FILE_IS_A_DIRECTORY. /// FileIsADirectory = 24, + /// - /// SSH_FX_BYTE_RANGE_LOCK_CONFLICT + /// SSH_FX_BYTE_RANGE_LOCK_CONFLICT. /// ByteRangeLockConflict = 25, + /// - /// SSH_FX_BYTE_RANGE_LOCK_REFUSED + /// SSH_FX_BYTE_RANGE_LOCK_REFUSED. /// ByteRangeLockRefused = 26, + /// - /// SSH_FX_DELETE_PENDING + /// SSH_FX_DELETE_PENDING. /// DeletePending = 27, + /// - /// SSH_FX_FILE_CORRUPT + /// SSH_FX_FILE_CORRUPT. /// FileCorrupt = 28, + /// - /// SSH_FX_OWNER_INVALID + /// SSH_FX_OWNER_INVALID. /// OwnerInvalid = 29, + /// - /// SSH_FX_GROUP_INVALID + /// SSH_FX_GROUP_INVALID. /// GroupInvalid = 30, + /// - /// SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK + /// SSH_FX_NO_MATCHING_BYTE_RANGE_LOCK. /// - NoMatchingByteRangeLock = 31, + NoMatchingByteRangeLock = 31 } } diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index 5467ceb92..aa30efadb 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -1,16 +1,17 @@ 锘縰sing System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.IO; using System.Globalization; +using System.IO; using System.Net; +using System.Runtime.CompilerServices; using System.Text; using System.Threading; +using System.Threading.Tasks; + using Renci.SshNet.Abstractions; using Renci.SshNet.Common; using Renci.SshNet.Sftp; -using System.Threading.Tasks; -using System.Runtime.CompilerServices; namespace Renci.SshNet { @@ -213,7 +214,7 @@ public SftpClient(string host, string username, string password) /// Authentication username. /// Authentication private key file(s) . /// is . - /// is invalid. -or- is null or contains only whitespace characters. + /// is invalid. -or- is or contains only whitespace characters. /// is not within and . [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] public SftpClient(string host, int port, string username, params IPrivateKeySource[] keyFiles) @@ -448,18 +449,17 @@ public void RenameFile(string oldPath, string newPath) } /// - /// Asynchronously renames remote file from old path to new path. + /// Renames remote file from old path to new path. /// /// Path to the old file location. /// Path to the new file location. - /// The to observe. - /// A that represents the asynchronous rename operation. - /// is . -or- or is . + /// if set to then perform a posix rename. + /// is . -or- or is . /// Client is not connected. /// Permission to rename the file was denied by the remote host. -or- A SSH command was denied by the server. - /// A SSH error where is the message from the remote host. + /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. - public async Task RenameFileAsync(string oldPath, string newPath, CancellationToken cancellationToken) + public void RenameFile(string oldPath, string newPath, bool isPosix) { CheckDisposed(); @@ -478,25 +478,33 @@ public async Task RenameFileAsync(string oldPath, string newPath, CancellationTo throw new SshConnectionException("Client not connected."); } - cancellationToken.ThrowIfCancellationRequested(); + var oldFullPath = _sftpSession.GetCanonicalPath(oldPath); - var oldFullPath = await _sftpSession.GetCanonicalPathAsync(oldPath, cancellationToken).ConfigureAwait(false); - var newFullPath = await _sftpSession.GetCanonicalPathAsync(newPath, cancellationToken).ConfigureAwait(false); - await _sftpSession.RequestRenameAsync(oldFullPath, newFullPath, cancellationToken).ConfigureAwait(false); + var newFullPath = _sftpSession.GetCanonicalPath(newPath); + + if (isPosix) + { + _sftpSession.RequestPosixRename(oldFullPath, newFullPath); + } + else + { + _sftpSession.RequestRename(oldFullPath, newFullPath); + } } /// - /// Renames remote file from old path to new path. + /// Asynchronously renames remote file from old path to new path. /// /// Path to the old file location. /// Path to the new file location. - /// if set to then perform a posix rename. - /// is . -or- or is . + /// The to observe. + /// A that represents the asynchronous rename operation. + /// is . -or- or is . /// Client is not connected. /// Permission to rename the file was denied by the remote host. -or- A SSH command was denied by the server. - /// A SSH error where is the message from the remote host. + /// A SSH error where is the message from the remote host. /// The method was called after the client was disposed. - public void RenameFile(string oldPath, string newPath, bool isPosix) + public async Task RenameFileAsync(string oldPath, string newPath, CancellationToken cancellationToken) { CheckDisposed(); @@ -515,18 +523,11 @@ public void RenameFile(string oldPath, string newPath, bool isPosix) throw new SshConnectionException("Client not connected."); } - var oldFullPath = _sftpSession.GetCanonicalPath(oldPath); - - var newFullPath = _sftpSession.GetCanonicalPath(newPath); + cancellationToken.ThrowIfCancellationRequested(); - if (isPosix) - { - _sftpSession.RequestPosixRename(oldFullPath, newFullPath); - } - else - { - _sftpSession.RequestRename(oldFullPath, newFullPath); - } + var oldFullPath = await _sftpSession.GetCanonicalPathAsync(oldPath, cancellationToken).ConfigureAwait(false); + var newFullPath = await _sftpSession.GetCanonicalPathAsync(newPath, cancellationToken).ConfigureAwait(false); + await _sftpSession.RequestRenameAsync(oldFullPath, newFullPath, cancellationToken).ConfigureAwait(false); } /// @@ -735,7 +736,7 @@ public ISftpFile Get(string path) } /// - /// Checks whether file or directory exists; + /// Checks whether file or directory exists. /// /// The path. /// @@ -762,22 +763,24 @@ public bool Exists(string path) var fullPath = _sftpSession.GetCanonicalPath(path); - // using SSH_FXP_REALPATH is not an alternative as the SFTP specification has not always - // been clear on how the server should respond when the specified path is not present on - // the server: - // - // SSH 1 to 4: - // No mention of how the server should respond if the path is not present on the server. - // - // SSH 5: - // The server SHOULD fail the request if the path is not present on the server. - // - // SSH 6: - // Draft 06: The server SHOULD fail the request if the path is not present on the server. - // Draft 07 to 13: The server MUST NOT fail the request if the path does not exist. - // - // Note that SSH 6 (draft 06 and forward) allows for more control options, but we - // currently only support up to v3. + /* + * Using SSH_FXP_REALPATH is not an alternative as the SFTP specification has not always + * been clear on how the server should respond when the specified path is not present on + * the server: + * + * SSH 1 to 4: + * No mention of how the server should respond if the path is not present on the server. + * + * SSH 5: + * The server SHOULD fail the request if the path is not present on the server. + * + * SSH 6: + * Draft 06: The server SHOULD fail the request if the path is not present on the server. + * Draft 07 to 13: The server MUST NOT fail the request if the path does not exist. + * + * Note that SSH 6 (draft 06 and forward) allows for more control options, but we + * currently only support up to v3. + */ try { @@ -1233,12 +1236,12 @@ public async Task GetStatusAsync(string path, Cancella /// /// The file to append the lines to. The file is created if it does not already exist. /// The lines to append to the file. - /// is -or- is . + /// is . -or- is . /// Client is not connected. /// The specified path is invalid, or its directory was not found on the remote host. /// The method was called after the client was disposed. /// - /// The characters are written to the file using UTF-8 encoding without a Byte-Order Mark (BOM) + /// The characters are written to the file using UTF-8 encoding without a byte-order mark (BOM). /// public void AppendAllLines(string path, IEnumerable contents) { @@ -1710,10 +1713,13 @@ public string[] ReadAllLines(string path) /// The method was called after the client was disposed. public string[] ReadAllLines(string path, Encoding encoding) { - // we use the default buffer size for StreamReader - which is 1024 bytes - and the configured buffer size - // for the SftpFileStream; may want to revisit this later + /* + * We use the default buffer size for StreamReader - which is 1024 bytes - and the configured buffer size + * for the SftpFileStream. We may want to revisit this later. + */ var lines = new List(); + using (var stream = new StreamReader(OpenRead(path), encoding)) { while (!stream.EndOfStream) @@ -1721,6 +1727,7 @@ public string[] ReadAllLines(string path, Encoding encoding) lines.Add(stream.ReadLine()); } } + return lines.ToArray(); } @@ -1752,8 +1759,10 @@ public string ReadAllText(string path) /// The method was called after the client was disposed. public string ReadAllText(string path, Encoding encoding) { - // we use the default buffer size for StreamReader - which is 1024 bytes - and the configured buffer size - // for the SftpFileStream; may want to revisit this later + /* + * We use the default buffer size for StreamReader - which is 1024 bytes - and the configured buffer size + * for the SftpFileStream. We may want to revisit this later. + */ using (var stream = new StreamReader(OpenRead(path), encoding)) { @@ -2074,15 +2083,6 @@ public void SetAttributes(string path, SftpFileAttributes fileAttributes) _sftpSession.RequestSetStat(fullPath, fileAttributes); } - // Please don't forget this when you implement these methods: is . - //public FileSecurity GetAccessControl(string path); - //public FileSecurity GetAccessControl(string path, AccessControlSections includeSections); - //public DateTime GetCreationTime(string path); - //public DateTime GetCreationTimeUtc(string path); - //public void SetAccessControl(string path, FileSecurity fileSecurity); - //public void SetCreationTime(string path, DateTime creationTime); - //public void SetCreationTimeUtc(string path, DateTime creationTimeUtc); - #endregion // File Methods #region SynchronizeDirectories @@ -2099,7 +2099,7 @@ public void SetAttributes(string path, SftpFileAttributes fileAttributes) /// is . /// is or contains only whitespace. /// was not found on the remote host. - /// If a problem occurs while copying the file + /// If a problem occurs while copying the file. public IEnumerable SynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern) { if (sourcePath is null) @@ -2128,7 +2128,7 @@ public IEnumerable SynchronizeDirectories(string sourcePath, string de /// /// is . /// is or contains only whitespace. - /// If a problem occurs while copying the file + /// If a problem occurs while copying the file. public IAsyncResult BeginSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, AsyncCallback asyncCallback, object state) { if (sourcePath is null) @@ -2180,7 +2180,7 @@ public IEnumerable EndSynchronizeDirectories(IAsyncResult asyncResult) return ar.EndInvoke(); } - private IEnumerable InternalSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, SftpSynchronizeDirectoriesAsyncResult asynchResult) + private List InternalSynchronizeDirectories(string sourcePath, string destinationPath, string searchPattern, SftpSynchronizeDirectoriesAsyncResult asynchResult) { if (!Directory.Exists(sourcePath)) { @@ -2228,8 +2228,7 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, var isDifferent = true; if (destDict.TryGetValue(localFile.Name, out var remoteFile)) { - // TODO: Use md5 to detect a difference - //ltang: File exists at the destination => Using filesize to detect the difference + // File exists at the destination, use filesize to detect if there's a difference isDifferent = localFile.Length != remoteFile.Length; } @@ -2238,7 +2237,9 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, var remoteFileName = string.Format(CultureInfo.InvariantCulture, @"{0}/{1}", destinationPath, localFile.Name); try { +#pragma warning disable CA2000 // Dispose objects before losing scope; false positive using (var file = File.OpenRead(localFile.FullName)) +#pragma warning restore CA2000 // Dispose objects before losing scope; false positive { InternalUploadFile(file, remoteFileName, uploadFlag, asyncResult: null, uploadCallback: null); } @@ -2273,7 +2274,7 @@ private IEnumerable InternalSynchronizeDirectories(string sourcePath, /// /// is . /// Client not connected. - private IEnumerable InternalListDirectory(string path, Action listCallback) + private List InternalListDirectory(string path, Action listCallback) { if (path is null) { @@ -2291,7 +2292,11 @@ private IEnumerable InternalListDirectory(string path, Action li var basePath = fullPath; - if (!basePath.EndsWith("/")) +#if NET || NETSTANDARD2_1_OR_GREATER + if (!basePath.EndsWith('/')) +#else + if (!basePath.EndsWith("/", StringComparison.Ordinal)) +#endif // NET || NETSTANDARD2_1_OR_GREATER { basePath = string.Format("{0}/", fullPath); } @@ -2309,10 +2314,10 @@ private IEnumerable InternalListDirectory(string path, Action li f.Value)); } - // Call callback to report number of files read + // Call callback to report number of files read if (listCallback is not null) { - // Execute callback on different thread + // Execute callback on different thread ThreadAbstraction.ExecuteThread(() => listCallback(result.Count)); } @@ -2377,10 +2382,10 @@ private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncR if (downloadCallback is not null) { - // copy offset to ensure it's not modified between now and execution of callback + // Copy offset to ensure it's not modified between now and execution of callback var downloadOffset = totalBytesRead; - // Execute callback on different thread + // Execute callback on different thread ThreadAbstraction.ExecuteThread(() => { downloadCallback(downloadOffset); }); } } @@ -2447,10 +2452,10 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo _ = Interlocked.Decrement(ref expectedResponses); _ = responseReceivedWaitHandle.Set(); - // Call callback to report number of bytes written + // Call callback to report number of bytes written if (uploadCallback is not null) { - // Execute callback on different thread + // Execute callback on different thread ThreadAbstraction.ExecuteThread(() => uploadCallback(writtenBytes)); } } @@ -2464,13 +2469,14 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo } else if (expectedResponses > 0) { - // Wait for expectedResponses to change + // Wait for expectedResponses to change _sftpSession.WaitOnHandle(responseReceivedWaitHandle, _operationTimeout); } } while (expectedResponses > 0 || bytesRead > 0); _sftpSession.RequestClose(handle); + responseReceivedWaitHandle.Dispose(); } /// @@ -2501,7 +2507,7 @@ protected override void OnDisconnecting() } /// - /// Releases unmanaged and - optionally - managed resources + /// Releases unmanaged and - optionally - managed resources. /// /// to release both managed and unmanaged resources; to release only unmanaged resources. protected override void Dispose(bool disposing) diff --git a/src/Renci.SshNet/Shell.cs b/src/Renci.SshNet/Shell.cs index 0f80c3ca7..4a73e58fb 100644 --- a/src/Renci.SshNet/Shell.cs +++ b/src/Renci.SshNet/Shell.cs @@ -24,9 +24,9 @@ public class Shell : IDisposable private readonly Stream _outputStream; private readonly Stream _extendedOutputStream; private readonly int _bufferSize; - private EventWaitHandle _dataReaderTaskCompleted; + private ManualResetEvent _dataReaderTaskCompleted; private IChannelSession _channel; - private EventWaitHandle _channelClosedWaitHandle; + private AutoResetEvent _channelClosedWaitHandle; private Stream _input; /// @@ -130,7 +130,7 @@ public void Start() var readTask = _input.ReadAsync(buffer, 0, buffer.Length); var readWaitHandle = ((IAsyncResult) readTask).AsyncWaitHandle; - if (WaitHandle.WaitAny(new[] {readWaitHandle, _channelClosedWaitHandle}) == 0) + if (WaitHandle.WaitAny(new[] { readWaitHandle, _channelClosedWaitHandle }) == 0) { var read = readTask.GetAwaiter().GetResult(); _channel.SendData(buffer, 0, read); diff --git a/src/Renci.SshNet/ShellStream.cs b/src/Renci.SshNet/ShellStream.cs index 80097bafe..ce57072d5 100644 --- a/src/Renci.SshNet/ShellStream.cs +++ b/src/Renci.SshNet/ShellStream.cs @@ -155,10 +155,14 @@ public override bool CanWrite /// Methods were called after the stream was closed. public override void Flush() { +#if NET7_0_OR_GREATER + ObjectDisposedException.ThrowIf(_channel is null, this); +#else if (_channel is null) { - throw new ObjectDisposedException("ShellStream"); + throw new ObjectDisposedException(GetType().FullName); } +#endif // NET7_0_OR_GREATER if (_outgoing.Count > 0) { @@ -199,36 +203,6 @@ public override long Position set { throw new NotSupportedException(); } } - /// - /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. - /// - /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source. - /// The zero-based byte offset in at which to begin storing the data read from the current stream. - /// The maximum number of bytes to be read from the current stream. - /// - /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. - /// - /// The sum of and is larger than the buffer length. - /// is . - /// or is negative. - /// An I/O error occurs. - /// The stream does not support reading. - /// Methods were called after the stream was closed. - public override int Read(byte[] buffer, int offset, int count) - { - var i = 0; - - lock (_incoming) - { - for (; i < count && _incoming.Count > 0; i++) - { - buffer[offset + i] = _incoming.Dequeue(); - } - } - - return i; - } - /// /// This method is not supported. /// @@ -257,31 +231,6 @@ public override void SetLength(long value) throw new NotSupportedException(); } - /// - /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. - /// - /// An array of bytes. This method copies bytes from to the current stream. - /// The zero-based byte offset in at which to begin copying bytes to the current stream. - /// The number of bytes to be written to the current stream. - /// The sum of and is greater than the buffer length. - /// is . - /// or is negative. - /// An I/O error occurs. - /// The stream does not support writing. - /// Methods were called after the stream was closed. - public override void Write(byte[] buffer, int offset, int count) - { - foreach (var b in buffer.Take(offset, count)) - { - if (_outgoing.Count == _bufferSize) - { - Flush(); - } - - _outgoing.Enqueue(b); - } - } - /// /// Expects the specified expression and performs action when one is found. /// @@ -351,6 +300,95 @@ public void Expect(TimeSpan timeout, params ExpectAction[] expectActions) while (!expectedFound); } + /// + /// Expects the expression specified by text. + /// + /// The text to expect. + /// + /// Text available in the shell that ends with expected text. + /// + public string Expect(string text) + { + return Expect(new Regex(Regex.Escape(text)), Session.InfiniteTimeSpan); + } + + /// + /// Expects the expression specified by text. + /// + /// The text to expect. + /// Time to wait for input. + /// + /// The text available in the shell that ends with expected text, or if the specified time has elapsed. + /// + public string Expect(string text, TimeSpan timeout) + { + return Expect(new Regex(Regex.Escape(text)), timeout); + } + + /// + /// Expects the expression specified by regular expression. + /// + /// The regular expression to expect. + /// + /// The text available in the shell that contains all the text that ends with expected expression. + /// + public string Expect(Regex regex) + { + return Expect(regex, TimeSpan.Zero); + } + + /// + /// Expects the expression specified by regular expression. + /// + /// The regular expression to expect. + /// Time to wait for input. + /// + /// The text available in the shell that contains all the text that ends with expected expression, + /// or if the specified time has elapsed. + /// + public string Expect(Regex regex, TimeSpan timeout) + { + var text = string.Empty; + + while (true) + { + lock (_incoming) + { + if (_incoming.Count > 0) + { + text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count); + } + + var match = regex.Match(text); + + if (match.Success) + { + // Remove processed items from the queue + for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++) + { + _ = _incoming.Dequeue(); + } + + break; + } + } + + if (timeout.Ticks > 0) + { + if (!_dataReceived.WaitOne(timeout)) + { + return null; + } + } + else + { + _ = _dataReceived.WaitOne(); + } + } + + return text; + } + /// /// Begins the expect. /// @@ -400,7 +438,9 @@ public IAsyncResult BeginExpect(AsyncCallback callback, object state, params Exp /// /// An that references the asynchronous operation. /// +#pragma warning disable CA1859 // Use concrete types when possible for improved performance public IAsyncResult BeginExpect(TimeSpan timeout, AsyncCallback callback, object state, params ExpectAction[] expectActions) +#pragma warning restore CA1859 // Use concrete types when possible for improved performance { var text = string.Empty; @@ -481,6 +521,9 @@ public IAsyncResult BeginExpect(TimeSpan timeout, AsyncCallback callback, object /// Ends the execute. /// /// The async result. + /// + /// Text available in the shell that ends with expected text. + /// /// 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. public string EndExpect(IAsyncResult asyncResult) { @@ -493,95 +536,6 @@ public string EndExpect(IAsyncResult asyncResult) return ar.EndInvoke(); } - /// - /// Expects the expression specified by text. - /// - /// The text to expect. - /// - /// Text available in the shell that ends with expected text. - /// - public string Expect(string text) - { - return Expect(new Regex(Regex.Escape(text)), Session.InfiniteTimeSpan); - } - - /// - /// Expects the expression specified by text. - /// - /// The text to expect. - /// Time to wait for input. - /// - /// The text available in the shell that ends with expected text, or if the specified time has elapsed. - /// - public string Expect(string text, TimeSpan timeout) - { - return Expect(new Regex(Regex.Escape(text)), timeout); - } - - /// - /// Expects the expression specified by regular expression. - /// - /// The regular expression to expect. - /// - /// The text available in the shell that contains all the text that ends with expected expression. - /// - public string Expect(Regex regex) - { - return Expect(regex, TimeSpan.Zero); - } - - /// - /// Expects the expression specified by regular expression. - /// - /// The regular expression to expect. - /// Time to wait for input. - /// - /// The text available in the shell that contains all the text that ends with expected expression, - /// or if the specified time has elapsed. - /// - public string Expect(Regex regex, TimeSpan timeout) - { - var text = string.Empty; - - while (true) - { - lock (_incoming) - { - if (_incoming.Count > 0) - { - text = _encoding.GetString(_incoming.ToArray(), 0, _incoming.Count); - } - - var match = regex.Match(text); - - if (match.Success) - { - // Remove processed items from the queue - for (var i = 0; i < match.Index + match.Length && _incoming.Count > 0; i++) - { - _ = _incoming.Dequeue(); - } - - break; - } - } - - if (timeout.Ticks > 0) - { - if (!_dataReceived.WaitOne(timeout)) - { - return null; - } - } - else - { - _ = _dataReceived.WaitOne(); - } - } - - return text; - } - /// /// Reads the line from the shell. If line is not available it will block the execution and will wait for new line. /// @@ -667,6 +621,36 @@ public string Read() return text; } + /// + /// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read. + /// + /// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source. + /// The zero-based byte offset in at which to begin storing the data read from the current stream. + /// The maximum number of bytes to be read from the current stream. + /// + /// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached. + /// + /// The sum of and is larger than the buffer length. + /// is . + /// or is negative. + /// An I/O error occurs. + /// The stream does not support reading. + /// Methods were called after the stream was closed. + public override int Read(byte[] buffer, int offset, int count) + { + var i = 0; + + lock (_incoming) + { + for (; i < count && _incoming.Count > 0; i++) + { + buffer[offset + i] = _incoming.Dequeue(); + } + } + + return i; + } + /// /// Writes the specified text to the shell. /// @@ -681,15 +665,44 @@ public void Write(string text) return; } +#if NET7_0_OR_GREATER + ObjectDisposedException.ThrowIf(_channel is null, this); +#else if (_channel is null) { - throw new ObjectDisposedException("ShellStream"); + throw new ObjectDisposedException(GetType().FullName); } +#endif // NET7_0_OR_GREATER var data = _encoding.GetBytes(text); _channel.SendData(data); } + /// + /// Writes a sequence of bytes to the current stream and advances the current position within this stream by the number of bytes written. + /// + /// An array of bytes. This method copies bytes from to the current stream. + /// The zero-based byte offset in at which to begin copying bytes to the current stream. + /// The number of bytes to be written to the current stream. + /// The sum of and is greater than the buffer length. + /// is . + /// or is negative. + /// An I/O error occurs. + /// The stream does not support writing. + /// Methods were called after the stream was closed. + public override void Write(byte[] buffer, int offset, int count) + { + foreach (var b in buffer.Take(offset, count)) + { + if (_outgoing.Count == _bufferSize) + { + Flush(); + } + + _outgoing.Enqueue(b); + } + } + /// /// Writes the line to the shell. /// diff --git a/src/Renci.SshNet/SshClient.cs b/src/Renci.SshNet/SshClient.cs index 171b79775..753ab8f9f 100644 --- a/src/Renci.SshNet/SshClient.cs +++ b/src/Renci.SshNet/SshClient.cs @@ -27,7 +27,7 @@ public class SshClient : BaseClient /// private bool _isDisposed; - private Stream _inputStream; + private MemoryStream _inputStream; /// /// Gets the list of forwarded ports. @@ -68,7 +68,9 @@ public SshClient(ConnectionInfo connectionInfo) /// is not within and . [SuppressMessage("Microsoft.Reliability", "C2A000:DisposeObjectsBeforeLosingScope", Justification = "Disposed in Dispose(bool) method.")] public SshClient(string host, int port, string username, string password) +#pragma warning disable CA2000 // Dispose objects before losing scope : this(new PasswordConnectionInfo(host, port, username, password), ownsConnectionInfo: true) +#pragma warning restore CA2000 // Dispose objects before losing scope { } @@ -359,12 +361,18 @@ public Shell CreateShell(Stream input, Stream output, Stream extendedOutput) /// Client is not connected. public Shell CreateShell(Encoding encoding, string input, Stream output, Stream extendedOutput, string terminalName, uint columns, uint rows, uint width, uint height, IDictionary terminalModes, int bufferSize) { - // TODO let shell dispose of input stream when we own the stream! + /* + * TODO Issue #1224: let shell dispose of input stream when we own the stream! + */ _inputStream = new MemoryStream(); - var writer = new StreamWriter(_inputStream, encoding); - writer.Write(input); - writer.Flush(); + + using (var writer = new StreamWriter(_inputStream, encoding, bufferSize: 1024, leaveOpen: true)) + { + writer.Write(input); + writer.Flush(); + } + _ = _inputStream.Seek(0, SeekOrigin.Begin); return CreateShell(_inputStream, output, extendedOutput, terminalName, columns, rows, width, height, terminalModes, bufferSize); diff --git a/src/Renci.SshNet/SshCommand.cs b/src/Renci.SshNet/SshCommand.cs index 9bcd30342..5b93354f7 100644 --- a/src/Renci.SshNet/SshCommand.cs +++ b/src/Renci.SshNet/SshCommand.cs @@ -62,7 +62,9 @@ public class SshCommand : IDisposable /// /// /// +#pragma warning disable CA1859 // Use concrete types when possible for improved performance public Stream OutputStream { get; private set; } +#pragma warning restore CA1859 // Use concrete types when possible for improved performance /// /// Gets the extended output stream. @@ -70,7 +72,9 @@ public class SshCommand : IDisposable /// /// /// +#pragma warning disable CA1859 // Use concrete types when possible for improved performance public Stream ExtendedOutputStream { get; private set; } +#pragma warning restore CA1859 // Use concrete types when possible for improved performance /// /// Gets the command execution result. @@ -86,9 +90,14 @@ public string Result if (OutputStream != null && OutputStream.Length > 0) { - // do not dispose the StreamReader, as it would also dispose the stream - var sr = new StreamReader(OutputStream, _encoding); - _ = _result.Append(sr.ReadToEnd()); + using (var sr = new StreamReader(OutputStream, + _encoding, + detectEncodingFromByteOrderMarks: true, + bufferSize: 1024, + leaveOpen: true)) + { + _ = _result.Append(sr.ReadToEnd()); + } } return _result.ToString(); @@ -111,9 +120,14 @@ public string Error if (ExtendedOutputStream != null && ExtendedOutputStream.Length > 0) { - // do not dispose the StreamReader, as it would also dispose the stream - var sr = new StreamReader(ExtendedOutputStream, _encoding); - _ = _error.Append(sr.ReadToEnd()); + using (var sr = new StreamReader(ExtendedOutputStream, + _encoding, + detectEncodingFromByteOrderMarks: true, + bufferSize: 1024, + leaveOpen: true)) + { + _ = _error.Append(sr.ReadToEnd()); + } } return _error.ToString(); @@ -206,7 +220,9 @@ public IAsyncResult BeginExecute(AsyncCallback callback) /// CommandText property is empty. /// Client is not connected. /// Operation has timed out. +#pragma warning disable CA1859 // Use concrete types when possible for improved performance public IAsyncResult BeginExecute(AsyncCallback callback, object state) +#pragma warning restore CA1859 // Use concrete types when possible for improved performance { // Prevent from executing BeginExecute before calling EndExecute if (_asyncResult != null && !_asyncResult.EndCalled) @@ -321,10 +337,24 @@ public string EndExecute(IAsyncResult asyncResult) } } + /// + /// Cancels command execution in asynchronous scenarios. + /// + public void CancelAsync() + { + if (_channel is not null && _channel.IsOpen && _asyncResult is not null) + { + // TODO: check with Oleg if we shouldn't dispose the channel and uninitialize it ? + _channel.Dispose(); + } + } + /// /// Executes command specified by property. /// - /// Command execution result + /// + /// Command execution result. + /// /// /// /// @@ -337,18 +367,6 @@ public string Execute() return EndExecute(BeginExecute(callback: null, state: null)); } - /// - /// Cancels command execution in asynchronous scenarios. - /// - public void CancelAsync() - { - if (_channel is not null && _channel.IsOpen && _asyncResult is not null) - { - // TODO: check with Oleg if we shouldn't dispose the channel and uninitialize it ? - _channel.Dispose(); - } - } - /// /// Executes the specified command text. /// @@ -493,7 +511,6 @@ private void WaitOnHandle(WaitHandle waitHandle) throw new SshOperationTimeoutException(string.Format(CultureInfo.CurrentCulture, "Command '{0}' has timed out.", CommandText)); default: throw new SshException($"Unexpected element '{signaledElement.ToString(CultureInfo.InvariantCulture)}' signaled."); - } } diff --git a/src/Renci.SshNet/SshMessageFactory.cs b/src/Renci.SshNet/SshMessageFactory.cs index 5941c120e..efa861256 100644 --- a/src/Renci.SshNet/SshMessageFactory.cs +++ b/src/Renci.SshNet/SshMessageFactory.cs @@ -1,6 +1,7 @@ 锘縰sing System; using System.Collections.Generic; using System.Globalization; + using Renci.SshNet.Common; using Renci.SshNet.Messages; using Renci.SshNet.Messages.Authentication; @@ -13,9 +14,44 @@ internal sealed class SshMessageFactory { private readonly MessageMetadata[] _enabledMessagesByNumber; private readonly bool[] _activatedMessagesById; + private readonly object _lock = new object(); - internal static readonly MessageMetadata[] AllMessages; - private static readonly Dictionary MessagesByName; + private static readonly MessageMetadata[] AllMessages = new MessageMetadata[] + { + new MessageMetadata(0, "SSH_MSG_KEXINIT", 20), + new MessageMetadata(1, "SSH_MSG_NEWKEYS", 21), + new MessageMetadata(2, "SSH_MSG_REQUEST_FAILURE", 82), + new MessageMetadata(3, "SSH_MSG_CHANNEL_OPEN_FAILURE", 92), + new MessageMetadata(4, "SSH_MSG_CHANNEL_FAILURE", 100), + new MessageMetadata(5, "SSH_MSG_CHANNEL_EXTENDED_DATA", 95), + new MessageMetadata(6, "SSH_MSG_CHANNEL_DATA", 94), + new MessageMetadata(7, "SSH_MSG_CHANNEL_REQUEST", 98), + new MessageMetadata(8, "SSH_MSG_USERAUTH_BANNER", 53), + new MessageMetadata(9, "SSH_MSG_USERAUTH_INFO_RESPONSE", 61), + new MessageMetadata(10, "SSH_MSG_USERAUTH_FAILURE", 51), + new MessageMetadata(11, "SSH_MSG_DEBUG", 4), + new MessageMetadata(12, "SSH_MSG_GLOBAL_REQUEST", 80), + new MessageMetadata(13, "SSH_MSG_CHANNEL_OPEN", 90), + new MessageMetadata(14, "SSH_MSG_CHANNEL_OPEN_CONFIRMATION", 91), + new MessageMetadata(15, "SSH_MSG_USERAUTH_INFO_REQUEST", 60), + new MessageMetadata(16, "SSH_MSG_UNIMPLEMENTED", 3), + new MessageMetadata(17, "SSH_MSG_REQUEST_SUCCESS", 81), + new MessageMetadata(18, "SSH_MSG_CHANNEL_SUCCESS", 99), + new MessageMetadata(19, "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ", 60), + new MessageMetadata(20, "SSH_MSG_DISCONNECT", 1), + new MessageMetadata(21, "SSH_MSG_USERAUTH_SUCCESS", 52), + new MessageMetadata(22, "SSH_MSG_USERAUTH_PK_OK", 60), + new MessageMetadata(23, "SSH_MSG_IGNORE", 2), + new MessageMetadata(24, "SSH_MSG_CHANNEL_WINDOW_ADJUST", 93), + new MessageMetadata(25, "SSH_MSG_CHANNEL_EOF", 96), + new MessageMetadata(26, "SSH_MSG_CHANNEL_CLOSE", 97), + new MessageMetadata(27, "SSH_MSG_SERVICE_ACCEPT", 6), + new MessageMetadata(28, "SSH_MSG_KEX_DH_GEX_GROUP", 31), + new MessageMetadata(29, "SSH_MSG_KEXDH_REPLY", 31), + new MessageMetadata(30, "SSH_MSG_KEX_DH_GEX_REPLY", 33), + new MessageMetadata(31, "SSH_MSG_KEX_ECDH_REPLY", 31) + }; + private static readonly Dictionary MessagesByName = CreateMessagesByNameMapping(); /// /// Defines the highest message number that is currently supported. @@ -27,52 +63,6 @@ internal sealed class SshMessageFactory /// internal const int TotalMessageCount = 32; - static SshMessageFactory() - { - AllMessages = new MessageMetadata[] - { - new MessageMetadata(0, "SSH_MSG_KEXINIT", 20), - new MessageMetadata(1, "SSH_MSG_NEWKEYS", 21), - new MessageMetadata(2, "SSH_MSG_REQUEST_FAILURE", 82), - new MessageMetadata(3, "SSH_MSG_CHANNEL_OPEN_FAILURE", 92), - new MessageMetadata(4, "SSH_MSG_CHANNEL_FAILURE", 100), - new MessageMetadata(5, "SSH_MSG_CHANNEL_EXTENDED_DATA", 95), - new MessageMetadata(6, "SSH_MSG_CHANNEL_DATA", 94), - new MessageMetadata(7, "SSH_MSG_CHANNEL_REQUEST", 98), - new MessageMetadata(8, "SSH_MSG_USERAUTH_BANNER", 53), - new MessageMetadata(9, "SSH_MSG_USERAUTH_INFO_RESPONSE", 61), - new MessageMetadata(10, "SSH_MSG_USERAUTH_FAILURE", 51), - new MessageMetadata(11, "SSH_MSG_DEBUG", 4), - new MessageMetadata(12, "SSH_MSG_GLOBAL_REQUEST", 80), - new MessageMetadata(13, "SSH_MSG_CHANNEL_OPEN", 90), - new MessageMetadata(14, "SSH_MSG_CHANNEL_OPEN_CONFIRMATION", 91), - new MessageMetadata(15, "SSH_MSG_USERAUTH_INFO_REQUEST", 60), - new MessageMetadata(16, "SSH_MSG_UNIMPLEMENTED", 3), - new MessageMetadata(17, "SSH_MSG_REQUEST_SUCCESS", 81), - new MessageMetadata(18, "SSH_MSG_CHANNEL_SUCCESS", 99), - new MessageMetadata(19, "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ", 60), - new MessageMetadata(20, "SSH_MSG_DISCONNECT", 1), - new MessageMetadata(21, "SSH_MSG_USERAUTH_SUCCESS", 52), - new MessageMetadata(22, "SSH_MSG_USERAUTH_PK_OK", 60), - new MessageMetadata(23, "SSH_MSG_IGNORE", 2), - new MessageMetadata(24, "SSH_MSG_CHANNEL_WINDOW_ADJUST", 93), - new MessageMetadata(25, "SSH_MSG_CHANNEL_EOF", 96), - new MessageMetadata(26, "SSH_MSG_CHANNEL_CLOSE", 97), - new MessageMetadata(27, "SSH_MSG_SERVICE_ACCEPT", 6), - new MessageMetadata(28, "SSH_MSG_KEX_DH_GEX_GROUP", 31), - new MessageMetadata(29, "SSH_MSG_KEXDH_REPLY", 31), - new MessageMetadata(30, "SSH_MSG_KEX_DH_GEX_REPLY", 33), - new MessageMetadata(31, "SSH_MSG_KEX_ECDH_REPLY", 31) - }; - - MessagesByName = new Dictionary(AllMessages.Length); - for (var i = 0; i < AllMessages.Length; i++) - { - var messageMetadata = AllMessages[i]; - MessagesByName.Add(messageMetadata.Name, messageMetadata); - } - } - /// /// Initializes a new instance of the class. /// @@ -169,7 +159,7 @@ public void EnableAndActivateMessage(string messageName) throw new ArgumentNullException(nameof(messageName)); } - lock (this) + lock (_lock) { if (!MessagesByName.TryGetValue(messageName, out var messageMetadata)) { @@ -196,7 +186,7 @@ public void DisableAndDeactivateMessage(string messageName) throw new ArgumentNullException(nameof(messageName)); } - lock (this) + lock (_lock) { if (!MessagesByName.TryGetValue(messageName, out var messageMetadata)) { @@ -216,6 +206,19 @@ public void DisableAndDeactivateMessage(string messageName) } } + private static Dictionary CreateMessagesByNameMapping() + { + var messagesByName = new Dictionary(AllMessages.Length); + + for (var i = 0; i < AllMessages.Length; i++) + { + var messageMetadata = AllMessages[i]; + messagesByName.Add(messageMetadata.Name, messageMetadata); + } + + return messagesByName; + } + private static SshException CreateMessageTypeNotSupportedException(byte messageNumber) { throw new SshException(string.Format(CultureInfo.InvariantCulture, "Message type {0} is not supported.", messageNumber)); @@ -229,11 +232,13 @@ private static SshException CreateMessageNotSupportedException(string messageNam private static SshException CreateMessageTypeAlreadyEnabledForOtherMessageException(byte messageNumber, string messageName, string currentEnabledForMessageName) { throw new SshException(string.Format(CultureInfo.InvariantCulture, - "Cannot enable message '{0}'. Message type {1} is already enabled for '{2}'.", - messageName, messageNumber, currentEnabledForMessageName)); + "Cannot enable message '{0}'. Message type {1} is already enabled for '{2}'.", + messageName, + messageNumber, + currentEnabledForMessageName)); } - internal abstract class MessageMetadata + private abstract class MessageMetadata { protected MessageMetadata(byte id, string name, byte number) { @@ -242,16 +247,16 @@ protected MessageMetadata(byte id, string name, byte number) Number = number; } - public readonly byte Id; + public byte Id { get; } - public readonly string Name; + public string Name { get; } - public readonly byte Number; + public byte Number { get; } public abstract Message Create(); } - internal sealed class MessageMetadata : MessageMetadata + private sealed class MessageMetadata : MessageMetadata where T : Message, new() { public MessageMetadata(byte id, string name, byte number) diff --git a/src/Renci.SshNet/SubsystemSession.cs b/src/Renci.SshNet/SubsystemSession.cs index ab6182bba..70385d903 100644 --- a/src/Renci.SshNet/SubsystemSession.cs +++ b/src/Renci.SshNet/SubsystemSession.cs @@ -307,12 +307,12 @@ public bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout) /// Blocks the current thread until the specified gets signaled, using a /// 32-bit signed integer to specify the time interval in milliseconds. /// - /// The first handle to wait for. - /// The second handle to wait for. + /// The first handle to wait for. + /// The second handle to wait for. /// To number of milliseconds to wait for a to get signaled, or -1 to wait indefinitely. /// - /// 0 if received a signal within the specified timeout, and 1 - /// if received a signal within the specified timeout. + /// 0 if received a signal within the specified timeout, and 1 + /// if received a signal within the specified timeout. /// /// The connection was closed by the server. /// The channel was closed. @@ -324,19 +324,19 @@ public bool WaitOne(WaitHandle waitHandle, int millisecondsTimeout) /// or session event. /// /// - /// When both and are signaled during the call, + /// When both and are signaled during the call, /// then 0 is returned. /// /// - public int WaitAny(WaitHandle waitHandle1, WaitHandle waitHandle2, int millisecondsTimeout) + public int WaitAny(WaitHandle waitHandleA, WaitHandle waitHandleB, int millisecondsTimeout) { var waitHandles = new[] { _errorOccuredWaitHandle, _sessionDisconnectedWaitHandle, _channelClosedWaitHandle, - waitHandle1, - waitHandle2 + waitHandleA, + waitHandleB }; var result = WaitHandle.WaitAny(waitHandles, millisecondsTimeout); @@ -547,10 +547,14 @@ protected virtual void Dispose(bool disposing) private void EnsureNotDisposed() { +#if NET7_0_OR_GREATER + ObjectDisposedException.ThrowIf(_isDisposed, this); +#else if (_isDisposed) { throw new ObjectDisposedException(GetType().FullName); } +#endif // NET7_0_OR_GREATER } } } diff --git a/test/.editorconfig b/test/.editorconfig index ff0eebcf3..60515fd14 100644 --- a/test/.editorconfig +++ b/test/.editorconfig @@ -1,6 +1,10 @@ 锘縖*.cs] -# Sonar rules +#### Sonar rules #### + +# S1215: ""GC.Collect" should not be called +# https://rules.sonarsource.com/csharp/RSPEC-1215 +dotnet_diagnostic.S1215.severity = none # S1854: Unused assignments should be removed # https://rules.sonarsource.com/csharp/RSPEC-1854 @@ -18,6 +22,12 @@ # For unit tests, we do not care about this diagnostic. dotnet_diagnostic.S1854.severity = none +#### Meziantou.Analyzer rules #### + +# MA0089: Optimize string method usage +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0089.md +dotnet_diagnostic.MA0089.severity = suggestion + #### StyleCop rules #### # SA1202: Elements must be ordered by access @@ -95,6 +105,18 @@ dotnet_diagnostic.CA1001.severity = none # We frequently use underscores in test classes and test methods. dotnet_diagnostic.CA1707.severity = none +# CA1824: Mark assemblies with NeutralResourcesLanguageAttribute +# https://learn.microsoft.com/en-US/dotnet/fundamentals/code-analysis/quality-rules/ca1824 +# +# We do not care (much) about performance for tests. +dotnet_diagnostic.CA1824.severity = none + +# CA1835: Prefer the memory-based overloads of ReadAsync/WriteAsync methods in stream-based classes +# https://learn.microsoft.com/en-US/dotnet/fundamentals/code-analysis/quality-rules/ca1835 +# +# We do not care about this for unit tests. +dotnet_diagnostic.CA1835.severity = none + # CA1711: Identifiers should not have incorrect suffix # # We frequently define test classes and test method with a suffix that refers to a type. @@ -105,6 +127,11 @@ dotnet_diagnostic.CA1711.severity = none # We do not care about this for unit tests. dotnet_diagnostic.CA1720.severity = none +# CA5351: Do not use broken cryptographic algorithms +# +# We do not care about this for unit tests. +dotnet_diagnostic.CA5351.severity = none + # CA5394: Do not use insecure randomness # # We do not care about this for unit tests. diff --git a/test/Renci.SshNet.Benchmarks/.editorconfig b/test/Renci.SshNet.Benchmarks/.editorconfig new file mode 100644 index 000000000..e903a76d8 --- /dev/null +++ b/test/Renci.SshNet.Benchmarks/.editorconfig @@ -0,0 +1,72 @@ +锘縖*.cs] + +#### Sonar rules #### + +# S125: Sections of code should not be commented out +https://rules.sonarsource.com/csharp/RSPEC-125/ +dotnet_diagnostic.S125.severity = suggestion + +# S1118: Utility classes should not have public constructors +# https://rules.sonarsource.com/csharp/RSPEC-1118/ +dotnet_diagnostic.S1118.severity = suggestion + +# S1450: Private fields only used as local variables in methods should become local variables +# https://rules.sonarsource.com/csharp/RSPEC-1450/ +dotnet_diagnostic.S1450.severity = suggestion + +# S4144: Methods should not have identical implementations +# https://rules.sonarsource.com/csharp/RSPEC-4144/ +dotnet_diagnostic.S4144.severity = suggestion + +#### SYSLIB diagnostics #### + + +#### StyleCop Analyzers rules #### + +# SA1028: Code must not contain trailing whitespace +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1028.md +dotnet_diagnostic.SA1028.severity = suggestion + +# SA1414: Tuple types in signatures should have element names +https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1414.md +dotnet_diagnostic.SA1414.severity = suggestion + +# SA1400: Access modifier must be declared +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1400.md +dotnet_diagnostic.SA1400.severity = suggestion + +# SA1401: Fields must be private +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md +dotnet_diagnostic.SA1401.severity = suggestion + +# SA1411: Attribute constructor must not use unnecessary parenthesis +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1411.md +dotnet_diagnostic.SA1411.severity = suggestion + +# SA1505: Opening braces must not be followed by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1505.md +dotnet_diagnostic.SA1505.severity = suggestion + +# SA1512: Single line comments must not be followed by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1512.md +dotnet_diagnostic.SA1512.severity = suggestion + +# SA1513: Closing brace must be followed by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1513.md +dotnet_diagnostic.SA1513.severity = suggestion + +#### Meziantou.Analyzer rules #### + +# MA0003: Add parameter name to improve readability +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0003.md +dotnet_diagnostic.MA0003.severity = suggestion + +# MA0053: Make class sealed +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0053.md +dotnet_diagnostic.MA0053.severity = suggestion + +#### .NET Compiler Platform analysers rules #### + +# CA2000: Dispose objects before losing scope +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2000 +dotnet_diagnostic.CA2000.severity = suggestion diff --git a/test/Renci.SshNet.IntegrationTests/.editorconfig b/test/Renci.SshNet.IntegrationTests/.editorconfig index b94e29112..dfeca510a 100644 --- a/test/Renci.SshNet.IntegrationTests/.editorconfig +++ b/test/Renci.SshNet.IntegrationTests/.editorconfig @@ -1,5 +1,59 @@ 锘縖*.cs] +#### Sonar rules #### + +# S108: Nested blocks of code should not be left empty +# https://rules.sonarsource.com/csharp/RSPEC-108/ +dotnet_diagnostic.S108.severity = none + +# S125: Sections of code should not be commented out +# https://rules.sonarsource.com/csharp/RSPEC-125/ +dotnet_diagnostic.S125.severity = none + +# S1118: Utility classes should not have public constructors +# https://rules.sonarsource.com/csharp/RSPEC-1118/ +dotnet_diagnostic.S1118.severity = none + +# S1155: "Any()" should be used to test for emptiness +# https://rules.sonarsource.com/csharp/RSPEC-1155/ +dotnet_diagnostic.S1155.severity = none + +# S1607: Tests should not be ignored +# https://rules.sonarsource.com/csharp/RSPEC-1607/ +dotnet_diagnostic.S1607.severity = none + +# S2925: "Thread.Sleep" should not be used in tests +# https://rules.sonarsource.com/csharp/RSPEC-2925/ +dotnet_diagnostic.S2925.severity = none + +# 53241: Methods should not return values that are never used +# https://rules.sonarsource.com/csharp/RSPEC-3241/ +dotnet_diagnostic.S3241.severity = none + +# S3415: Assertion arguments should be passed in the correct order +# https://rules.sonarsource.com/csharp/RSPEC-3415/ +dotnet_diagnostic.S3415.severity = none + +# S3881: "IDisposable" should be implemented correctly +# https://rules.sonarsource.com/csharp/RSPEC-3881/ +dotnet_diagnostic.S3881.severity = none + +# S3966: Objects should not be disposed more than once +# https://rules.sonarsource.com/csharp/RSPEC-3966/ +dotnet_diagnostic.S3966.severity = none + +# S4144: Methods should not have identical implementations +# https://rules.sonarsource.com/csharp/RSPEC-4144/ +dotnet_diagnostic.S4144.severity = none + +# S6602: "Find" method should be used instead of the "FirstOrDefault" extension +# https://rules.sonarsource.com/csharp/RSPEC-6602/ +dotnet_diagnostic.S6602.severity = none + +# S6610: "StartsWith" and "EndsWith" overloads that take a "char" should be used instead of the ones that take a "string" +# https://rules.sonarsource.com/csharp/RSPEC-6610/ +dotnet_diagnostic.S6610.severity = none + #### SYSLIB diagnostics #### # SYSLIB1045: Use 'GeneratedRegexAttribute' to generate the regular expression implementation at compile-time @@ -9,8 +63,266 @@ dotnet_diagnostic.SYSLIB1045.severity = none ### StyleCop Analyzers rules ### +# SA1000: Keywords must be spaced correctly +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1000.md +dotnet_diagnostic.SA1000.severity = suggestion + +# SA1004: Documentation lines must begin with single space +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1004.md +dotnet_diagnostic.SA1004.severity = suggestion + +# SA1005: Single line comments must begin with single space +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1005.md +dotnet_diagnostic.SA1005.severity = suggestion + +# SA1012: Opening braces must be spaced correctly +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1012.md +dotnet_diagnostic.SA1012.severity = suggestion + +# SA1025: Code must not contain multiple whitespace in a row +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1025.md +dotnet_diagnostic.SA1025.severity = suggestion + +# SA1028: Code must not contain trailing whitespace +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1028.md +dotnet_diagnostic.SA1028.severity = suggestion + +# SA1111: Closing parenthesis must be on line of last parameter +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1111.md +dotnet_diagnostic.SA1111.severity = suggestion + +# SA1117: Parameters must be on same line or separate lines +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1117.md +dotnet_diagnostic.SA1117.severity = suggestion + +# SA1119: Statement must not use unnecessary parenthesis +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1119.md +dotnet_diagnostic.SA1119.severity = suggestion + +# SA1122: Use String.Empty for empty strings +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1122.md +dotnet_diagnostic.SA1122.severity = suggestion + +# SA1123:Do not place regions within elements +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1123.md +dotnet_diagnostic.SA1123.severity = suggestion + +# SA1130: Use lambda syntax +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1130.md +dotnet_diagnostic.SA1130.severity = suggestion + +# SA1133: Do not combine attributes +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1133.md +dotnet_diagnostic.SA1133.severity = suggestion + +# SA1203: Constants must appear before fields +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1203.md +dotnet_diagnostic.SA1203.severity = suggestion + +# SA1204: Static elements must appear before instance elements +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1204.md +dotnet_diagnostic.SA1204.severity = suggestion + +# SA1400: Access modifier must be declared +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1400.md +dotnet_diagnostic.SA1400.severity = suggestion + +# SA1401: Fields must be private +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md +dotnet_diagnostic.SA1401.severity = suggestion + +# SA1411: Attribute constructor must not use unnecessary parenthesis +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1411.md +dotnet_diagnostic.SA1411.severity = suggestion + +# SA1505: Opening braces must not be followed by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1505.md +dotnet_diagnostic.SA1505.severity = suggestion + +# SA1507: Code must not contain multiple blank lines in a row +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1507.md +dotnet_diagnostic.SA1507.severity = suggestion + +# SA1508: Closing braces must not be preceded by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1508.md +dotnet_diagnostic.SA1508.severity = suggestion + +# SA1510: Chained statement blocks must not be preceded by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1510.md +dotnet_diagnostic.SA1510.severity = suggestion + +# SA1512: Single line comments must not be followed by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1512.md +dotnet_diagnostic.SA1512.severity = suggestion + +# SA1513: Closing brace must be followed by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1513.md +dotnet_diagnostic.SA1513.severity = suggestion + +# SA1514: Element documentation header must be preceded by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1514.md +dotnet_diagnostic.SA1514.severity = suggestion + +# SA1515: Single line comment must be preceded by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1515.md +dotnet_diagnostic.SA1515.severity = suggestion + +# SA1517: Code must not contain blank lines at start of file +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1517.md +dotnet_diagnostic.SA1517.severity = suggestion + +# SA1518: Use line endings correctly at end of file +https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1518.md +dotnet_diagnostic.SA1518.severity = suggestion + +# SA1626: Single line comments must not use documentation style slashes +https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1626.md +dotnet_diagnostic.SA1626.severity = suggestion + +#### Meziantou.Analyzer rules #### + +# MA0001: StringComparison is missing +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0001.md +dotnet_diagnostic.MA0001.severity = suggestion + +# MA0003: Add parameter name to improve readability +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0003.md +dotnet_diagnostic.MA0003.severity = suggestion + +# MA0004: Use Task.ConfigureAwait(false) +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0004.md +dotnet_diagnostic.MA0004.severity = suggestion + +# MA0011: IFormatProvider is missing +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0011.md +dotnet_diagnostic.MA0011.severity = suggestion + +# MA0042: Do not use blocking calls in an async method +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0042.md +dotnet_diagnostic.MA0042.severity = suggestion + +# MA0043: Use nameof operator in ArgumentException +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0043.md +dotnet_diagnostic.MA0043.severity = suggestion + +# MA0046: Use EventHandler to declare events +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0046.md +dotnet_diagnostic.MA0046.severity = suggestion + +# MA0053: Make class sealed +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0053.md +dotnet_diagnostic.MA0053.severity = suggestion + +# MA0060: The value returned by Stream.Read/Stream.ReadAsync is not used +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0060.md +dotnet_diagnostic.MA0060.severity = suggestion + +# MA0074: Avoid implicit culture-sensitive methods +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0074.md +dotnet_diagnostic.MA0074.severity = suggestion + +# MA0075: Do not use implicit culture-sensitive ToString +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0075.md +dotnet_diagnostic.MA0075.severity = suggestion + +# MA0076: Do not use implicit culture-sensitive ToString in interpolated strings +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0076.md +dotnet_diagnostic.MA0076.severity = suggestion + +# MA0099 - Use Explicit enum value instead of 0 +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0099.md +dotnet_diagnostic.MA0099.severity = suggestion + +# MA0101: String contains an implicit end of line character +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0101.md +dotnet_diagnostic.MA0101.severity = suggestion + +# MA0110: Use the Regex source generator +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0110.md +dotnet_diagnostic.MA0110.severity = suggestion + #### .NET Compiler Platform analysers rules #### +# CA1031: Do not catch general exception types +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1031 +dotnet_diagnostic.CA1031.severity = suggestion + +# CA1052: Static holder types should be Static or NotInheritable +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1052 +dotnet_diagnostic.CA1052.severity = suggestion + +# CA1062: Validate arguments of public methods +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1062 +dotnet_diagnostic.CA1062.severity = suggestion + +# CA1063: Implement IDisposable correctly +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1063 +dotnet_diagnostic.CA1063.severity = suggestion + +# CA1307: Specify StringComparison for clarity +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1307 +dotnet_diagnostic.CA1307.severity = suggestion + +# CA1310: Specify StringComparison for correctness +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1310 +dotnet_diagnostic.CA1310.severity = suggestion + +# CA1507: Use nameof in place of string +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1507 +dotnet_diagnostic.CA1507.severity = suggestion + +# CA1827: Do not use Count()/LongCount() when Any() can be used +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1827 +dotnet_diagnostic.CA1827.severity = suggestion + +# CA1812: Avoid uninstantiated internal classes +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1812 +dotnet_diagnostic.CA1812.severity = suggestion + +# CA1816: Call GC.SuppressFinalize correctly +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1816 +dotnet_diagnostic.CA1816.severity = suggestion + +# CA1822: Mark members as static +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1822 +dotnet_diagnostic.CA1822.severity = suggestion + +# CA1840: Use Environment.CurrentManagedThreadId instead of Thread.CurrentThread.ManagedThreadId +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1840 +dotnet_diagnostic.CA1840.severity = suggestion + +# CA1851: Possible multiple enumerations of IEnumerable collection +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1851 +dotnet_diagnostic.CA1851.severity = suggestion + +# CA1859: Use concrete types when possible for improved performance +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1859 +dotnet_diagnostic.CA1859.severity = suggestion + +# CA2000: Dispose objects before losing scope +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2000 +dotnet_diagnostic.CA2000.severity = suggestion + +# CA2007: Do not directly await a Task +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2007 +dotnet_diagnostic.CA2007.severity = suggestion + +# CA2008: Do not create tasks without passing a TaskScheduler +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2008 +dotnet_diagnostic.CA2008.severity = suggestion + +# CA2201: Do not raise reserved exception types +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2201 +dotnet_diagnostic.CA2201.severity = suggestion + +# CA2213: Disposable fields should be disposed +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2213 +dotnet_diagnostic.CA2213.severity = suggestion + +# CA2234: Pass System.Uri objects instead of strings +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2234 +dotnet_diagnostic.CA2234.severity = suggestion + # IDE0007: Use var instead of explicit type # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0007 dotnet_diagnostic.IDE0007.severity = suggestion diff --git a/test/Renci.SshNet.IntegrationTests/HostConfig.cs b/test/Renci.SshNet.IntegrationTests/HostConfig.cs index 817bd7026..d501dd384 100644 --- a/test/Renci.SshNet.IntegrationTests/HostConfig.cs +++ b/test/Renci.SshNet.IntegrationTests/HostConfig.cs @@ -98,18 +98,4 @@ public void Write(ScpClient scpClient, string path) } } } - - public class HostEntry - { - public HostEntry(IPAddress ipAddress, string hostName) - { - IPAddress = ipAddress; - HostName = hostName; - Aliases = new List(); - } - - public IPAddress IPAddress { get; private set; } - public string HostName { get; set; } - public List Aliases { get; } - } } diff --git a/test/Renci.SshNet.IntegrationTests/HostEntry.cs b/test/Renci.SshNet.IntegrationTests/HostEntry.cs new file mode 100644 index 000000000..9127e820a --- /dev/null +++ b/test/Renci.SshNet.IntegrationTests/HostEntry.cs @@ -0,0 +1,18 @@ +锘縰sing System.Net; + +namespace Renci.SshNet.IntegrationTests +{ + public sealed class HostEntry + { + public HostEntry(IPAddress ipAddress, string hostName) + { + IPAddress = ipAddress; + HostName = hostName; + Aliases = new List(); + } + + public IPAddress IPAddress { get; private set; } + public string HostName { get; set; } + public List Aliases { get; } + } +} diff --git a/test/Renci.SshNet.IntegrationTests/RemoteSshd.cs b/test/Renci.SshNet.IntegrationTests/RemoteSshd.cs index b9a32e67a..14614b406 100644 --- a/test/Renci.SshNet.IntegrationTests/RemoteSshd.cs +++ b/test/Renci.SshNet.IntegrationTests/RemoteSshd.cs @@ -1,6 +1,4 @@ -锘縰sing Renci.SshNet.TestTools.OpenSSH; - -namespace Renci.SshNet.IntegrationTests +锘縩amespace Renci.SshNet.IntegrationTests { internal class RemoteSshd { @@ -42,217 +40,4 @@ public RemoteSshd Restart() return this; } } - - internal class RemoteSshdConfig - { - private const string SshdConfigFilePath = "/etc/ssh/sshd_config"; - private static readonly Encoding Utf8NoBom = new UTF8Encoding(false, true); - - private readonly RemoteSshd _remoteSshd; - private readonly IConnectionInfoFactory _connectionInfoFactory; - private readonly SshdConfig _config; - - public RemoteSshdConfig(RemoteSshd remoteSshd, IConnectionInfoFactory connectionInfoFactory) - { - _remoteSshd = remoteSshd; - _connectionInfoFactory = connectionInfoFactory; - - using (var client = new ScpClient(_connectionInfoFactory.Create())) - { - client.Connect(); - - using (var memoryStream = new MemoryStream()) - { - client.Download(SshdConfigFilePath, memoryStream); - - memoryStream.Position = 0; - _config = SshdConfig.LoadFrom(memoryStream, Encoding.UTF8); - } - } - } - - /// - /// Specifies whether challenge-response authentication is allowed. - /// - /// to allow challenge-response authentication. - /// - /// The current instance. - /// - public RemoteSshdConfig WithChallengeResponseAuthentication(bool? value) - { - _config.ChallengeResponseAuthentication = value; - return this; - } - - /// - /// Specifies whether to allow keyboard-interactive authentication. - /// - /// to allow keyboard-interactive authentication. - /// - /// The current instance. - /// - public RemoteSshdConfig WithKeyboardInteractiveAuthentication(bool value) - { - _config.KeyboardInteractiveAuthentication = value; - return this; - } - - /// - /// Specifies whether sshd should print /etc/motd when a user logs in interactively. - /// - /// if sshd should print /etc/motd when a user logs in interactively. - /// - /// The current instance. - /// - public RemoteSshdConfig PrintMotd(bool? value = true) - { - _config.PrintMotd = value; - return this; - } - - /// - /// Specifies whether TCP forwarding is permitted. - /// - /// to allow TCP forwarding. - /// - /// The current instance. - /// - public RemoteSshdConfig AllowTcpForwarding(bool? value = true) - { - _config.AllowTcpForwarding = value; - return this; - } - - public RemoteSshdConfig WithAuthenticationMethods(string user, string authenticationMethods) - { - var sshNetMatch = _config.Matches.FirstOrDefault(m => m.Users.Contains(user)); - if (sshNetMatch == null) - { - sshNetMatch = new Match(new[] { user }, new string[0]); - _config.Matches.Add(sshNetMatch); - } - - sshNetMatch.AuthenticationMethods = authenticationMethods; - - return this; - } - - public RemoteSshdConfig ClearCiphers() - { - _config.Ciphers.Clear(); - return this; - } - - public RemoteSshdConfig AddCipher(Cipher cipher) - { - _config.Ciphers.Add(cipher); - return this; - } - - public RemoteSshdConfig ClearKeyExchangeAlgorithms() - { - _config.KeyExchangeAlgorithms.Clear(); - return this; - } - - public RemoteSshdConfig AddKeyExchangeAlgorithm(KeyExchangeAlgorithm keyExchangeAlgorithm) - { - _config.KeyExchangeAlgorithms.Add(keyExchangeAlgorithm); - return this; - } - - public RemoteSshdConfig ClearPublicKeyAcceptedAlgorithms() - { - _config.PublicKeyAcceptedAlgorithms.Clear(); - return this; - } - - public RemoteSshdConfig AddPublicKeyAcceptedAlgorithm(PublicKeyAlgorithm publicKeyAlgorithm) - { - _config.PublicKeyAcceptedAlgorithms.Add(publicKeyAlgorithm); - return this; - } - - public RemoteSshdConfig ClearMessageAuthenticationCodeAlgorithms() - { - _config.MessageAuthenticationCodeAlgorithms.Clear(); - return this; - } - - public RemoteSshdConfig AddMessageAuthenticationCodeAlgorithm(MessageAuthenticationCodeAlgorithm messageAuthenticationCodeAlgorithm) - { - _config.MessageAuthenticationCodeAlgorithms.Add(messageAuthenticationCodeAlgorithm); - return this; - } - - public RemoteSshdConfig ClearHostKeyAlgorithms() - { - _config.HostKeyAlgorithms.Clear(); - return this; - } - - public RemoteSshdConfig AddHostKeyAlgorithm(HostKeyAlgorithm hostKeyAlgorithm) - { - _config.HostKeyAlgorithms.Add(hostKeyAlgorithm); - return this; - } - - public RemoteSshdConfig ClearSubsystems() - { - _config.Subsystems.Clear(); - return this; - } - - public RemoteSshdConfig AddSubsystem(Subsystem subsystem) - { - _config.Subsystems.Add(subsystem); - return this; - } - - public RemoteSshdConfig WithLogLevel(LogLevel logLevel) - { - _config.LogLevel = logLevel; - return this; - } - - public RemoteSshdConfig WithUsePAM(bool usePAM) - { - _config.UsePAM = usePAM; - return this; - } - - public RemoteSshdConfig ClearHostKeyFiles() - { - _config.HostKeyFiles.Clear(); - return this; - } - - public RemoteSshdConfig AddHostKeyFile(string hostKeyFile) - { - _config.HostKeyFiles.Add(hostKeyFile); - return this; - } - - public RemoteSshd Update() - { - using (var client = new ScpClient(_connectionInfoFactory.Create())) - { - client.Connect(); - - using (var memoryStream = new MemoryStream()) - using (var sw = new StreamWriter(memoryStream, Utf8NoBom)) - { - sw.NewLine = "\n"; - _config.SaveTo(sw); - sw.Flush(); - - memoryStream.Position = 0; - - client.Upload(memoryStream, SshdConfigFilePath); - } - } - - return _remoteSshd; - } - } } diff --git a/test/Renci.SshNet.IntegrationTests/RemoteSshdConfig.cs b/test/Renci.SshNet.IntegrationTests/RemoteSshdConfig.cs new file mode 100644 index 000000000..391449973 --- /dev/null +++ b/test/Renci.SshNet.IntegrationTests/RemoteSshdConfig.cs @@ -0,0 +1,217 @@ +锘縰sing Renci.SshNet.TestTools.OpenSSH; + +namespace Renci.SshNet.IntegrationTests +{ + internal sealed class RemoteSshdConfig + { + private const string SshdConfigFilePath = "/etc/ssh/sshd_config"; + private static readonly Encoding Utf8NoBom = new UTF8Encoding(false, true); + + private readonly RemoteSshd _remoteSshd; + private readonly IConnectionInfoFactory _connectionInfoFactory; + private readonly SshdConfig _config; + + public RemoteSshdConfig(RemoteSshd remoteSshd, IConnectionInfoFactory connectionInfoFactory) + { + _remoteSshd = remoteSshd; + _connectionInfoFactory = connectionInfoFactory; + + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var memoryStream = new MemoryStream()) + { + client.Download(SshdConfigFilePath, memoryStream); + + memoryStream.Position = 0; + _config = SshdConfig.LoadFrom(memoryStream, Encoding.UTF8); + } + } + } + + /// + /// Specifies whether challenge-response authentication is allowed. + /// + /// to allow challenge-response authentication. + /// + /// The current instance. + /// + public RemoteSshdConfig WithChallengeResponseAuthentication(bool? value) + { + _config.ChallengeResponseAuthentication = value; + return this; + } + + /// + /// Specifies whether to allow keyboard-interactive authentication. + /// + /// to allow keyboard-interactive authentication. + /// + /// The current instance. + /// + public RemoteSshdConfig WithKeyboardInteractiveAuthentication(bool value) + { + _config.KeyboardInteractiveAuthentication = value; + return this; + } + + /// + /// Specifies whether sshd should print /etc/motd when a user logs in interactively. + /// + /// if sshd should print /etc/motd when a user logs in interactively. + /// + /// The current instance. + /// + public RemoteSshdConfig PrintMotd(bool? value = true) + { + _config.PrintMotd = value; + return this; + } + + /// + /// Specifies whether TCP forwarding is permitted. + /// + /// to allow TCP forwarding. + /// + /// The current instance. + /// + public RemoteSshdConfig AllowTcpForwarding(bool? value = true) + { + _config.AllowTcpForwarding = value; + return this; + } + + public RemoteSshdConfig WithAuthenticationMethods(string user, string authenticationMethods) + { + var sshNetMatch = _config.Matches.Find(m => m.Users.Contains(user)); + if (sshNetMatch is null) + { + sshNetMatch = new Match(new[] { user }, Array.Empty()); + _config.Matches.Add(sshNetMatch); + } + + sshNetMatch.AuthenticationMethods = authenticationMethods; + + return this; + } + + public RemoteSshdConfig ClearCiphers() + { + _config.Ciphers.Clear(); + return this; + } + + public RemoteSshdConfig AddCipher(Cipher cipher) + { + _config.Ciphers.Add(cipher); + return this; + } + + public RemoteSshdConfig ClearKeyExchangeAlgorithms() + { + _config.KeyExchangeAlgorithms.Clear(); + return this; + } + + public RemoteSshdConfig AddKeyExchangeAlgorithm(KeyExchangeAlgorithm keyExchangeAlgorithm) + { + _config.KeyExchangeAlgorithms.Add(keyExchangeAlgorithm); + return this; + } + + public RemoteSshdConfig ClearPublicKeyAcceptedAlgorithms() + { + _config.PublicKeyAcceptedAlgorithms.Clear(); + return this; + } + + public RemoteSshdConfig AddPublicKeyAcceptedAlgorithm(PublicKeyAlgorithm publicKeyAlgorithm) + { + _config.PublicKeyAcceptedAlgorithms.Add(publicKeyAlgorithm); + return this; + } + + public RemoteSshdConfig ClearMessageAuthenticationCodeAlgorithms() + { + _config.MessageAuthenticationCodeAlgorithms.Clear(); + return this; + } + + public RemoteSshdConfig AddMessageAuthenticationCodeAlgorithm(MessageAuthenticationCodeAlgorithm messageAuthenticationCodeAlgorithm) + { + _config.MessageAuthenticationCodeAlgorithms.Add(messageAuthenticationCodeAlgorithm); + return this; + } + + public RemoteSshdConfig ClearHostKeyAlgorithms() + { + _config.HostKeyAlgorithms.Clear(); + return this; + } + + public RemoteSshdConfig AddHostKeyAlgorithm(HostKeyAlgorithm hostKeyAlgorithm) + { + _config.HostKeyAlgorithms.Add(hostKeyAlgorithm); + return this; + } + + public RemoteSshdConfig ClearSubsystems() + { + _config.Subsystems.Clear(); + return this; + } + + public RemoteSshdConfig AddSubsystem(Subsystem subsystem) + { + _config.Subsystems.Add(subsystem); + return this; + } + + public RemoteSshdConfig WithLogLevel(LogLevel logLevel) + { + _config.LogLevel = logLevel; + return this; + } + + public RemoteSshdConfig WithUsePAM(bool usePAM) + { + _config.UsePAM = usePAM; + return this; + } + + public RemoteSshdConfig ClearHostKeyFiles() + { + _config.HostKeyFiles.Clear(); + return this; + } + + public RemoteSshdConfig AddHostKeyFile(string hostKeyFile) + { + _config.HostKeyFiles.Add(hostKeyFile); + return this; + } + + public RemoteSshd Update() + { + using (var client = new ScpClient(_connectionInfoFactory.Create())) + { + client.Connect(); + + using (var memoryStream = new MemoryStream()) + using (var sw = new StreamWriter(memoryStream, Utf8NoBom)) + { + sw.NewLine = "\n"; + _config.SaveTo(sw); + sw.Flush(); + + memoryStream.Position = 0; + + client.Upload(memoryStream, SshdConfigFilePath); + } + } + + return _remoteSshd; + } + } +} diff --git a/test/Renci.SshNet.TestTools.OpenSSH/.editorconfig b/test/Renci.SshNet.TestTools.OpenSSH/.editorconfig new file mode 100644 index 000000000..15b989dbb --- /dev/null +++ b/test/Renci.SshNet.TestTools.OpenSSH/.editorconfig @@ -0,0 +1,23 @@ +锘縖*.cs] + +#### Meziantou.Analyzer rules #### + +# MA0001: StringComparison is missing +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0001.md +# +# TODO: Re-enable when issues are fixed +dotnet_diagnostic.MA0001.severity = suggestion + +# MA0110: Use the Regex source generator +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0110.md +dotnet_diagnostic.MA0110.severity = none + +#### .NET Compiler Platform analysers rules #### + +# CA1307: Specify StringComparison for clarity +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1307 +dotnet_diagnostic.CA1307.severity = none + +# CA1822: Mark members as static +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1822 +dotnet_code_quality.CA1822.api_surface = none diff --git a/test/Renci.SshNet.TestTools.OpenSSH/Cipher.cs b/test/Renci.SshNet.TestTools.OpenSSH/Cipher.cs index f7d8d8842..676504330 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/Cipher.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/Cipher.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.TestTools.OpenSSH { - public class Cipher + public sealed class Cipher { public static readonly Cipher TripledesCbc = new Cipher("3des-cbc"); public static readonly Cipher Aes128Cbc = new Cipher("aes128-cbc"); diff --git a/test/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs index 3eab2b199..e58867d79 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/BooleanFormatter.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.TestTools.OpenSSH.Formatters { - internal class BooleanFormatter + internal sealed class BooleanFormatter { public string Format(bool value) { diff --git a/test/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs index 2b8231111..dcddb8954 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/Int32Formatter.cs @@ -2,7 +2,7 @@ namespace Renci.SshNet.TestTools.OpenSSH.Formatters { - internal class Int32Formatter + internal sealed class Int32Formatter { public string Format(int value) { diff --git a/test/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs index f9f4bbf6f..9ab89c6a1 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/LogLevelFormatter.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.TestTools.OpenSSH.Formatters { - internal class LogLevelFormatter + internal sealed class LogLevelFormatter { public string Format(LogLevel logLevel) { diff --git a/test/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs index df2968be0..d8d7820ff 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/MatchFormatter.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.TestTools.OpenSSH.Formatters { - internal class MatchFormatter + internal sealed class MatchFormatter { public string Format(Match match) { diff --git a/test/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs index fcb74e266..91129aeb0 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/Formatters/SubsystemFormatter.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.TestTools.OpenSSH.Formatters { - internal class SubsystemFormatter + internal sealed class SubsystemFormatter { public string Format(Subsystem subsystem) { diff --git a/test/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs b/test/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs index 65807f462..23f41478b 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/HostKeyAlgorithm.cs @@ -1,29 +1,29 @@ 锘縩amespace Renci.SshNet.TestTools.OpenSSH { - public class HostKeyAlgorithm + public sealed class HostKeyAlgorithm { - public static readonly HostKeyAlgorithm EcdsaSha2Nistp256CertV01OpenSSH = new HostKeyAlgorithm("ecdsa-sha2-nistp256-cert-v01@openssh.com"); - public static readonly HostKeyAlgorithm EcdsaSha2Nistp384CertV01OpenSSH = new HostKeyAlgorithm("ecdsa-sha2-nistp384-cert-v01@openssh.com"); - public static readonly HostKeyAlgorithm EcdsaSha2Nistp521CertV01OpenSSH = new HostKeyAlgorithm("ecdsa-sha2-nistp521-cert-v01@openssh.com"); - public static readonly HostKeyAlgorithm SshEd25519CertV01OpenSSH = new HostKeyAlgorithm("ssh-ed25519-cert-v01@openssh.com"); - public static readonly HostKeyAlgorithm RsaSha2256CertV01OpenSSH = new HostKeyAlgorithm("rsa-sha2-256-cert-v01@openssh.com"); - public static readonly HostKeyAlgorithm RsaSha2512CertV01OpenSSH = new HostKeyAlgorithm("rsa-sha2-512-cert-v01@openssh.com"); - public static readonly HostKeyAlgorithm SshRsaCertV01OpenSSH = new HostKeyAlgorithm("ssh-rsa-cert-v01@openssh.com"); - public static readonly HostKeyAlgorithm EcdsaSha2Nistp256 = new HostKeyAlgorithm("ecdsa-sha2-nistp256"); - public static readonly HostKeyAlgorithm EcdsaSha2Nistp384 = new HostKeyAlgorithm("ecdsa-sha2-nistp384"); - public static readonly HostKeyAlgorithm EcdsaSha2Nistp521 = new HostKeyAlgorithm("ecdsa-sha2-nistp521"); - public static readonly HostKeyAlgorithm SshEd25519 = new HostKeyAlgorithm("ssh-ed25519"); - public static readonly HostKeyAlgorithm RsaSha2512 = new HostKeyAlgorithm("rsa-sha2-512"); - public static readonly HostKeyAlgorithm RsaSha2256 = new HostKeyAlgorithm("rsa-sha2-256"); - public static readonly HostKeyAlgorithm SshRsa = new HostKeyAlgorithm("ssh-rsa"); + public static readonly HostKeyAlgorithm EcdsaSha2Nistp256CertV01OpenSSH = new HostKeyAlgorithm("ecdsa-sha2-nistp256-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm EcdsaSha2Nistp384CertV01OpenSSH = new HostKeyAlgorithm("ecdsa-sha2-nistp384-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm EcdsaSha2Nistp521CertV01OpenSSH = new HostKeyAlgorithm("ecdsa-sha2-nistp521-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm SshEd25519CertV01OpenSSH = new HostKeyAlgorithm("ssh-ed25519-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm RsaSha2256CertV01OpenSSH = new HostKeyAlgorithm("rsa-sha2-256-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm RsaSha2512CertV01OpenSSH = new HostKeyAlgorithm("rsa-sha2-512-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm SshRsaCertV01OpenSSH = new HostKeyAlgorithm("ssh-rsa-cert-v01@openssh.com"); + public static readonly HostKeyAlgorithm EcdsaSha2Nistp256 = new HostKeyAlgorithm("ecdsa-sha2-nistp256"); + public static readonly HostKeyAlgorithm EcdsaSha2Nistp384 = new HostKeyAlgorithm("ecdsa-sha2-nistp384"); + public static readonly HostKeyAlgorithm EcdsaSha2Nistp521 = new HostKeyAlgorithm("ecdsa-sha2-nistp521"); + public static readonly HostKeyAlgorithm SshEd25519 = new HostKeyAlgorithm("ssh-ed25519"); + public static readonly HostKeyAlgorithm RsaSha2512 = new HostKeyAlgorithm("rsa-sha2-512"); + public static readonly HostKeyAlgorithm RsaSha2256 = new HostKeyAlgorithm("rsa-sha2-256"); + public static readonly HostKeyAlgorithm SshRsa = new HostKeyAlgorithm("ssh-rsa"); public static readonly HostKeyAlgorithm SshDss = new HostKeyAlgorithm("ssh-dss"); public HostKeyAlgorithm(string name) { - Name = name; - } + Name = name; + } - public string Name { get; } + public string Name { get; } public override bool Equals(object? obj) { diff --git a/test/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs b/test/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs index 4701103f0..e63d8ea17 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/KeyExchangeAlgorithm.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.TestTools.OpenSSH { - public class KeyExchangeAlgorithm + public sealed class KeyExchangeAlgorithm { public static readonly KeyExchangeAlgorithm DiffieHellmanGroup1Sha1 = new KeyExchangeAlgorithm("diffie-hellman-group1-sha1"); public static readonly KeyExchangeAlgorithm DiffieHellmanGroup14Sha1 = new KeyExchangeAlgorithm("diffie-hellman-group14-sha1"); @@ -16,7 +16,6 @@ public class KeyExchangeAlgorithm public static readonly KeyExchangeAlgorithm Curve25519Sha256Libssh = new KeyExchangeAlgorithm("curve25519-sha256@libssh.org"); public static readonly KeyExchangeAlgorithm Sntrup4591761x25519Sha512 = new KeyExchangeAlgorithm("sntrup4591761x25519-sha512@tinyssh.org"); - public KeyExchangeAlgorithm(string name) { Name = name; diff --git a/test/Renci.SshNet.TestTools.OpenSSH/Match.cs b/test/Renci.SshNet.TestTools.OpenSSH/Match.cs index 16cd5073d..d44dc04a3 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/Match.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/Match.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.TestTools.OpenSSH { - public class Match + public sealed class Match { public Match(string[] users, string[] addresses) { @@ -16,6 +16,11 @@ public Match(string[] users, string[] addresses) public void WriteTo(TextWriter writer) { + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + writer.Write("Match "); if (Users.Length > 0) diff --git a/test/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs b/test/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs index 17bf0cf91..edb2466e9 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/MessageAuthenticationCodeAlgorithm.cs @@ -1,7 +1,8 @@ 锘縩amespace Renci.SshNet.TestTools.OpenSSH { - public class MessageAuthenticationCodeAlgorithm + public sealed class MessageAuthenticationCodeAlgorithm { +#pragma warning disable SA1310 // Field names should not contain underscore public static readonly MessageAuthenticationCodeAlgorithm HmacMd5 = new MessageAuthenticationCodeAlgorithm("hmac-md5"); public static readonly MessageAuthenticationCodeAlgorithm HmacMd5_96 = new MessageAuthenticationCodeAlgorithm("hmac-md5-96"); public static readonly MessageAuthenticationCodeAlgorithm HmacRipemd160 = new MessageAuthenticationCodeAlgorithm("hmac-ripemd160"); @@ -20,6 +21,7 @@ public class MessageAuthenticationCodeAlgorithm public static readonly MessageAuthenticationCodeAlgorithm HmacSha2_512_Etm = new MessageAuthenticationCodeAlgorithm("hmac-sha2-512-etm@openssh.com"); public static readonly MessageAuthenticationCodeAlgorithm Umac64_Etm = new MessageAuthenticationCodeAlgorithm("umac-64-etm@openssh.com"); public static readonly MessageAuthenticationCodeAlgorithm Umac128_Etm = new MessageAuthenticationCodeAlgorithm("umac-128-etm@openssh.com"); +#pragma warning restore SA1310 // Field names should not contain underscore public MessageAuthenticationCodeAlgorithm(string name) { diff --git a/test/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs b/test/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs index 292ace7f9..24e577b79 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/PublicKeyAlgorithm.cs @@ -1,6 +1,6 @@ 锘縩amespace Renci.SshNet.TestTools.OpenSSH { - public class PublicKeyAlgorithm + public sealed class PublicKeyAlgorithm { public static readonly PublicKeyAlgorithm SshEd25519 = new PublicKeyAlgorithm("ssh-ed25519"); public static readonly PublicKeyAlgorithm SshEd25519CertV01OpenSSH = new PublicKeyAlgorithm("ssh-ed25519-cert-v01@openssh.com"); diff --git a/test/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs b/test/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs index 7dc9f309c..5e3025711 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/SshdConfig.cs @@ -6,9 +6,10 @@ namespace Renci.SshNet.TestTools.OpenSSH { - public class SshdConfig + public sealed class SshdConfig { - private static readonly Regex MatchRegex = new Regex($@"\s*Match\s+(User\s+(?[\S]+))?\s*(Address\s+(?[\S]+))?\s*", RegexOptions.Compiled); + private static readonly Regex MatchRegex = new Regex($@"\s*Match\s+(User\s+(?[\S]+))?\s*(Address\s+(?[\S]+))?\s*", + RegexOptions.Compiled | RegexOptions.ExplicitCapture); private readonly SubsystemFormatter _subsystemFormatter; private readonly Int32Formatter _int32Formatter; @@ -50,7 +51,7 @@ private SshdConfig() /// /// A list of private host key files used by sshd. /// - public List HostKeyFiles { get; set; } + public List HostKeyFiles { get; } /// /// Gets or sets a value specifying whether challenge-response authentication is allowed. @@ -143,8 +144,83 @@ private SshdConfig() /// public bool? AllowTcpForwarding { get; set; } + public static SshdConfig LoadFrom(Stream stream, Encoding encoding) + { + using (var sr = new StreamReader(stream, encoding)) + { + var sshdConfig = new SshdConfig(); + + Match? currentMatchConfiguration = null; + + string? line; + while ((line = sr.ReadLine()) != null) + { + // Skip empty lines + if (line.Length == 0) + { + continue; + } + + // Skip comments + if (line[0] == '#') + { + continue; + } + + var match = MatchRegex.Match(line); + if (match.Success) + { + var usersGroup = match.Groups["users"]; + var addressesGroup = match.Groups["addresses"]; + var users = usersGroup.Success ? usersGroup.Value.Split(',') : Array.Empty(); + var addresses = addressesGroup.Success ? addressesGroup.Value.Split(',') : Array.Empty(); + + currentMatchConfiguration = new Match(users, addresses); + sshdConfig.Matches.Add(currentMatchConfiguration); + continue; + } + + if (currentMatchConfiguration != null) + { + ProcessMatchOption(currentMatchConfiguration, line); + } + else + { + ProcessGlobalOption(sshdConfig, line); + } + } + + if (sshdConfig.Ciphers == null) + { + // Obtain supported ciphers using ssh -Q cipher + } + + if (sshdConfig.KeyExchangeAlgorithms == null) + { + // Obtain supports key exchange algorithms using ssh -Q kex + } + + if (sshdConfig.HostKeyAlgorithms == null) + { + // Obtain supports host key algorithms using ssh -Q key + } + + if (sshdConfig.MessageAuthenticationCodeAlgorithms == null) + { + // Obtain supported MACs using ssh -Q mac + } + + return sshdConfig; + } + } + public void SaveTo(TextWriter writer) { + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + writer.WriteLine("Protocol " + Protocol); writer.WriteLine("Port " + _int32Formatter.Format(Port)); if (HostKeyFiles.Count > 0) @@ -215,84 +291,13 @@ public void SaveTo(TextWriter writer) { writer.WriteLine("PubkeyAcceptedAlgorithms " + string.Join(",", PublicKeyAcceptedAlgorithms.Select(c => c.Name).ToArray())); } - + foreach (var match in Matches) { _matchFormatter.Format(match, writer); } } - public static SshdConfig LoadFrom(Stream stream, Encoding encoding) - { - using (var sr = new StreamReader(stream, encoding)) - { - var sshdConfig = new SshdConfig(); - - Match? currentMatchConfiguration = null; - - string? line; - while ((line = sr.ReadLine()) != null) - { - // Skip empty lines - if (line.Length == 0) - { - continue; - } - - // Skip comments - if (line[0] == '#') - { - continue; - } - - var match = MatchRegex.Match(line); - if (match.Success) - { - var usersGroup = match.Groups["users"]; - var addressesGroup = match.Groups["addresses"]; - var users = usersGroup.Success ? usersGroup.Value.Split(',') : Array.Empty(); - var addresses = addressesGroup.Success ? addressesGroup.Value.Split(',') : Array.Empty(); - - currentMatchConfiguration = new Match(users, addresses); - sshdConfig.Matches.Add(currentMatchConfiguration); - continue; - } - - if (currentMatchConfiguration != null) - { - ProcessMatchOption(currentMatchConfiguration, line); - } - else - { - ProcessGlobalOption(sshdConfig, line); - } - } - - if (sshdConfig.Ciphers == null) - { - // Obtain supported ciphers using ssh -Q cipher - } - - if (sshdConfig.KeyExchangeAlgorithms == null) - { - // Obtain supports key exchange algorithms using ssh -Q kex - } - - if (sshdConfig.HostKeyAlgorithms == null) - { - // Obtain supports host key algorithms using ssh -Q key - } - - if (sshdConfig.MessageAuthenticationCodeAlgorithms == null) - { - // Obtain supported MACs using ssh -Q mac - } - - - return sshdConfig; - } - } - private static void ProcessGlobalOption(SshdConfig sshdConfig, string line) { var matchOptionRegex = new Regex(@"^\s*(?[\S]+)\s+(?.+?){1}\s*$"); @@ -315,7 +320,7 @@ private static void ProcessGlobalOption(SshdConfig sshdConfig, string line) sshdConfig.Port = ToInt(value); break; case "HostKey": - sshdConfig.HostKeyFiles = ParseCommaSeparatedValue(value); + ParseCommaSeparatedValue(sshdConfig.HostKeyFiles, value); break; case "ChallengeResponseAuthentication": sshdConfig.ChallengeResponseAuthentication = ToBool(value); @@ -324,7 +329,7 @@ private static void ProcessGlobalOption(SshdConfig sshdConfig, string line) sshdConfig.KeyboardInteractiveAuthentication = ToBool(value); break; case "LogLevel": - sshdConfig.LogLevel = (LogLevel) Enum.Parse(typeof(LogLevel), value, true); + sshdConfig.LogLevel = Enum.Parse(value, ignoreCase: true); break; case "Subsystem": sshdConfig.Subsystems.Add(Subsystem.FromConfig(value)); @@ -382,7 +387,7 @@ private static void ProcessGlobalOption(SshdConfig sshdConfig, string line) case "GatewayPorts": break; default: - throw new Exception($"Global option '{name}' is not implemented."); + throw new NotSupportedException($"Global option '{name}' is not supported."); } } @@ -399,10 +404,12 @@ private static List ParseCiphers(string value) { var cipherNames = value.Split(','); var ciphers = new List(cipherNames.Length); + foreach (var cipherName in cipherNames) { ciphers.Add(new Cipher(cipherName.Trim())); } + return ciphers; } @@ -410,21 +417,30 @@ private static List ParseKeyExchangeAlgorithms(string valu { var kexNames = value.Split(','); var keyExchangeAlgorithms = new List(kexNames.Length); + foreach (var kexName in kexNames) { keyExchangeAlgorithms.Add(new KeyExchangeAlgorithm(kexName.Trim())); } + return keyExchangeAlgorithms; } public static List ParsePublicKeyAcceptedAlgorithms(string value) { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + var publicKeyAlgorithmNames = value.Split(','); var publicKeyAlgorithms = new List(publicKeyAlgorithmNames.Length); + foreach (var publicKeyAlgorithmName in publicKeyAlgorithmNames) { publicKeyAlgorithms.Add(new PublicKeyAlgorithm(publicKeyAlgorithmName.Trim())); } + return publicKeyAlgorithms; } @@ -432,10 +448,12 @@ private static List ParseHostKeyAlgorithms(string value) { var algorithmNames = value.Split(','); var hostKeyAlgorithms = new List(algorithmNames.Length); + foreach (var algorithmName in algorithmNames) { hostKeyAlgorithms.Add(new HostKeyAlgorithm(algorithmName.Trim())); } + return hostKeyAlgorithms; } @@ -443,10 +461,12 @@ private static List ParseMacs(string value) { var macNames = value.Split(','); var macAlgorithms = new List(macNames.Length); + foreach (var algorithmName in macNames) { macAlgorithms.Add(new MessageAuthenticationCodeAlgorithm(algorithmName.Trim())); } + return macAlgorithms; } @@ -472,15 +492,14 @@ private static void ProcessMatchOption(Match matchConfiguration, string line) matchConfiguration.AuthenticationMethods = value; break; default: - throw new Exception($"Match option '{name}' is not implemented."); + throw new NotSupportedException($"Match option '{name}' is not supported."); } } - - private static List ParseCommaSeparatedValue(string value) + private static void ParseCommaSeparatedValue(List list, string value) { var values = value.Split(','); - return new List(values); + list.AddRange(values); } private static bool ToBool(string value) @@ -492,7 +511,8 @@ private static bool ToBool(string value) case "no": return false; default: - throw new Exception($"Value '{value}' cannot be mapped to a boolean."); + throw new ArgumentException($"Value '{value}' cannot be mapped to a boolean.", + nameof(value)); } } diff --git a/test/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs b/test/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs index 4d1155105..140bc35bf 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs +++ b/test/Renci.SshNet.TestTools.OpenSSH/Subsystem.cs @@ -2,7 +2,7 @@ namespace Renci.SshNet.TestTools.OpenSSH { - public class Subsystem + public sealed class Subsystem { public Subsystem(string name, string command) { @@ -14,11 +14,6 @@ public Subsystem(string name, string command) public string Command { get; set; } - public void WriteTo(TextWriter writer) - { - writer.WriteLine(Name + "=" + Command); - } - public static Subsystem FromConfig(string value) { var subSystemValueRegex = new Regex(@"^\s*(?[\S]+)\s+(?.+?){1}\s*$"); @@ -35,7 +30,18 @@ public static Subsystem FromConfig(string value) return new Subsystem(name, command); } - throw new Exception($"'{value}' not recognized as value for Subsystem."); + throw new ArgumentException($"'{value}' not recognized as value for Subsystem.", + nameof(value)); + } + + public void WriteTo(TextWriter writer) + { + if (writer is null) + { + throw new ArgumentNullException(nameof(writer)); + } + + writer.WriteLine(Name + "=" + Command); } } } diff --git a/test/Renci.SshNet.Tests/.editorconfig b/test/Renci.SshNet.Tests/.editorconfig index b94e29112..aa6a9ba37 100644 --- a/test/Renci.SshNet.Tests/.editorconfig +++ b/test/Renci.SshNet.Tests/.editorconfig @@ -1,5 +1,59 @@ 锘縖*.cs] +#### Sonar rules #### + +# S108: Nested blocks of code should not be left empty +# https://rules.sonarsource.com/csharp/RSPEC-108/ +dotnet_diagnostic.S108.severity = suggestion + +# S125: Sections of code should not be commented out +# https://rules.sonarsource.com/csharp/RSPEC-125/ +dotnet_diagnostic.S125.severity = none + +# S1144: Unused private types or members should be removed +# https://rules.sonarsource.com/csharp/RSPEC-1144/ +dotnet_diagnostic.S1144.severity = none + +# S1186: Methods should not be empty +# https://rules.sonarsource.com/csharp/RSPEC-1186/ +dotnet_diagnostic.S1186.severity = none + +# S1607: Tests should not be ignored +# https://rules.sonarsource.com/csharp/RSPEC-1607/ +dotnet_diagnostic.S1607.severity = none + +# S2094: Classes should not be empty +# https://rules.sonarsource.com/csharp/RSPEC-2094/ +dotnet_diagnostic.S2094.severity = none + +# S2187: Test classes should contain at least one test case +# https://rules.sonarsource.com/csharp/RSPEC-2187/ +dotnet_diagnostic.S2187.severity = none + +# S2292: Trivial properties should be auto-implemented +# https://rules.sonarsource.com/csharp/RSPEC-2292/ +dotnet_diagnostic.S2292.severity = none + +# S2925: "Thread.Sleep" should not be used in tests +# https://rules.sonarsource.com/csharp/RSPEC-2925/ +dotnet_diagnostic.S2925.severity = none + +# S3415: Assertion arguments should be passed in the correct order +# https://rules.sonarsource.com/csharp/RSPEC-3415/ +dotnet_diagnostic.S3415.severity = none + +# S3881: "IDisposable" should be implemented correctly +# https://rules.sonarsource.com/csharp/RSPEC-3881/ +dotnet_diagnostic.S3881.severity = none + +# S4144: Methods should not have identical implementations +# https://rules.sonarsource.com/csharp/RSPEC-4144/ +dotnet_diagnostic.S4144.severity = none + +# S4158: Empty collections should not be accessed or iterated +# https://rules.sonarsource.com/csharp/RSPEC-4158/ +dotnet_diagnostic.S4158.severity = none + #### SYSLIB diagnostics #### # SYSLIB1045: Use 'GeneratedRegexAttribute' to generate the regular expression implementation at compile-time @@ -9,8 +63,306 @@ dotnet_diagnostic.SYSLIB1045.severity = none ### StyleCop Analyzers rules ### +# SA1000: Keywords must be spaced correctly +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1000.md +dotnet_diagnostic.SA1000.severity = suggestion + +# SA1001: Commas must be spaced correctly +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1001.md +dotnet_diagnostic.SA1001.severity = suggestion + +# SA1002: Semicolons must be spaced correctly +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1002.md +dotnet_diagnostic.SA1002.severity = suggestion + +# SA1004: Documentation lines must begin with single space +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1004.md +dotnet_diagnostic.SA1004.severity = suggestion + +# SA1005: Single line comments must begin with single space +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1005.md +dotnet_diagnostic.SA1005.severity = suggestion + +# SA1012: Opening braces must be spaced correctly +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1012.md +dotnet_diagnostic.SA1012.severity = suggestion + +# SA1013: Closing braces must be spaced correctly +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1013.md +dotnet_diagnostic.SA1013.severity = suggestion + +# SA1025: Code must not contain multiple whitespace in a row +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1025.md +dotnet_diagnostic.SA1025.severity = suggestion + +# SA1026: Code must not contain space after new keyword in implicitly typed array allocation +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1026.md +dotnet_diagnostic.SA1026.severity = suggestion + +# SA1028: Code must not contain trailing whitespace +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1028.md +dotnet_diagnostic.SA1028.severity = suggestion + +# SA1111: Closing parenthesis must be on line of last parameter +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1111.md +dotnet_diagnostic.SA1111.severity = suggestion + +# SA1117: Parameters must be on same line or separate lines +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1028.md +dotnet_diagnostic.SA1117.severity = suggestion + +# SA1119: Statement must not use unnecessary parenthesis +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1119.md +dotnet_diagnostic.SA1119.severity = suggestion + +# SA1120: Comments must contain text +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1120.md +dotnet_diagnostic.SA1120.severity = suggestion + +# SA1122: Use String.Empty for empty strings +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1122.md +dotnet_diagnostic.SA1122.severity = suggestion + +# SA1123:Do not place regions within elements +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1123.md +dotnet_diagnostic.SA1123.severity = suggestion + +# SA1124: Do not use regions +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1124.md +dotnet_diagnostic.SA1124.severity = suggestion + +# SA1128: Constructor initializer must be on own line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1128.md +dotnet_diagnostic.SA1128.severity = suggestion + +# SA1129: Do not use default value type constructor +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1129.md +dotnet_diagnostic.SA1129.severity = suggestion + +# SA1133: Do not combine attributes +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1133.md +dotnet_diagnostic.SA1133.severity = suggestion + +# SA1137: Elements should have the same indentation +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1137.md +dotnet_diagnostic.SA1137.severity = suggestion + +# SA1139: Use literals suffix notation instead of casting +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1139.md +dotnet_diagnostic.SA1139.severity = suggestion + +# SA1204: Static elements must appear before instance elements +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1204.md +dotnet_diagnostic.SA1204.severity = suggestion + +# SA1208: System using directives must be placed before other using directives +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1208.md +dotnet_diagnostic.SA1208.severity = suggestion + +# SA1210: Using directives must be ordered alphabetically by namespace +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1210.md +dotnet_diagnostic.SA1210.severity = suggestion + +# SA1214: Readonly elements must appear before non-readonly elements +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1214.md +dotnet_diagnostic.SA1214.severity = suggestion + +# SA1306: Field names must begin with lower case letter +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1306.md +dotnet_diagnostic.SA1306.severity = suggestion + +# SA1310: Field names must not contain underscore +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1310.md +dotnet_diagnostic.SA1310.severity = suggestion + +# SA1400: Access modifier must be declared +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1400.md +dotnet_diagnostic.SA1400.severity = suggestion + +# SA1401: Fields must be private +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1401.md +dotnet_diagnostic.SA1401.severity = suggestion + +# SA1402: File may only contain a single type +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1402.md +dotnet_diagnostic.SA1402.severity = suggestion + +# SA1404: Code analysis suppression must have justification +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1404.md +dotnet_diagnostic.SA1404.severity = suggestion + +# SA1411: Attribute constructor must not use unnecessary parenthesis +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1411.md +dotnet_diagnostic.SA1411.severity = suggestion + +# SA1500: Braces for multiline statements must not share line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1500.md +dotnet_diagnostic.SA1500.severity = suggestion + +# SA1501: Statement must not be on single line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1501.md +dotnet_diagnostic.SA1501.severity = suggestion + +# SA1505: Opening braces must not be followed by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1505.md +dotnet_diagnostic.SA1505.severity = suggestion + +# SA1507: Code must not contain multiple blank lines in a row +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1507.md +dotnet_diagnostic.SA1507.severity = suggestion + +# SA1508: Closing braces must not be preceded by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1508.md +dotnet_diagnostic.SA1508.severity = suggestion + +# SA1512: Single line comments must not be followed by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1512.md +dotnet_diagnostic.SA1512.severity = suggestion + +# SA1513: Closing brace must be followed by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1513.md +dotnet_diagnostic.SA1513.severity = suggestion + +# SA1515: Single line comment must be preceded by blank line +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1515.md +dotnet_diagnostic.SA1515.severity = suggestion + +# SA1518: Use line endings correctly at end of file +https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1518.md +dotnet_diagnostic.SA1518.severity = suggestion + +# SA1636: File header copyright text must match +https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1636.md +dotnet_diagnostic.SA1636.severity = suggestion + +# SA1642: Constructor summary documentation must begin with standard text +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1642.md +dotnet_diagnostic.SA1642.severity = suggestion + +# SA1649: File name must match type name +https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1649.md +dotnet_diagnostic.SA1649.severity = suggestion + +#### Meziantou.Analyzer rules #### + +# MA0001: StringComparison is missing +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0001.md +dotnet_diagnostic.MA0001.severity = suggestion + +# MA0003: Add parameter name to improve readability +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0003.md +dotnet_diagnostic.MA0003.severity = suggestion + +# MA0004: Use Task.ConfigureAwait(false) +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0004.md +dotnet_diagnostic.MA0004.severity = suggestion + +# MA0005: Use Array.Empty() +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0005.md +dotnet_diagnostic.MA0005.severity = suggestion + +# MA0011: IFormatProvider is missing +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0011.md +dotnet_diagnostic.MA0011.severity = suggestion + +# MA0015: Specify the parameter name in ArgumentException +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0015.md +dotnet_diagnostic.MA0015.severity = suggestion + +# MA0019: Use EventArgs.Empty +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0019.md +dotnet_diagnostic.MA0019.severity = suggestion + +# MA0035: Do not use dangerous threading methods +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0035.md +dotnet_diagnostic.MA0035.severity = suggestion + +# MA0040: Forward the CancellationToken parameter to methods that take one +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0040.md +dotnet_diagnostic.MA0040.severity = suggestion + +# MA0046: Use EventHandler to declare events +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0046.md +dotnet_diagnostic.MA0046.severity = suggestion + +# MA0053: Make class sealed +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0053.md +dotnet_diagnostic.MA0053.severity = suggestion + +# MA0060: The value returned by Stream.Read/Stream.ReadAsync is not used +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0060.md +dotnet_diagnostic.MA0060.severity = suggestion + +# MA0075: Do not use implicit culture-sensitive ToString +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0075.md +dotnet_diagnostic.MA0075.severity = suggestion + +# MA0099 - Use Explicit enum value instead of 0 +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0099.md +dotnet_diagnostic.MA0099.severity = suggestion + +# MA0110: Use the Regex source generator +# https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0110.md +dotnet_diagnostic.MA0110.severity = suggestion + #### .NET Compiler Platform analysers rules #### +# CA1031: Do not catch general exception types +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1031 +dotnet_diagnostic.CA1031.severity = suggestion + +# CA1062: Validate arguments of public methods +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1062 +dotnet_diagnostic.CA1062.severity = suggestion + +# CA1063: Implement IDisposable correctly +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1063 +dotnet_diagnostic.CA1063.severity = suggestion + +# CA1307: Specify StringComparison for clarity +https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1307 +dotnet_diagnostic.CA1307.severity = suggestion + +# CA1806: Do not ignore method results +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1806 +dotnet_diagnostic.CA1806.severity = suggestion + +# CA1812: Avoid uninstantiated internal classes +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1812 +dotnet_diagnostic.CA1812.severity = suggestion + +# CA1822: Mark members as static +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1822 +dotnet_diagnostic.CA1822.severity = suggestion + +# CA1825: Avoid zero-length array allocations +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1825 +dotnet_diagnostic.CA1825.severity = suggestion + +# CA1859: Use concrete types when possible for improved performance +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1859 +dotnet_diagnostic.CA1859.severity = suggestion + +# CA2000: Dispose objects before losing scope +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2000 +dotnet_diagnostic.CA2000.severity = suggestion + +# CA2007: Do not directly await a Task +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2007 +dotnet_diagnostic.CA2007.severity = suggestion + +# CA2201: Do not raise reserved exception types +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2201 +dotnet_diagnostic.CA2201.severity = suggestion + +# CA2213: Disposable fields should be disposed +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2213 +dotnet_diagnostic.CA2213.severity = suggestion + +# CA2227: Collection properties should be read only +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2227 +dotnet_diagnostic.CA2227.severity = suggestion + # IDE0007: Use var instead of explicit type # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ide0007 dotnet_diagnostic.IDE0007.severity = suggestion diff --git a/test/Renci.SshNet.Tests/Classes/Common/SshDataTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SshDataTest.cs index e5b7bc86b..03b489121 100644 --- a/test/Renci.SshNet.Tests/Classes/Common/SshDataTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Common/SshDataTest.cs @@ -1,5 +1,7 @@ 锘縰sing System; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Renci.SshNet.Common; namespace Renci.SshNet.Tests.Classes.Common @@ -86,6 +88,55 @@ public void Load_DataAndOffsetAndCount() Assert.AreEqual(two, request.ValueTwo); } + [TestMethod] + public void ReadBytes_Length_LengthEqualsNumberOfBytesAvailable() + { + MySshData sshData = new MySshData(); + + sshData.Load(new byte[] { 0x01, 0x0d, 0x0a, 0x07, 0x0b }, 0, 4); + sshData.Write(new byte[] { 0x09, 0x03, 0x06, 0x0b }, 0, 3); + + var bytes = sshData.ReadBytes(1); + + CollectionAssert.AreEqual(new byte[] { 0x07 }, bytes); + } + + [TestMethod] + public void ReadBytes_Length_LengthIsGreaterThanNumberOfBytesAvailable() + { + MySshData sshData = new MySshData(); + + sshData.Load(new byte[] { 0x01, 0x0d, 0x0a }, 0, 3); + + try + { + sshData.ReadBytes(4); + Assert.Fail(); + } + catch (ArgumentOutOfRangeException ex) + { + Assert.AreEqual(typeof(ArgumentOutOfRangeException), ex.GetType()); + Assert.IsNull(ex.InnerException); + Assert.AreEqual("length", ex.ParamName); + } + } + + [TestMethod] + public void ReadBytes_Length_LengthIsLessThanNumberOfBytesAvailable() + { + MySshData sshData = new MySshData(); + + sshData.Load(new byte[] { 0x05, 0x07, 0x02, 0x0b, 0x0a, 0x0d }, 0, 5); + + var bytes = sshData.ReadBytes(2); + + CollectionAssert.AreEqual(new byte[] { 0x05, 0x07 }, bytes); + + bytes = sshData.ReadBytes(3); + + CollectionAssert.AreEqual(new byte[] { 0x02, 0x0b, 0x0a }, bytes); + } + private class BoolSshData : SshData { private readonly bool _value; @@ -145,5 +196,26 @@ protected override void SaveData() Write(ValueTwo); } } + + private class MySshData : SshData + { + protected override void LoadData() + { + } + + protected override void SaveData() + { + } + + public new byte[] ReadBytes(int length) + { + return base.ReadBytes(length); + } + + public new void Write(byte[] buffer, int offset, int count) + { + base.Write(buffer, offset, count); + } + } } } diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs index 09423c6bd..e366914c7 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessRead.cs @@ -2,6 +2,7 @@ using System.IO; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Sftp; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -48,8 +49,8 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("{0} mode can be requested only when combined with write-only access.", _fileMode), _actualException.Message); - Assert.IsNull(_actualException.ParamName); + ArgumentExceptionAssert.MessageEquals(string.Format("{0} mode can be requested only when combined with write-only access.", _fileMode), _actualException); + Assert.AreEqual("mode", _actualException.ParamName); } } } diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs index 8f31995ce..d4b311ffa 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeAppend_FileAccessReadWrite.cs @@ -2,6 +2,7 @@ using System.IO; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Sftp; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -48,8 +49,8 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("{0} mode can be requested only when combined with write-only access.", _fileMode), _actualException.Message); - Assert.IsNull(_actualException.ParamName); + ArgumentExceptionAssert.MessageEquals(string.Format("{0} mode can be requested only when combined with write-only access.", _fileMode), _actualException); + Assert.AreEqual("mode", _actualException.ParamName); } } } diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs index 47cabd2a6..5fd18e511 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreateNew_FileAccessRead.cs @@ -4,6 +4,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Sftp; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -50,8 +51,8 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException.Message); - Assert.IsNull(_actualException.ParamName); + ArgumentExceptionAssert.MessageEquals(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException); + Assert.AreEqual("mode", _actualException.ParamName); } } } diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs index 29e4956ac..c70b3239f 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeCreate_FileAccessRead.cs @@ -4,6 +4,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Sftp; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -50,8 +51,8 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException.Message); - Assert.IsNull(_actualException.ParamName); + ArgumentExceptionAssert.MessageEquals(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException); + Assert.AreEqual("mode", _actualException.ParamName); } } } diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs index 2ed977784..9e520a597 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Ctor_FileModeTruncate_FileAccessRead.cs @@ -2,6 +2,7 @@ using System.IO; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Sftp; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -48,8 +49,8 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException.Message); - Assert.IsNull(_actualException.ParamName); + ArgumentExceptionAssert.MessageEquals(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException); + Assert.AreEqual("mode", _actualException.ParamName); } } } diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs index 14a2338b0..242755a04 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessRead.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Sftp; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -49,8 +50,8 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("{0} mode can be requested only when combined with write-only access.", _fileMode), _actualException.Message); - Assert.IsNull(_actualException.ParamName); + ArgumentExceptionAssert.MessageEquals(string.Format("{0} mode can be requested only when combined with write-only access.", _fileMode), _actualException); + Assert.AreEqual("mode", _actualException.ParamName); } } } diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs index c58f33873..776cec41f 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeAppend_FileAccessReadWrite.cs @@ -3,6 +3,7 @@ using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Sftp; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -49,8 +50,8 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("{0} mode can be requested only when combined with write-only access.", _fileMode), _actualException.Message); - Assert.IsNull(_actualException.ParamName); + ArgumentExceptionAssert.MessageEquals(string.Format("{0} mode can be requested only when combined with write-only access.", _fileMode), _actualException); + Assert.AreEqual("mode", _actualException.ParamName); } } } diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs index 1d8b792dd..900f1b15d 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreateNew_FileAccessRead.cs @@ -5,6 +5,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Sftp; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -51,8 +52,8 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException.Message); - Assert.IsNull(_actualException.ParamName); + ArgumentExceptionAssert.MessageEquals(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException); + Assert.AreEqual("mode", _actualException.ParamName); } } } diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs index d253c30e4..6924da972 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeCreate_FileAccessRead.cs @@ -5,6 +5,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Sftp; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -51,8 +52,8 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException.Message); - Assert.IsNull(_actualException.ParamName); + ArgumentExceptionAssert.MessageEquals(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException); + Assert.AreEqual("mode", _actualException.ParamName); } } } diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs index 660bd1a1f..276455b7a 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_OpenAsync_FileModeTruncate_FileAccessRead.cs @@ -5,6 +5,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Sftp; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Sftp { @@ -51,8 +52,8 @@ public void CtorShouldHaveThrownArgumentException() { Assert.IsNotNull(_actualException); Assert.IsNull(_actualException.InnerException); - Assert.AreEqual(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException.Message); - Assert.IsNull(_actualException.ParamName); + ArgumentExceptionAssert.MessageEquals(string.Format("Combining {0}: {1} with {2}: {3} is invalid.", nameof(FileMode), _fileMode, nameof(FileAccess), _fileAccess), _actualException); + Assert.AreEqual("mode", _actualException.ParamName); } } } From 826222f6fe33450754b1bb58c6a8e033e912b5ff Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Sun, 5 Nov 2023 08:45:30 +0000 Subject: [PATCH 58/96] Increase test coverage for AesCipher (#1232) * Increase test coverage for AesCipher The tests were generated by a script which is also added for posterity. The script works by running "openssl enc [...]" (via WSL) to generate the expected encrypted values, and also verifies those values against the .NET BCL implementation as an extra validation (it uncovered a difference in CFB mode between the two relating to the feedback size). * Fix OfbCipherMode It was an exact copy of CfbCipherMode --- .../Ciphers/Modes/OfbCipherMode.cs | 5 +- .../Ciphers/AesCipherTest.Gen.cs.txt | 142 ++ .../Cryptography/Ciphers/AesCipherTest.cs | 1511 +++++++++++++++++ 3 files changed, 1655 insertions(+), 3 deletions(-) create mode 100644 test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.Gen.cs.txt diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs index e87dc9d32..df2ce60be 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs @@ -50,14 +50,13 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC _ = Cipher.EncryptBlock(IV, 0, IV.Length, _ivOutput, 0); + Buffer.BlockCopy(_ivOutput, 0, IV, 0, IV.Length); + for (var i = 0; i < _blockSize; i++) { outputBuffer[outputOffset + i] = (byte)(_ivOutput[i] ^ inputBuffer[inputOffset + i]); } - Buffer.BlockCopy(IV, _blockSize, IV, 0, IV.Length - _blockSize); - Buffer.BlockCopy(outputBuffer, outputOffset, IV, IV.Length - _blockSize, _blockSize); - return _blockSize; } diff --git a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.Gen.cs.txt b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.Gen.cs.txt new file mode 100644 index 000000000..c0bda499b --- /dev/null +++ b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.Gen.cs.txt @@ -0,0 +1,142 @@ +// Used to generate tests in AesCipherTest.cs + +// The script works by running "openssl enc [...]" (via WSL) to generate the +// expected encrypted values, and also verifies those values against the .NET +// BCL implementation as an extra validation before generating the tests. + +Dictionary modes = new() +{ + ["ecb"] = ("mode: null", CipherMode.ECB), + ["cbc"] = ("new CbcCipherMode((byte[])iv.Clone())", CipherMode.CBC), + ["cfb"] = ("new CfbCipherMode((byte[])iv.Clone())", CipherMode.CFB), + ["ctr"] = ("new CtrCipherMode((byte[])iv.Clone())", null), + ["ofb"] = ("new OfbCipherMode((byte[])iv.Clone())", CipherMode.OFB), +}; + +Random random = new(123); + +using IndentedTextWriter tw = new(Console.Out); + +foreach ((string mode, (string modeCode, CipherMode? bclMode)) in modes) +{ + foreach (int keySize in new int[] { 128, 192, 256 }) + { + foreach (int inputLength in new int[] { 16, 32, 64 }) + { + byte[] input = new byte[inputLength]; + random.NextBytes(input); + + byte[] key = new byte[keySize / 8]; + random.NextBytes(key); + + byte[] iv = new byte[16]; + random.NextBytes(iv); + + StringBuilder openSslCmd = new(); + + openSslCmd.Append($"echo -n -e '{string.Join("", input.Select(b => $"\\x{b:x2}"))}' |"); + openSslCmd.Append($" openssl enc -e -aes-{keySize}-{mode}"); + openSslCmd.Append($" -K {Convert.ToHexString(key)}"); + if (mode != "ecb") + { + openSslCmd.Append($" -iv {Convert.ToHexString(iv)}"); + } + openSslCmd.Append(" -nopad"); + + ProcessStartInfo pi = new("wsl", openSslCmd.ToString()) + { + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + + byte[] expected; + string error; + + using (MemoryStream ms = new()) + { + var p = Process.Start(pi); + p.StandardOutput.BaseStream.CopyTo(ms); + error = p.StandardError.ReadToEnd(); + + p.WaitForExit(); + + expected = ms.ToArray(); + } + + tw.WriteLine("[TestMethod]"); + tw.WriteLine($"public void AES_{mode.ToUpper()}_{keySize}_Length{inputLength}()"); + tw.WriteLine("{"); + tw.Indent++; + + WriteBytes(input); + WriteBytes(key); + if (mode != "ecb") + { + WriteBytes(iv); + } + tw.WriteLine(); + + if (!string.IsNullOrWhiteSpace(error)) + { + tw.WriteLine($"// {openSslCmd}"); + tw.WriteLine($"Assert.Fail(@\"{error}\");"); + + tw.Indent--; + tw.WriteLine("}"); + tw.WriteLine(); + continue; + } + + tw.WriteLine($"// {openSslCmd} | hd"); // pipe to hexdump + WriteBytes(expected); + tw.WriteLine(); + tw.WriteLine($"var actual = new AesCipher(key, {modeCode}, padding: null).Encrypt(input);"); + tw.WriteLine(); + tw.WriteLine($"CollectionAssert.AreEqual(expected, actual);"); + + if (bclMode is not null and not CipherMode.OFB) + { + // Verify the OpenSSL result is the same as the .NET BCL, just to be sure + Aes bcl = Aes.Create(); + bcl.Key = key; + bcl.IV = iv; + bcl.Mode = bclMode.Value; + bcl.Padding = PaddingMode.None; + bcl.FeedbackSize = 128; // .NET is CFB8 by default, OpenSSL is CFB128 + byte[] bclBytes = bcl.CreateEncryptor().TransformFinalBlock(input, 0, input.Length); + + if (!bclBytes.AsSpan().SequenceEqual(expected)) + { + tw.WriteLine(); + tw.WriteLine(@"Assert.Inconclusive(@""OpenSSL does not match the .NET BCL"); + tw.Indent++; + tw.WriteLine($@"OpenSSL: {Convert.ToHexString(expected)}"); + tw.WriteLine($@"BCL: {Convert.ToHexString(bclBytes)}"");"); + tw.Indent--; + } + } + + tw.WriteLine(); + tw.WriteLine($"var decrypted = new AesCipher(key, {modeCode}, padding: null).Decrypt(actual);"); + tw.WriteLine(); + tw.WriteLine($"CollectionAssert.AreEqual(input, decrypted);"); + + tw.Indent--; + tw.WriteLine("}"); + tw.WriteLine(); + } + } +} + +void WriteBytes(byte[] bytes, [CallerArgumentExpression(nameof(bytes))] string name = null) +{ + tw.WriteLine($"var {name} = new byte[]"); + tw.WriteLine("{"); + tw.Indent++; + foreach (byte[] chunk in bytes.Chunk(16)) + { + tw.WriteLine(string.Join(", ", chunk.Select(b => $"0x{b:x2}")) + ','); + } + tw.Indent--; + tw.WriteLine("};"); +} diff --git a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs index b439b67a4..1587481ea 100644 --- a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs @@ -82,5 +82,1516 @@ public void Decrypt_InputAndOffsetAndLength_128_CTR() Assert.IsTrue(expected.IsEqualTo(actual)); } + + // All tests below this line were generated by the script in AesCipherTest.Gen.cs.txt + + [TestMethod] + public void AES_ECB_128_Length16() + { + var input = new byte[] + { + 0x03, 0xe1, 0xe1, 0xaa, 0xa5, 0xbc, 0xa1, 0x9f, 0xba, 0x8c, 0x42, 0x05, 0x8b, 0x4a, 0xbf, 0x28, + }; + var key = new byte[] + { + 0x96, 0x39, 0xec, 0x0d, 0xfc, 0x2d, 0xb2, 0x7c, 0xe9, 0x74, 0x8e, 0x5f, 0xb9, 0xf3, 0x99, 0xce, + }; + + // echo -n -e '\x03\xe1\xe1\xaa\xa5\xbc\xa1\x9f\xba\x8c\x42\x05\x8b\x4a\xbf\x28' | openssl enc -e -aes-128-ecb -K 9639EC0DFC2DB27CE9748E5FB9F399CE -nopad | hd + var expected = new byte[] + { + 0x9d, 0x55, 0x05, 0x4e, 0xe9, 0x50, 0xb5, 0x93, 0x50, 0x93, 0x69, 0x96, 0xa6, 0xdd, 0x1e, 0x15, + }; + + var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_ECB_128_Length32() + { + var input = new byte[] + { + 0x1a, 0xf1, 0x3a, 0x35, 0x8c, 0xca, 0x3f, 0xd6, 0x2f, 0x65, 0xc1, 0x31, 0x2d, 0x41, 0xe5, 0xc7, + 0xf3, 0x74, 0x23, 0x71, 0xed, 0x6d, 0x84, 0x79, 0x61, 0xd0, 0xf8, 0x6f, 0x7f, 0x0c, 0xcc, 0x86, + }; + var key = new byte[] + { + 0x67, 0x02, 0x45, 0xc8, 0xb8, 0x64, 0x42, 0x17, 0xda, 0x85, 0x21, 0x3e, 0x5c, 0xa6, 0xee, 0xd4, + }; + + // echo -n -e '\x1a\xf1\x3a\x35\x8c\xca\x3f\xd6\x2f\x65\xc1\x31\x2d\x41\xe5\xc7\xf3\x74\x23\x71\xed\x6d\x84\x79\x61\xd0\xf8\x6f\x7f\x0c\xcc\x86' | openssl enc -e -aes-128-ecb -K 670245C8B8644217DA85213E5CA6EED4 -nopad | hd + var expected = new byte[] + { + 0x73, 0x67, 0xcc, 0x04, 0x46, 0xf5, 0x31, 0x9b, 0x64, 0x26, 0x32, 0xba, 0xa4, 0x18, 0x0d, 0x8a, + 0xe3, 0x1c, 0x95, 0x44, 0x49, 0x9e, 0x4a, 0x17, 0x0e, 0x64, 0xd3, 0xe8, 0x5c, 0xe6, 0x9f, 0x83, + }; + + var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_ECB_128_Length64() + { + var input = new byte[] + { + 0x99, 0x3a, 0xc9, 0x2b, 0xfb, 0x1d, 0x0e, 0x8e, 0x31, 0x0c, 0x96, 0x68, 0x4c, 0x46, 0x1d, 0xbb, + 0xe1, 0x23, 0xc8, 0x99, 0x59, 0x90, 0x47, 0xcb, 0x63, 0x99, 0x5b, 0xf7, 0x91, 0x87, 0x44, 0x09, + 0x2e, 0xff, 0xa4, 0x21, 0xdc, 0xc3, 0xd9, 0x89, 0xd7, 0x24, 0x0a, 0x32, 0x05, 0x36, 0x60, 0x25, + 0xa4, 0x17, 0xda, 0xaf, 0x08, 0xbe, 0xc9, 0x08, 0xf3, 0xfe, 0xc7, 0x61, 0xc2, 0x17, 0xfd, 0xaa, + }; + var key = new byte[] + { + 0xc7, 0x8d, 0x3a, 0x4c, 0xa2, 0xfb, 0xde, 0x1e, 0x49, 0x3e, 0xc1, 0x34, 0x86, 0x14, 0xc6, 0x2d, + }; + + // echo -n -e '\x99\x3a\xc9\x2b\xfb\x1d\x0e\x8e\x31\x0c\x96\x68\x4c\x46\x1d\xbb\xe1\x23\xc8\x99\x59\x90\x47\xcb\x63\x99\x5b\xf7\x91\x87\x44\x09\x2e\xff\xa4\x21\xdc\xc3\xd9\x89\xd7\x24\x0a\x32\x05\x36\x60\x25\xa4\x17\xda\xaf\x08\xbe\xc9\x08\xf3\xfe\xc7\x61\xc2\x17\xfd\xaa' | openssl enc -e -aes-128-ecb -K C78D3A4CA2FBDE1E493EC1348614C62D -nopad | hd + var expected = new byte[] + { + 0x3f, 0xdb, 0xa3, 0xbb, 0xf2, 0x98, 0x24, 0x14, 0xe9, 0x0e, 0x74, 0xc3, 0x96, 0xfe, 0x54, 0xd6, + 0xfb, 0x78, 0x6a, 0x70, 0x8d, 0x5e, 0xe2, 0x31, 0x51, 0x74, 0xaf, 0x31, 0x67, 0xb6, 0x90, 0xfc, + 0xee, 0x64, 0xf2, 0xf4, 0xa3, 0x20, 0x54, 0x84, 0x7f, 0x8d, 0xe1, 0x6b, 0xf3, 0xd9, 0x7e, 0x34, + 0x10, 0xe3, 0xe0, 0x30, 0xd3, 0x0e, 0xe3, 0x94, 0xd8, 0xf5, 0xb1, 0x44, 0xf8, 0x36, 0xfd, 0x0b, + }; + + var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_ECB_192_Length16() + { + var input = new byte[] + { + 0x27, 0x60, 0x6b, 0x78, 0xfc, 0x13, 0x83, 0xa8, 0x38, 0xbb, 0x65, 0xca, 0xfd, 0x94, 0x82, 0xde, + }; + var key = new byte[] + { + 0x38, 0x99, 0x28, 0x8c, 0xc4, 0x84, 0xfd, 0x32, 0x8c, 0xca, 0x16, 0x06, 0xcc, 0x00, 0x22, 0xd2, + 0x76, 0x00, 0x0d, 0x25, 0xa9, 0x4e, 0x31, 0x25, + }; + + // echo -n -e '\x27\x60\x6b\x78\xfc\x13\x83\xa8\x38\xbb\x65\xca\xfd\x94\x82\xde' | openssl enc -e -aes-192-ecb -K 3899288CC484FD328CCA1606CC0022D276000D25A94E3125 -nopad | hd + var expected = new byte[] + { + 0x1c, 0xd3, 0x91, 0xd8, 0xc3, 0xe0, 0x4d, 0x8e, 0x9e, 0x5c, 0xaf, 0xcc, 0x55, 0x65, 0x54, 0xb7, + }; + + var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_ECB_192_Length32() + { + var input = new byte[] + { + 0x63, 0x38, 0xec, 0x32, 0xfd, 0x7d, 0xdb, 0x38, 0x99, 0x93, 0x53, 0xfc, 0x86, 0x5d, 0x35, 0xe9, + 0x68, 0x02, 0xda, 0x1a, 0x43, 0x0b, 0x02, 0x55, 0x57, 0x74, 0xed, 0x7d, 0x5a, 0xbf, 0x82, 0x3b, + }; + var key = new byte[] + { + 0x05, 0x6a, 0xc2, 0x70, 0x62, 0xff, 0x28, 0x34, 0xce, 0x08, 0x58, 0x9c, 0xe3, 0x76, 0x1b, 0xbb, + 0x1a, 0xbc, 0xf9, 0x4c, 0x60, 0xe1, 0x5f, 0x57, + }; + + // echo -n -e '\x63\x38\xec\x32\xfd\x7d\xdb\x38\x99\x93\x53\xfc\x86\x5d\x35\xe9\x68\x02\xda\x1a\x43\x0b\x02\x55\x57\x74\xed\x7d\x5a\xbf\x82\x3b' | openssl enc -e -aes-192-ecb -K 056AC27062FF2834CE08589CE3761BBB1ABCF94C60E15F57 -nopad | hd + var expected = new byte[] + { + 0x02, 0x7c, 0x02, 0x3d, 0x80, 0x78, 0xbe, 0x53, 0x10, 0xb9, 0x1b, 0xbf, 0xb4, 0x2c, 0x16, 0xe7, + 0x87, 0xe2, 0x91, 0x40, 0x31, 0x26, 0x67, 0xf6, 0xf7, 0x86, 0x73, 0x89, 0x0d, 0x35, 0x22, 0x6c, + }; + + var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_ECB_192_Length64() + { + var input = new byte[] + { + 0xda, 0xa5, 0x4b, 0x3b, 0xb3, 0x66, 0x71, 0xe0, 0x58, 0x31, 0x62, 0x9d, 0xc6, 0x36, 0xda, 0x23, + 0x0b, 0x6b, 0x3b, 0xcb, 0x24, 0x9f, 0xa4, 0x6f, 0x29, 0x7e, 0x8b, 0xcb, 0x7f, 0xff, 0x21, 0x56, + 0x34, 0x90, 0x72, 0xba, 0x95, 0x23, 0xa3, 0xcf, 0x25, 0xfa, 0x30, 0x5e, 0xfc, 0x40, 0x13, 0xda, + 0x3d, 0xd3, 0x10, 0x2f, 0x89, 0xbc, 0x44, 0x3a, 0x01, 0xdb, 0x11, 0x34, 0xda, 0xa5, 0x60, 0x58, + }; + var key = new byte[] + { + 0x10, 0x0c, 0x69, 0x35, 0xc3, 0x1f, 0x8d, 0xe7, 0xc7, 0x6b, 0xa5, 0x2a, 0x6f, 0x46, 0x73, 0xe9, + 0x6b, 0xb1, 0x8e, 0xac, 0xef, 0xf1, 0xcc, 0x78, + }; + + // echo -n -e '\xda\xa5\x4b\x3b\xb3\x66\x71\xe0\x58\x31\x62\x9d\xc6\x36\xda\x23\x0b\x6b\x3b\xcb\x24\x9f\xa4\x6f\x29\x7e\x8b\xcb\x7f\xff\x21\x56\x34\x90\x72\xba\x95\x23\xa3\xcf\x25\xfa\x30\x5e\xfc\x40\x13\xda\x3d\xd3\x10\x2f\x89\xbc\x44\x3a\x01\xdb\x11\x34\xda\xa5\x60\x58' | openssl enc -e -aes-192-ecb -K 100C6935C31F8DE7C76BA52A6F4673E96BB18EACEFF1CC78 -nopad | hd + var expected = new byte[] + { + 0x5e, 0x66, 0x56, 0xfb, 0x86, 0xff, 0x50, 0xba, 0x1a, 0xf4, 0xff, 0x65, 0xaa, 0x32, 0xbb, 0xa0, + 0x02, 0x3f, 0x2f, 0x5c, 0x4e, 0x16, 0x0d, 0xaa, 0xb1, 0x8b, 0x2f, 0xb9, 0x42, 0xec, 0xa1, 0x16, + 0xc1, 0xe2, 0xf0, 0xbc, 0x01, 0xad, 0xb1, 0x15, 0xaf, 0x42, 0x6c, 0x08, 0xc8, 0xb3, 0x98, 0xf3, + 0xcd, 0x20, 0xab, 0xbc, 0x59, 0xb2, 0xa5, 0x80, 0xf5, 0x8e, 0x53, 0xda, 0xb1, 0x39, 0x8f, 0xbc, + }; + + var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_ECB_256_Length16() + { + var input = new byte[] + { + 0x45, 0x29, 0x67, 0x1d, 0x16, 0x1a, 0xcb, 0xba, 0x67, 0x28, 0xc9, 0x28, 0x17, 0xb4, 0x69, 0x1e, + }; + var key = new byte[] + { + 0x3f, 0xf1, 0xe9, 0x8b, 0x65, 0xd3, 0xd5, 0x58, 0x77, 0x26, 0x91, 0x97, 0xf9, 0x84, 0x12, 0x8e, + 0x9b, 0x71, 0x66, 0xc6, 0x8a, 0xaf, 0x61, 0x31, 0x6c, 0xff, 0x52, 0xea, 0xa5, 0xcb, 0x68, 0xe4, + }; + + // echo -n -e '\x45\x29\x67\x1d\x16\x1a\xcb\xba\x67\x28\xc9\x28\x17\xb4\x69\x1e' | openssl enc -e -aes-256-ecb -K 3FF1E98B65D3D55877269197F984128E9B7166C68AAF61316CFF52EAA5CB68E4 -nopad | hd + var expected = new byte[] + { + 0x6a, 0xd2, 0x73, 0x2b, 0x05, 0x2e, 0xdd, 0x74, 0x0c, 0x37, 0xf2, 0xcf, 0x8a, 0xef, 0x57, 0x8a, + }; + + var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_ECB_256_Length32() + { + var input = new byte[] + { + 0x16, 0x3b, 0x8d, 0xa6, 0x4d, 0xa3, 0x94, 0x8f, 0x8f, 0xb8, 0x1f, 0x66, 0x81, 0xeb, 0xb3, 0xab, + 0xbe, 0xac, 0x29, 0xca, 0xd3, 0x2b, 0x9a, 0x10, 0xba, 0xf4, 0x72, 0x7b, 0x09, 0x70, 0xa8, 0x38, + }; + var key = new byte[] + { + 0x3e, 0x6e, 0xd3, 0x69, 0x3e, 0xc2, 0x96, 0xca, 0x9a, 0x20, 0x56, 0x3a, 0x6b, 0x50, 0xf0, 0x68, + 0x5b, 0xfa, 0x32, 0xdc, 0x0a, 0xf6, 0x10, 0xea, 0xa0, 0x7c, 0xec, 0x58, 0x30, 0x19, 0x86, 0x1f, + }; + + // echo -n -e '\x16\x3b\x8d\xa6\x4d\xa3\x94\x8f\x8f\xb8\x1f\x66\x81\xeb\xb3\xab\xbe\xac\x29\xca\xd3\x2b\x9a\x10\xba\xf4\x72\x7b\x09\x70\xa8\x38' | openssl enc -e -aes-256-ecb -K 3E6ED3693EC296CA9A20563A6B50F0685BFA32DC0AF610EAA07CEC583019861F -nopad | hd + var expected = new byte[] + { + 0xb3, 0x37, 0x5d, 0x78, 0xf5, 0x99, 0x69, 0xad, 0x7e, 0xf9, 0x0f, 0xb7, 0x00, 0x8b, 0x99, 0x0f, + 0x59, 0x0b, 0x9c, 0x7a, 0xf2, 0xb6, 0x34, 0x0d, 0xc9, 0xdd, 0x15, 0x6e, 0x75, 0xe7, 0xc6, 0x82, + }; + + var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_ECB_256_Length64() + { + var input = new byte[] + { + 0x03, 0x09, 0x1f, 0x0e, 0x3e, 0xcb, 0x2e, 0x47, 0x5e, 0xe9, 0xc8, 0xc2, 0xd5, 0x3e, 0x9a, 0x80, + 0x9a, 0x37, 0x2a, 0x85, 0x28, 0xdd, 0x51, 0x11, 0x8d, 0x36, 0xc6, 0xab, 0xc6, 0x5c, 0x14, 0x41, + 0xd7, 0x82, 0x55, 0x26, 0xf9, 0x77, 0xe0, 0x44, 0xb7, 0xe0, 0xb4, 0x2d, 0x80, 0xaa, 0x26, 0xd7, + 0xc4, 0xaf, 0x19, 0x9e, 0x34, 0x20, 0x41, 0x25, 0xb8, 0x0d, 0x81, 0x08, 0x05, 0x82, 0x81, 0x01, + }; + var key = new byte[] + { + 0xd4, 0x87, 0xea, 0x53, 0xe8, 0x73, 0x87, 0x22, 0x56, 0xe6, 0xcd, 0x47, 0x29, 0x23, 0x91, 0xe3, + 0x0f, 0xee, 0xe7, 0x16, 0x43, 0x76, 0x0c, 0xb7, 0x41, 0x2f, 0x6e, 0xeb, 0xf6, 0xd8, 0x3e, 0x35, + }; + + // echo -n -e '\x03\x09\x1f\x0e\x3e\xcb\x2e\x47\x5e\xe9\xc8\xc2\xd5\x3e\x9a\x80\x9a\x37\x2a\x85\x28\xdd\x51\x11\x8d\x36\xc6\xab\xc6\x5c\x14\x41\xd7\x82\x55\x26\xf9\x77\xe0\x44\xb7\xe0\xb4\x2d\x80\xaa\x26\xd7\xc4\xaf\x19\x9e\x34\x20\x41\x25\xb8\x0d\x81\x08\x05\x82\x81\x01' | openssl enc -e -aes-256-ecb -K D487EA53E873872256E6CD47292391E30FEEE71643760CB7412F6EEBF6D83E35 -nopad | hd + var expected = new byte[] + { + 0xe1, 0x47, 0xed, 0x16, 0x2d, 0xce, 0x7a, 0xd9, 0x3f, 0x66, 0xa3, 0x53, 0x0d, 0x64, 0x55, 0xb7, + 0x4e, 0xd7, 0x40, 0xcc, 0x71, 0x65, 0xc0, 0xc5, 0x69, 0xb4, 0x16, 0x02, 0x15, 0x44, 0x8b, 0x9a, + 0x06, 0x36, 0x7b, 0x61, 0x48, 0x62, 0x76, 0xfb, 0x58, 0x3e, 0x08, 0x51, 0xf6, 0xf8, 0xfa, 0xd2, + 0x63, 0xd2, 0x7d, 0x7a, 0xfc, 0xdb, 0x11, 0x08, 0x70, 0x73, 0x61, 0xe0, 0xfb, 0x93, 0xa6, 0xf9, + }; + + var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CBC_128_Length16() + { + var input = new byte[] + { + 0x7c, 0x9e, 0xf8, 0x16, 0x9b, 0x6a, 0xbe, 0x5e, 0x7a, 0x33, 0x11, 0xb9, 0x04, 0x9b, 0x2c, 0x7d, + }; + var key = new byte[] + { + 0xa7, 0x98, 0xe7, 0x75, 0xca, 0x98, 0x23, 0x3c, 0x00, 0x96, 0xed, 0x4c, 0x2d, 0xbe, 0x64, 0x47, + }; + var iv = new byte[] + { + 0x32, 0xda, 0x6f, 0x58, 0xe0, 0x28, 0x99, 0xf5, 0xf5, 0xfa, 0x7e, 0x8c, 0xc1, 0x35, 0x4c, 0x8d, + }; + + // echo -n -e '\x7c\x9e\xf8\x16\x9b\x6a\xbe\x5e\x7a\x33\x11\xb9\x04\x9b\x2c\x7d' | openssl enc -e -aes-128-cbc -K A798E775CA98233C0096ED4C2DBE6447 -iv 32DA6F58E02899F5F5FA7E8CC1354C8D -nopad | hd + var expected = new byte[] + { + 0x49, 0x0e, 0xa9, 0x6f, 0x55, 0xb3, 0x57, 0xdf, 0x7c, 0x18, 0x77, 0x0c, 0xca, 0x46, 0x0d, 0x83, + }; + + var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CBC_128_Length32() + { + var input = new byte[] + { + 0xca, 0xcb, 0xa6, 0xb9, 0x12, 0x87, 0xca, 0xe3, 0x7a, 0xbb, 0x16, 0x04, 0x7c, 0x71, 0x30, 0xbc, + 0xce, 0xc9, 0x86, 0x2a, 0x2b, 0xd4, 0x9c, 0x7e, 0xfe, 0xf2, 0x80, 0xcf, 0x19, 0x96, 0x7b, 0xca, + }; + var key = new byte[] + { + 0x4a, 0x60, 0x82, 0x62, 0x17, 0xaa, 0x35, 0xab, 0x10, 0x8b, 0xdd, 0x25, 0x12, 0x95, 0x78, 0x83, + }; + var iv = new byte[] + { + 0xca, 0xc2, 0xbd, 0xf7, 0xae, 0x21, 0x62, 0xf5, 0x2e, 0x28, 0xbb, 0x1f, 0x06, 0xfa, 0xca, 0xe4, + }; + + // echo -n -e '\xca\xcb\xa6\xb9\x12\x87\xca\xe3\x7a\xbb\x16\x04\x7c\x71\x30\xbc\xce\xc9\x86\x2a\x2b\xd4\x9c\x7e\xfe\xf2\x80\xcf\x19\x96\x7b\xca' | openssl enc -e -aes-128-cbc -K 4A60826217AA35AB108BDD2512957883 -iv CAC2BDF7AE2162F52E28BB1F06FACAE4 -nopad | hd + var expected = new byte[] + { + 0x55, 0xf4, 0x06, 0x4c, 0xdf, 0x4e, 0xf0, 0x12, 0xce, 0x45, 0x53, 0xdd, 0x9e, 0x12, 0x62, 0x61, + 0x2d, 0x87, 0x42, 0x20, 0xf1, 0x0b, 0x78, 0x96, 0xd5, 0x7c, 0xeb, 0xa2, 0x7f, 0x4b, 0x5a, 0xff, + }; + + var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CBC_128_Length64() + { + var input = new byte[] + { + 0x3f, 0x4b, 0xb9, 0x1c, 0xef, 0xcd, 0xa4, 0x23, 0x94, 0xdb, 0x1a, 0x9f, 0xf7, 0x77, 0x6c, 0x69, + 0x79, 0xfc, 0x05, 0x57, 0xd9, 0x84, 0x1c, 0x29, 0xfe, 0x8c, 0x34, 0xef, 0xef, 0x15, 0xa4, 0x15, + 0xc1, 0xf9, 0xe5, 0xc6, 0xdb, 0x5c, 0x94, 0xfc, 0x1d, 0x99, 0x63, 0xd3, 0x06, 0xc2, 0xfe, 0xb7, + 0xbb, 0x51, 0xa6, 0x09, 0xf4, 0x72, 0x0a, 0xbb, 0x2f, 0x90, 0x1e, 0x62, 0x99, 0xb5, 0x34, 0x7e, + }; + var key = new byte[] + { + 0x36, 0x04, 0xde, 0xfd, 0x91, 0xa6, 0x8d, 0x1d, 0x68, 0x08, 0x39, 0x40, 0x21, 0x48, 0x22, 0x3c, + }; + var iv = new byte[] + { + 0x8e, 0x7d, 0x33, 0x9e, 0x6f, 0x9b, 0x21, 0x4f, 0xee, 0x2a, 0x96, 0x4a, 0x3e, 0x32, 0x63, 0x68, + }; + + // echo -n -e '\x3f\x4b\xb9\x1c\xef\xcd\xa4\x23\x94\xdb\x1a\x9f\xf7\x77\x6c\x69\x79\xfc\x05\x57\xd9\x84\x1c\x29\xfe\x8c\x34\xef\xef\x15\xa4\x15\xc1\xf9\xe5\xc6\xdb\x5c\x94\xfc\x1d\x99\x63\xd3\x06\xc2\xfe\xb7\xbb\x51\xa6\x09\xf4\x72\x0a\xbb\x2f\x90\x1e\x62\x99\xb5\x34\x7e' | openssl enc -e -aes-128-cbc -K 3604DEFD91A68D1D680839402148223C -iv 8E7D339E6F9B214FEE2A964A3E326368 -nopad | hd + var expected = new byte[] + { + 0x83, 0x0b, 0x95, 0x08, 0x9d, 0xef, 0xc4, 0x97, 0x9c, 0xcf, 0xd5, 0xd2, 0xa5, 0x1e, 0xbd, 0xda, + 0xb9, 0x22, 0xdd, 0xf9, 0x53, 0x73, 0x03, 0x82, 0x31, 0x83, 0x8a, 0x9f, 0x27, 0x45, 0xae, 0x5b, + 0x64, 0xd5, 0x0e, 0xc2, 0x47, 0xce, 0x2a, 0x40, 0x47, 0x12, 0x05, 0xde, 0x19, 0xbd, 0x23, 0x76, + 0x3d, 0x61, 0x9e, 0x0d, 0x54, 0x7f, 0xe1, 0xc4, 0x78, 0xf2, 0x04, 0x00, 0x68, 0xa9, 0x9b, 0x32, + }; + + var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CBC_192_Length16() + { + var input = new byte[] + { + 0x65, 0xe4, 0x9c, 0x01, 0xe4, 0x00, 0x26, 0x15, 0xc3, 0x88, 0xa1, 0xeb, 0x38, 0xca, 0x99, 0xe6, + }; + var key = new byte[] + { + 0x6e, 0xe2, 0xd4, 0x1c, 0x81, 0x96, 0x0f, 0x9b, 0xe3, 0x8e, 0x0f, 0x66, 0x0f, 0x43, 0xdf, 0x36, + 0xa5, 0xd1, 0xda, 0x3c, 0xac, 0x20, 0x57, 0x8d, + }; + var iv = new byte[] + { + 0x57, 0x1e, 0xda, 0xe6, 0xf9, 0x35, 0x16, 0x23, 0x91, 0xaf, 0xdb, 0x5c, 0x5e, 0x47, 0xe7, 0xcf, + }; + + // echo -n -e '\x65\xe4\x9c\x01\xe4\x00\x26\x15\xc3\x88\xa1\xeb\x38\xca\x99\xe6' | openssl enc -e -aes-192-cbc -K 6EE2D41C81960F9BE38E0F660F43DF36A5D1DA3CAC20578D -iv 571EDAE6F935162391AFDB5C5E47E7CF -nopad | hd + var expected = new byte[] + { + 0xe1, 0x2f, 0x71, 0xad, 0x59, 0xae, 0xa7, 0xe3, 0xd3, 0x23, 0x43, 0x81, 0x31, 0xc2, 0xe5, 0xd9, + }; + + var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CBC_192_Length32() + { + var input = new byte[] + { + 0xd5, 0x00, 0x1e, 0x55, 0xf1, 0xbf, 0x05, 0x80, 0xa9, 0x6a, 0x46, 0x67, 0xef, 0x5c, 0x3a, 0x4e, + 0x8a, 0x46, 0xc5, 0x63, 0xbb, 0x28, 0xa1, 0xae, 0x78, 0xeb, 0xd4, 0x5f, 0x67, 0x82, 0xd8, 0x5e, + }; + var key = new byte[] + { + 0xe9, 0x0b, 0x67, 0xab, 0x02, 0x02, 0x9b, 0x97, 0x18, 0x59, 0x3c, 0x8e, 0xee, 0xae, 0x33, 0x34, + 0x75, 0x8d, 0xd2, 0x17, 0x82, 0x84, 0x13, 0xac, + }; + var iv = new byte[] + { + 0x5f, 0x6f, 0xdc, 0x06, 0xea, 0xa5, 0x18, 0x27, 0x92, 0xe8, 0x7e, 0xe4, 0xf4, 0x8e, 0x4c, 0x87, + }; + + // echo -n -e '\xd5\x00\x1e\x55\xf1\xbf\x05\x80\xa9\x6a\x46\x67\xef\x5c\x3a\x4e\x8a\x46\xc5\x63\xbb\x28\xa1\xae\x78\xeb\xd4\x5f\x67\x82\xd8\x5e' | openssl enc -e -aes-192-cbc -K E90B67AB02029B9718593C8EEEAE3334758DD217828413AC -iv 5F6FDC06EAA5182792E87EE4F48E4C87 -nopad | hd + var expected = new byte[] + { + 0x21, 0x2c, 0x43, 0x64, 0x48, 0x20, 0xe9, 0xfd, 0xe9, 0x15, 0x27, 0x4d, 0x35, 0x8f, 0xf8, 0x42, + 0x07, 0xf2, 0x98, 0x41, 0xbb, 0x58, 0x3d, 0xe5, 0xcf, 0x56, 0xf5, 0x4b, 0x33, 0xf7, 0xa0, 0x9a, + }; + + var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CBC_192_Length64() + { + var input = new byte[] + { + 0xab, 0x2d, 0x4a, 0x61, 0xeb, 0x12, 0xc0, 0xca, 0xb7, 0xa0, 0xea, 0xda, 0xb0, 0xc0, 0xdb, 0x65, + 0xf8, 0xbb, 0x4c, 0x92, 0x26, 0x95, 0xac, 0x72, 0x41, 0x15, 0xfc, 0x06, 0x30, 0x4f, 0x3f, 0xe6, + 0x40, 0x4a, 0x6b, 0x54, 0x39, 0xb1, 0xc0, 0x4c, 0xaf, 0x11, 0x4e, 0x4a, 0xbb, 0x3e, 0x76, 0xd2, + 0x0c, 0x18, 0xeb, 0x39, 0x42, 0xb9, 0x61, 0x15, 0x81, 0xd7, 0x20, 0xd6, 0x16, 0xba, 0x9a, 0x67, + }; + var key = new byte[] + { + 0x60, 0x04, 0x9a, 0x66, 0x55, 0x87, 0x2c, 0x46, 0xfa, 0xff, 0xe3, 0x14, 0x47, 0x62, 0xb7, 0x03, + 0x9f, 0x29, 0xf9, 0x18, 0x63, 0x06, 0xa3, 0x86, + }; + var iv = new byte[] + { + 0xe9, 0x55, 0xd3, 0x62, 0x90, 0xea, 0x36, 0xf4, 0x77, 0xe6, 0xea, 0xb7, 0xa4, 0x10, 0x7c, 0x85, + }; + + // echo -n -e '\xab\x2d\x4a\x61\xeb\x12\xc0\xca\xb7\xa0\xea\xda\xb0\xc0\xdb\x65\xf8\xbb\x4c\x92\x26\x95\xac\x72\x41\x15\xfc\x06\x30\x4f\x3f\xe6\x40\x4a\x6b\x54\x39\xb1\xc0\x4c\xaf\x11\x4e\x4a\xbb\x3e\x76\xd2\x0c\x18\xeb\x39\x42\xb9\x61\x15\x81\xd7\x20\xd6\x16\xba\x9a\x67' | openssl enc -e -aes-192-cbc -K 60049A6655872C46FAFFE3144762B7039F29F9186306A386 -iv E955D36290EA36F477E6EAB7A4107C85 -nopad | hd + var expected = new byte[] + { + 0xae, 0x0d, 0x32, 0x1a, 0x60, 0x91, 0x3a, 0xf8, 0x50, 0x63, 0x78, 0xa9, 0x04, 0x88, 0x1a, 0xd0, + 0x34, 0x6b, 0xc8, 0xdf, 0xf2, 0xb6, 0xa5, 0x4a, 0x9f, 0xf1, 0x11, 0x98, 0x13, 0x5f, 0x1c, 0x87, + 0x7f, 0x91, 0x8f, 0xed, 0xa9, 0x88, 0x72, 0x0c, 0x9c, 0x55, 0x13, 0x87, 0x34, 0x17, 0x51, 0xd3, + 0xda, 0xba, 0xde, 0xb2, 0x7d, 0xbc, 0x71, 0xf8, 0x9b, 0xaa, 0x93, 0x52, 0xf4, 0x26, 0x3c, 0x6f, + }; + + var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CBC_256_Length16() + { + var input = new byte[] + { + 0xec, 0xa5, 0x3e, 0x43, 0xd6, 0x4d, 0xce, 0x1f, 0x1f, 0x1d, 0x37, 0xec, 0xc0, 0x82, 0x03, 0x5a, + }; + var key = new byte[] + { + 0x60, 0x13, 0x7c, 0xff, 0xb3, 0xc9, 0xb5, 0x10, 0xc9, 0xee, 0x9c, 0x60, 0x77, 0x00, 0x5f, 0x8e, + 0xac, 0x73, 0x2b, 0xbe, 0xc7, 0x60, 0xb0, 0x9c, 0x87, 0xb4, 0x42, 0x73, 0xb3, 0x49, 0x34, 0xf5, + }; + var iv = new byte[] + { + 0xe2, 0x90, 0x56, 0x90, 0x93, 0x7d, 0xd2, 0x22, 0xef, 0x2d, 0x7a, 0xe7, 0xb0, 0x6e, 0xa7, 0x1f, + }; + + // echo -n -e '\xec\xa5\x3e\x43\xd6\x4d\xce\x1f\x1f\x1d\x37\xec\xc0\x82\x03\x5a' | openssl enc -e -aes-256-cbc -K 60137CFFB3C9B510C9EE9C6077005F8EAC732BBEC760B09C87B44273B34934F5 -iv E2905690937DD222EF2D7AE7B06EA71F -nopad | hd + var expected = new byte[] + { + 0xe7, 0xa5, 0x53, 0xd7, 0x28, 0x4c, 0x16, 0x4e, 0xfc, 0xa2, 0xa8, 0x86, 0xfc, 0xcb, 0x71, 0x61, + }; + + var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CBC_256_Length32() + { + var input = new byte[] + { + 0xbe, 0xa8, 0x3f, 0x4d, 0x56, 0x45, 0x92, 0x00, 0x63, 0xe0, 0x78, 0xfe, 0x87, 0x42, 0x5d, 0x7f, + 0xba, 0xa7, 0x7d, 0xe7, 0xaa, 0xce, 0xfb, 0x2f, 0xa1, 0x09, 0xcf, 0x99, 0xe5, 0xc8, 0xec, 0x18, + }; + var key = new byte[] + { + 0x0d, 0x22, 0xb4, 0x0a, 0x09, 0xe6, 0x9e, 0x9d, 0xfd, 0x55, 0x2d, 0xb2, 0x05, 0xd3, 0x9a, 0xad, + 0xd0, 0xfa, 0x2d, 0x08, 0xf0, 0xbf, 0x75, 0xf0, 0xac, 0x10, 0xab, 0x4c, 0x76, 0xf8, 0x1a, 0x9b, + }; + var iv = new byte[] + { + 0xf4, 0x5f, 0xf1, 0x64, 0x8d, 0x52, 0x75, 0xd3, 0x08, 0xe0, 0xea, 0x54, 0xa1, 0x48, 0x29, 0xcd, + }; + + // echo -n -e '\xbe\xa8\x3f\x4d\x56\x45\x92\x00\x63\xe0\x78\xfe\x87\x42\x5d\x7f\xba\xa7\x7d\xe7\xaa\xce\xfb\x2f\xa1\x09\xcf\x99\xe5\xc8\xec\x18' | openssl enc -e -aes-256-cbc -K 0D22B40A09E69E9DFD552DB205D39AADD0FA2D08F0BF75F0AC10AB4C76F81A9B -iv F45FF1648D5275D308E0EA54A14829CD -nopad | hd + var expected = new byte[] + { + 0x4f, 0x29, 0xa7, 0xd7, 0xbc, 0x51, 0x95, 0xc5, 0x4c, 0x79, 0x1c, 0xde, 0xad, 0xc8, 0xe0, 0xfd, + 0x6a, 0xfb, 0x4a, 0x8b, 0xc8, 0x25, 0x87, 0x5c, 0x9b, 0x47, 0xf5, 0x3f, 0x42, 0xf5, 0xc6, 0x08, + }; + + var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CBC_256_Length64() + { + var input = new byte[] + { + 0x6e, 0x21, 0xc9, 0xeb, 0x9a, 0xe3, 0x28, 0x4e, 0xad, 0xc4, 0x5e, 0xf9, 0x3a, 0x52, 0x26, 0x04, + 0x3b, 0x91, 0xbd, 0xa6, 0xe2, 0x36, 0x1f, 0x7d, 0x85, 0x59, 0xff, 0x0f, 0xd5, 0x21, 0x4e, 0x63, + 0xe7, 0xde, 0xdd, 0x54, 0x2f, 0x2f, 0x00, 0x11, 0x36, 0xa3, 0xb7, 0xc8, 0xf4, 0x7c, 0x98, 0xb6, + 0xb9, 0xe5, 0x18, 0x0f, 0x8b, 0x82, 0xeb, 0x38, 0x02, 0x4b, 0x65, 0x40, 0xe3, 0x19, 0x78, 0x8b, + }; + var key = new byte[] + { + 0x76, 0xfa, 0x12, 0x5c, 0x74, 0xd2, 0xd5, 0x0c, 0x90, 0xac, 0x70, 0x3e, 0x7e, 0x57, 0x88, 0x09, + 0xc1, 0x48, 0x55, 0xf0, 0x08, 0x3f, 0xd8, 0x64, 0xf2, 0xa4, 0x52, 0xe3, 0xc9, 0xc0, 0x2d, 0x1d, + }; + var iv = new byte[] + { + 0x2a, 0x2b, 0x52, 0xf9, 0x69, 0x3c, 0x42, 0xe7, 0x0f, 0x0c, 0x7f, 0xde, 0x12, 0xad, 0xb9, 0xab, + }; + + // echo -n -e '\x6e\x21\xc9\xeb\x9a\xe3\x28\x4e\xad\xc4\x5e\xf9\x3a\x52\x26\x04\x3b\x91\xbd\xa6\xe2\x36\x1f\x7d\x85\x59\xff\x0f\xd5\x21\x4e\x63\xe7\xde\xdd\x54\x2f\x2f\x00\x11\x36\xa3\xb7\xc8\xf4\x7c\x98\xb6\xb9\xe5\x18\x0f\x8b\x82\xeb\x38\x02\x4b\x65\x40\xe3\x19\x78\x8b' | openssl enc -e -aes-256-cbc -K 76FA125C74D2D50C90AC703E7E578809C14855F0083FD864F2A452E3C9C02D1D -iv 2A2B52F9693C42E70F0C7FDE12ADB9AB -nopad | hd + var expected = new byte[] + { + 0x04, 0xf0, 0x4c, 0x9b, 0xfb, 0xa0, 0x6e, 0xaa, 0xdf, 0x38, 0xf3, 0x9a, 0xc6, 0x3c, 0x70, 0x82, + 0xda, 0xa3, 0x08, 0x19, 0x6f, 0xf8, 0xb9, 0xd8, 0xc4, 0x92, 0x45, 0x97, 0x05, 0x3e, 0xc5, 0xea, + 0x54, 0x3e, 0xb6, 0x23, 0x0a, 0x82, 0x7d, 0x3f, 0xbf, 0x88, 0xd1, 0x05, 0x0d, 0x10, 0x10, 0x59, + 0x08, 0x19, 0x66, 0x47, 0xe7, 0xd9, 0x1d, 0x1c, 0x42, 0xdc, 0x97, 0x9c, 0xf0, 0x9a, 0x14, 0x34, + }; + + var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CFB_128_Length16() + { + var input = new byte[] + { + 0xc2, 0x5c, 0x7f, 0x9b, 0xc3, 0x88, 0x83, 0x37, 0x22, 0xad, 0x6a, 0xcf, 0x7f, 0xf1, 0x42, 0xd0, + }; + var key = new byte[] + { + 0x7f, 0x53, 0x13, 0x53, 0x04, 0x8f, 0x9f, 0x84, 0x06, 0x6e, 0xe0, 0xfc, 0xbf, 0xfa, 0x51, 0x44, + }; + var iv = new byte[] + { + 0xea, 0xa7, 0x20, 0x6c, 0x40, 0x92, 0x59, 0xa2, 0xa8, 0x1b, 0xd7, 0xbc, 0xd1, 0x72, 0x67, 0x1d, + }; + + // echo -n -e '\xc2\x5c\x7f\x9b\xc3\x88\x83\x37\x22\xad\x6a\xcf\x7f\xf1\x42\xd0' | openssl enc -e -aes-128-cfb -K 7F531353048F9F84066EE0FCBFFA5144 -iv EAA7206C409259A2A81BD7BCD172671D -nopad | hd + var expected = new byte[] + { + 0x76, 0xd2, 0x2b, 0x69, 0xa6, 0xdf, 0x3b, 0x4d, 0x4a, 0x52, 0x8a, 0x7a, 0x54, 0x9d, 0xbe, 0x55, + }; + + var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CFB_128_Length32() + { + var input = new byte[] + { + 0xc9, 0xae, 0x5e, 0xbf, 0x99, 0x66, 0xa6, 0x33, 0xbd, 0xfa, 0x94, 0x55, 0xa8, 0x87, 0x77, 0x28, + 0x5b, 0x25, 0xe4, 0xd8, 0xd1, 0xd6, 0x8f, 0xed, 0xf9, 0x71, 0xab, 0xe8, 0xb7, 0xe2, 0xb3, 0x94, + }; + var key = new byte[] + { + 0x06, 0xc2, 0x32, 0x11, 0x9b, 0x92, 0xab, 0x84, 0x00, 0xec, 0xae, 0x46, 0xfe, 0x04, 0xf9, 0x21, + }; + var iv = new byte[] + { + 0xa4, 0xaf, 0x60, 0xab, 0x8d, 0x8e, 0x4c, 0xf3, 0x1f, 0x71, 0xc6, 0x27, 0xbb, 0xbe, 0x7c, 0xda, + }; + + // echo -n -e '\xc9\xae\x5e\xbf\x99\x66\xa6\x33\xbd\xfa\x94\x55\xa8\x87\x77\x28\x5b\x25\xe4\xd8\xd1\xd6\x8f\xed\xf9\x71\xab\xe8\xb7\xe2\xb3\x94' | openssl enc -e -aes-128-cfb -K 06C232119B92AB8400ECAE46FE04F921 -iv A4AF60AB8D8E4CF31F71C627BBBE7CDA -nopad | hd + var expected = new byte[] + { + 0x62, 0x67, 0x2b, 0xa7, 0x0b, 0xd1, 0xbc, 0x2f, 0x55, 0xaa, 0x71, 0x53, 0x7a, 0x68, 0xe5, 0x46, + 0x18, 0xc5, 0xf7, 0x41, 0x78, 0x5f, 0x38, 0x6b, 0x4d, 0x04, 0x00, 0x3b, 0x61, 0x8c, 0xaf, 0xe7, + }; + + var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CFB_128_Length64() + { + var input = new byte[] + { + 0x47, 0xff, 0x4e, 0xe5, 0x54, 0x65, 0x8d, 0xc9, 0x7a, 0x60, 0xd7, 0xe4, 0x27, 0x49, 0xef, 0xf4, + 0x78, 0x89, 0x44, 0x07, 0x82, 0x07, 0x06, 0x77, 0x76, 0x3e, 0xf1, 0x29, 0xcc, 0x84, 0xc8, 0x42, + 0x70, 0xd3, 0xff, 0xfe, 0xb6, 0x13, 0xcc, 0x3e, 0x22, 0x96, 0x31, 0x2d, 0xb6, 0x67, 0xcb, 0xd6, + 0x82, 0xd1, 0xaf, 0x31, 0x79, 0x74, 0x58, 0x3f, 0xf9, 0xd6, 0x6f, 0x16, 0x73, 0x63, 0xfc, 0xf6, + }; + var key = new byte[] + { + 0x97, 0x95, 0x73, 0x54, 0x4a, 0xf0, 0x3d, 0x64, 0xbd, 0x05, 0xe5, 0xeb, 0xd5, 0xd8, 0xc0, 0x0e, + }; + var iv = new byte[] + { + 0x73, 0x1b, 0xa7, 0xfa, 0xd4, 0x97, 0xc8, 0xfb, 0x7b, 0xbf, 0x05, 0xe0, 0xa4, 0xb6, 0xca, 0xbf, + }; + + // echo -n -e '\x47\xff\x4e\xe5\x54\x65\x8d\xc9\x7a\x60\xd7\xe4\x27\x49\xef\xf4\x78\x89\x44\x07\x82\x07\x06\x77\x76\x3e\xf1\x29\xcc\x84\xc8\x42\x70\xd3\xff\xfe\xb6\x13\xcc\x3e\x22\x96\x31\x2d\xb6\x67\xcb\xd6\x82\xd1\xaf\x31\x79\x74\x58\x3f\xf9\xd6\x6f\x16\x73\x63\xfc\xf6' | openssl enc -e -aes-128-cfb -K 979573544AF03D64BD05E5EBD5D8C00E -iv 731BA7FAD497C8FB7BBF05E0A4B6CABF -nopad | hd + var expected = new byte[] + { + 0x42, 0xd5, 0xe9, 0xb7, 0x92, 0xdd, 0x1f, 0xaa, 0x7c, 0xf2, 0x41, 0x96, 0x6d, 0xd5, 0xb1, 0x65, + 0x93, 0xcd, 0x0e, 0xc5, 0x49, 0x7c, 0x24, 0xca, 0xb2, 0xe6, 0x7d, 0xbc, 0x78, 0xf1, 0x40, 0x75, + 0x44, 0xe6, 0xce, 0x49, 0xe6, 0x8f, 0x35, 0x27, 0x26, 0x21, 0x04, 0xee, 0x52, 0x44, 0x40, 0x80, + 0xf7, 0x49, 0xbc, 0xbf, 0xcb, 0x5c, 0xfa, 0x12, 0xcb, 0xcc, 0x38, 0x71, 0x68, 0xd6, 0xe9, 0x64, + }; + + var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CFB_192_Length16() + { + var input = new byte[] + { + 0x9a, 0x3b, 0x96, 0x21, 0xf3, 0x77, 0x8b, 0x91, 0x94, 0x4a, 0x73, 0x74, 0x8f, 0x6c, 0x6a, 0x20, + }; + var key = new byte[] + { + 0x15, 0x61, 0xa3, 0x57, 0xbc, 0x02, 0x21, 0x00, 0xcc, 0x78, 0xd9, 0x8a, 0xeb, 0x5d, 0xc0, 0x07, + 0x3a, 0x26, 0x51, 0x9a, 0x42, 0x9f, 0x1a, 0xfb, + }; + var iv = new byte[] + { + 0x90, 0x15, 0x66, 0x89, 0x23, 0x54, 0x6c, 0x0f, 0x55, 0xe4, 0xca, 0x43, 0x12, 0x72, 0x02, 0x98, + }; + + // echo -n -e '\x9a\x3b\x96\x21\xf3\x77\x8b\x91\x94\x4a\x73\x74\x8f\x6c\x6a\x20' | openssl enc -e -aes-192-cfb -K 1561A357BC022100CC78D98AEB5DC0073A26519A429F1AFB -iv 9015668923546C0F55E4CA4312720298 -nopad | hd + var expected = new byte[] + { + 0x4f, 0x9b, 0xdf, 0x72, 0x2d, 0x10, 0x1b, 0xb9, 0xa1, 0xe1, 0x06, 0xba, 0xbc, 0xc5, 0xfe, 0x13, + }; + + var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CFB_192_Length32() + { + var input = new byte[] + { + 0x1a, 0x96, 0x54, 0x7b, 0x9e, 0x01, 0xa6, 0x36, 0x8a, 0x6c, 0x3a, 0x69, 0x1a, 0xcf, 0xdd, 0x76, + 0x46, 0xa7, 0xc7, 0xa7, 0x9b, 0x97, 0xdc, 0x78, 0x0b, 0xca, 0x35, 0x06, 0x93, 0x7c, 0xf4, 0xc7, + }; + var key = new byte[] + { + 0x23, 0xb9, 0x7f, 0xac, 0x4a, 0x9e, 0x5d, 0x8e, 0x6f, 0x2f, 0xff, 0xb6, 0x19, 0x03, 0xf4, 0x85, + 0x07, 0x53, 0xfc, 0x6b, 0xab, 0x5b, 0xfc, 0x83, + }; + var iv = new byte[] + { + 0xb9, 0xdc, 0x70, 0xd4, 0xcb, 0x9f, 0xa3, 0x0d, 0x77, 0x72, 0x45, 0x61, 0x50, 0x31, 0x2c, 0xa8, + }; + + // echo -n -e '\x1a\x96\x54\x7b\x9e\x01\xa6\x36\x8a\x6c\x3a\x69\x1a\xcf\xdd\x76\x46\xa7\xc7\xa7\x9b\x97\xdc\x78\x0b\xca\x35\x06\x93\x7c\xf4\xc7' | openssl enc -e -aes-192-cfb -K 23B97FAC4A9E5D8E6F2FFFB61903F4850753FC6BAB5BFC83 -iv B9DC70D4CB9FA30D7772456150312CA8 -nopad | hd + var expected = new byte[] + { + 0xc0, 0xdf, 0x63, 0xb5, 0x17, 0x40, 0xd4, 0xa7, 0x73, 0x40, 0xc5, 0x21, 0xa5, 0xea, 0x63, 0xdf, + 0x72, 0xcf, 0x57, 0x7f, 0xf9, 0x5d, 0xfe, 0xb1, 0x36, 0x9a, 0x1d, 0x02, 0x0d, 0x4b, 0x8f, 0x35, + }; + + var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CFB_192_Length64() + { + var input = new byte[] + { + 0x4a, 0x38, 0x37, 0x6b, 0x98, 0x26, 0x5e, 0x08, 0xd5, 0xb0, 0xff, 0x3f, 0x80, 0x88, 0x1c, 0xc8, + 0xbc, 0xfc, 0xf3, 0x6d, 0x2d, 0x89, 0xc3, 0xcf, 0x8c, 0xf1, 0x3e, 0xa7, 0xbe, 0x93, 0x34, 0xd6, + 0x27, 0x53, 0x21, 0x72, 0x23, 0x90, 0xeb, 0x93, 0x7d, 0x68, 0xfe, 0x1b, 0xa0, 0x63, 0x8d, 0xee, + 0x56, 0x7c, 0xa4, 0x54, 0x3d, 0xbe, 0x7a, 0xc0, 0x75, 0x68, 0xdf, 0xa6, 0xe7, 0xb7, 0x49, 0x42, + }; + var key = new byte[] + { + 0x7b, 0x28, 0x18, 0x2d, 0x67, 0xaa, 0xa5, 0x2c, 0x11, 0x60, 0xf0, 0xc5, 0x8a, 0xa7, 0x2f, 0x28, + 0x64, 0x4f, 0x50, 0x41, 0xee, 0xe0, 0x98, 0x68, + }; + var iv = new byte[] + { + 0xd9, 0x60, 0xfc, 0xbb, 0xb1, 0x44, 0xab, 0xc6, 0x1e, 0xbb, 0xa0, 0x77, 0x4b, 0x5f, 0x87, 0xac, + }; + + // echo -n -e '\x4a\x38\x37\x6b\x98\x26\x5e\x08\xd5\xb0\xff\x3f\x80\x88\x1c\xc8\xbc\xfc\xf3\x6d\x2d\x89\xc3\xcf\x8c\xf1\x3e\xa7\xbe\x93\x34\xd6\x27\x53\x21\x72\x23\x90\xeb\x93\x7d\x68\xfe\x1b\xa0\x63\x8d\xee\x56\x7c\xa4\x54\x3d\xbe\x7a\xc0\x75\x68\xdf\xa6\xe7\xb7\x49\x42' | openssl enc -e -aes-192-cfb -K 7B28182D67AAA52C1160F0C58AA72F28644F5041EEE09868 -iv D960FCBBB144ABC61EBBA0774B5F87AC -nopad | hd + var expected = new byte[] + { + 0x02, 0x43, 0x43, 0x74, 0xdd, 0xa0, 0x4a, 0x13, 0x19, 0xbd, 0x4b, 0x88, 0xc0, 0xe4, 0x67, 0xe8, + 0xae, 0xfe, 0xfe, 0x94, 0x44, 0x8f, 0x16, 0x7d, 0x57, 0x5c, 0xc3, 0x50, 0x5f, 0xcf, 0xd3, 0x41, + 0xec, 0x58, 0x90, 0x0d, 0xe0, 0x32, 0xb6, 0xa4, 0xfd, 0x6f, 0xac, 0xdb, 0x40, 0x63, 0xe9, 0x28, + 0x69, 0x90, 0x2a, 0xf9, 0xf4, 0xe8, 0xcc, 0xa5, 0x2b, 0xdd, 0x9c, 0xbc, 0x44, 0xcd, 0x1e, 0x5b, + }; + + var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CFB_256_Length16() + { + var input = new byte[] + { + 0xd7, 0x78, 0x42, 0xdd, 0xce, 0xb5, 0x36, 0xcd, 0x38, 0xb7, 0x42, 0x97, 0x66, 0x08, 0x53, 0x9a, + }; + var key = new byte[] + { + 0x90, 0xaf, 0x54, 0x06, 0xad, 0xe9, 0x7a, 0xcc, 0xb4, 0x29, 0xa7, 0xce, 0x07, 0xb7, 0xdc, 0x04, + 0xc8, 0xa4, 0x69, 0x76, 0x9e, 0xbb, 0x9a, 0x24, 0x2a, 0x2e, 0x82, 0xfa, 0x01, 0x14, 0x5f, 0x16, + }; + var iv = new byte[] + { + 0x67, 0x06, 0xe7, 0x9c, 0x0b, 0x80, 0xfe, 0xed, 0xfd, 0x75, 0x28, 0xa4, 0x0d, 0x67, 0xc6, 0x80, + }; + + // echo -n -e '\xd7\x78\x42\xdd\xce\xb5\x36\xcd\x38\xb7\x42\x97\x66\x08\x53\x9a' | openssl enc -e -aes-256-cfb -K 90AF5406ADE97ACCB429A7CE07B7DC04C8A469769EBB9A242A2E82FA01145F16 -iv 6706E79C0B80FEEDFD7528A40D67C680 -nopad | hd + var expected = new byte[] + { + 0xf0, 0xfa, 0x95, 0x5c, 0xfc, 0x3f, 0xbe, 0xe5, 0x4b, 0x55, 0x57, 0xad, 0x93, 0x63, 0x36, 0x07, + }; + + var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CFB_256_Length32() + { + var input = new byte[] + { + 0xda, 0x3e, 0xcf, 0xc2, 0x9e, 0xdd, 0xfc, 0xd4, 0x15, 0x30, 0xdc, 0x7f, 0x67, 0x80, 0xcb, 0xa0, + 0xca, 0x91, 0x66, 0x01, 0xd0, 0x40, 0xf8, 0x47, 0xa5, 0x7b, 0x78, 0x28, 0x93, 0xf5, 0x16, 0xc2, + }; + var key = new byte[] + { + 0x68, 0x01, 0x20, 0xc3, 0x45, 0x9c, 0x77, 0x8a, 0x09, 0x12, 0x86, 0xdb, 0xa3, 0x7f, 0x86, 0x7d, + 0xaa, 0x88, 0xd9, 0x7c, 0x01, 0xc4, 0xb0, 0x99, 0x45, 0x87, 0x1c, 0x23, 0x65, 0xd3, 0x41, 0x1f, + }; + var iv = new byte[] + { + 0x1a, 0x1a, 0x16, 0x65, 0x60, 0x07, 0x5a, 0x2e, 0x19, 0xdc, 0xf7, 0xbe, 0xb9, 0x1d, 0xa4, 0x26, + }; + + // echo -n -e '\xda\x3e\xcf\xc2\x9e\xdd\xfc\xd4\x15\x30\xdc\x7f\x67\x80\xcb\xa0\xca\x91\x66\x01\xd0\x40\xf8\x47\xa5\x7b\x78\x28\x93\xf5\x16\xc2' | openssl enc -e -aes-256-cfb -K 680120C3459C778A091286DBA37F867DAA88D97C01C4B09945871C2365D3411F -iv 1A1A166560075A2E19DCF7BEB91DA426 -nopad | hd + var expected = new byte[] + { + 0x94, 0x65, 0xf5, 0x19, 0xe9, 0xc8, 0xc6, 0xd0, 0x0d, 0x81, 0x4e, 0x13, 0xb8, 0x37, 0x2b, 0x92, + 0xc2, 0xc1, 0x54, 0x9c, 0xfd, 0xf9, 0x43, 0xd0, 0xdc, 0xa7, 0x20, 0x68, 0x3e, 0xc3, 0x8f, 0x3c, + }; + + var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CFB_256_Length64() + { + var input = new byte[] + { + 0xf5, 0xfa, 0x7d, 0x0a, 0x1c, 0x99, 0xc0, 0xa4, 0x51, 0x86, 0x7e, 0xbe, 0x7f, 0x54, 0x24, 0x35, + 0xd1, 0x67, 0xc1, 0x89, 0x68, 0x20, 0x1d, 0xa2, 0x2d, 0xab, 0x63, 0x25, 0xcc, 0xf1, 0xe0, 0x27, + 0xe3, 0xf6, 0x2d, 0x6a, 0x56, 0x36, 0x03, 0x81, 0x59, 0x72, 0x13, 0xd9, 0x89, 0x9c, 0xae, 0xc5, + 0xb7, 0xc1, 0xec, 0x52, 0x5c, 0x1a, 0xbd, 0xd4, 0xdd, 0xda, 0xdd, 0x70, 0x35, 0x9b, 0xd7, 0x5f, + }; + var key = new byte[] + { + 0xa6, 0x56, 0xda, 0x89, 0x26, 0xba, 0xdf, 0x9a, 0x63, 0x3f, 0x2f, 0xf6, 0x0c, 0x43, 0x19, 0x90, + 0xfc, 0x9d, 0x6d, 0x0a, 0x04, 0x8d, 0xcb, 0xc8, 0x38, 0x58, 0x8d, 0x7b, 0x59, 0x92, 0x4b, 0xbe, + }; + var iv = new byte[] + { + 0x9a, 0xb4, 0x33, 0x33, 0xc2, 0x25, 0x9f, 0xfd, 0xe2, 0x52, 0xee, 0x1c, 0xeb, 0xc6, 0xc7, 0x99, + }; + + // echo -n -e '\xf5\xfa\x7d\x0a\x1c\x99\xc0\xa4\x51\x86\x7e\xbe\x7f\x54\x24\x35\xd1\x67\xc1\x89\x68\x20\x1d\xa2\x2d\xab\x63\x25\xcc\xf1\xe0\x27\xe3\xf6\x2d\x6a\x56\x36\x03\x81\x59\x72\x13\xd9\x89\x9c\xae\xc5\xb7\xc1\xec\x52\x5c\x1a\xbd\xd4\xdd\xda\xdd\x70\x35\x9b\xd7\x5f' | openssl enc -e -aes-256-cfb -K A656DA8926BADF9A633F2FF60C431990FC9D6D0A048DCBC838588D7B59924BBE -iv 9AB43333C2259FFDE252EE1CEBC6C799 -nopad | hd + var expected = new byte[] + { + 0xab, 0xe4, 0xf7, 0xcf, 0x22, 0xa5, 0x47, 0x03, 0xf6, 0xca, 0xdc, 0xbf, 0xee, 0x80, 0x6b, 0x91, + 0x8f, 0xa6, 0xf3, 0xfe, 0x77, 0xc8, 0x14, 0xe0, 0xaf, 0x95, 0x6e, 0xf8, 0xc0, 0x83, 0x62, 0x53, + 0xa1, 0xd6, 0x8a, 0xc4, 0xbc, 0xe1, 0xca, 0x0a, 0xaa, 0xa8, 0xea, 0x4f, 0x7c, 0xd2, 0xd2, 0xc4, + 0xf6, 0xd4, 0x06, 0xef, 0x04, 0xf1, 0xe5, 0x53, 0x54, 0xd5, 0x80, 0xc2, 0x96, 0x6b, 0xc7, 0x07, + }; + + var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CTR_128_Length16() + { + var input = new byte[] + { + 0xc1, 0x4d, 0x74, 0x98, 0x2e, 0xcc, 0x5a, 0x18, 0x8a, 0x12, 0x50, 0xcd, 0x2c, 0x63, 0x41, 0xd0, + }; + var key = new byte[] + { + 0xf4, 0x71, 0x5b, 0x58, 0x0f, 0xe5, 0xce, 0xd7, 0xfd, 0x70, 0x28, 0xb2, 0x9e, 0xae, 0xdc, 0x71, + }; + var iv = new byte[] + { + 0x91, 0xf3, 0xba, 0x0b, 0x1e, 0xb2, 0x8f, 0xce, 0x59, 0x1b, 0xa8, 0xaf, 0xd4, 0xd1, 0xd0, 0x7e, + }; + + // echo -n -e '\xc1\x4d\x74\x98\x2e\xcc\x5a\x18\x8a\x12\x50\xcd\x2c\x63\x41\xd0' | openssl enc -e -aes-128-ctr -K F4715B580FE5CED7FD7028B29EAEDC71 -iv 91F3BA0B1EB28FCE591BA8AFD4D1D07E -nopad | hd + var expected = new byte[] + { + 0xe4, 0x03, 0x8f, 0x2a, 0xdd, 0x9d, 0xf6, 0x87, 0xf6, 0x29, 0xee, 0x27, 0x4c, 0xf3, 0xba, 0x82, + }; + + var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CTR_128_Length32() + { + var input = new byte[] + { + 0x11, 0x1e, 0x28, 0x7a, 0x6a, 0x6f, 0x89, 0xdb, 0x7f, 0x9d, 0x9a, 0xbd, 0xa3, 0xa8, 0x79, 0xdc, + 0x36, 0xde, 0x3c, 0x38, 0xa9, 0x35, 0xb2, 0x41, 0xe1, 0x8d, 0xff, 0xf4, 0x3d, 0x1e, 0x02, 0x2c, + }; + var key = new byte[] + { + 0xa0, 0xaa, 0xa1, 0x80, 0x86, 0x61, 0x07, 0x21, 0x6a, 0xde, 0x8c, 0x80, 0x17, 0xd1, 0x2a, 0xb1, + }; + var iv = new byte[] + { + 0xa1, 0xcc, 0x79, 0xf6, 0x95, 0x97, 0xd4, 0xdb, 0x6b, 0xe6, 0x99, 0xdd, 0x70, 0x95, 0x9e, 0x60, + }; + + // echo -n -e '\x11\x1e\x28\x7a\x6a\x6f\x89\xdb\x7f\x9d\x9a\xbd\xa3\xa8\x79\xdc\x36\xde\x3c\x38\xa9\x35\xb2\x41\xe1\x8d\xff\xf4\x3d\x1e\x02\x2c' | openssl enc -e -aes-128-ctr -K A0AAA180866107216ADE8C8017D12AB1 -iv A1CC79F69597D4DB6BE699DD70959E60 -nopad | hd + var expected = new byte[] + { + 0xa9, 0x27, 0xa5, 0xbd, 0x73, 0x59, 0xe3, 0x69, 0x79, 0x89, 0x62, 0xe8, 0x4c, 0x7d, 0x75, 0xcd, + 0x9c, 0xb2, 0x30, 0x94, 0xdc, 0x88, 0xfa, 0x39, 0x05, 0x0c, 0x26, 0x25, 0x28, 0x6a, 0x9b, 0x4e, + }; + + var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CTR_128_Length64() + { + var input = new byte[] + { + 0x9b, 0x6e, 0x1d, 0xf8, 0x07, 0xf9, 0x55, 0xd4, 0xd7, 0x1a, 0xce, 0xca, 0xa8, 0x31, 0x29, 0x0f, + 0x63, 0x4d, 0x52, 0x71, 0xa5, 0x0c, 0x96, 0x08, 0xd6, 0xc5, 0x14, 0xa0, 0xc8, 0x29, 0xb1, 0xd5, + 0x40, 0x2c, 0xe5, 0xa9, 0xb4, 0x31, 0xa9, 0xa8, 0x76, 0xa5, 0x1e, 0x7a, 0xc8, 0x09, 0x32, 0x39, + 0xbc, 0x89, 0x7a, 0x22, 0x42, 0x2c, 0xba, 0x8e, 0xd7, 0x15, 0x22, 0x41, 0xe4, 0xb5, 0x0b, 0xad, + }; + var key = new byte[] + { + 0x69, 0xf9, 0x8a, 0x7c, 0x4b, 0x80, 0x5b, 0x31, 0xa4, 0xaa, 0xfa, 0xff, 0xed, 0x1c, 0x3f, 0xcc, + }; + var iv = new byte[] + { + 0x92, 0xdb, 0xe4, 0x3e, 0xaf, 0x8f, 0x92, 0x13, 0x71, 0x56, 0xd1, 0x9f, 0x0f, 0x68, 0xc3, 0xc1, + }; + + // echo -n -e '\x9b\x6e\x1d\xf8\x07\xf9\x55\xd4\xd7\x1a\xce\xca\xa8\x31\x29\x0f\x63\x4d\x52\x71\xa5\x0c\x96\x08\xd6\xc5\x14\xa0\xc8\x29\xb1\xd5\x40\x2c\xe5\xa9\xb4\x31\xa9\xa8\x76\xa5\x1e\x7a\xc8\x09\x32\x39\xbc\x89\x7a\x22\x42\x2c\xba\x8e\xd7\x15\x22\x41\xe4\xb5\x0b\xad' | openssl enc -e -aes-128-ctr -K 69F98A7C4B805B31A4AAFAFFED1C3FCC -iv 92DBE43EAF8F92137156D19F0F68C3C1 -nopad | hd + var expected = new byte[] + { + 0xc0, 0x69, 0x4b, 0xdb, 0xb2, 0x0c, 0x22, 0x82, 0xf0, 0x85, 0x77, 0x3e, 0xd9, 0x5a, 0xe7, 0x9e, + 0xb0, 0x34, 0xe8, 0x95, 0x8e, 0x93, 0x0a, 0xcf, 0xa4, 0x26, 0xd3, 0x80, 0x12, 0xcc, 0x06, 0x38, + 0x1d, 0x18, 0x55, 0xfc, 0x56, 0x59, 0xaf, 0x0b, 0x2b, 0x80, 0x87, 0x0c, 0x87, 0x45, 0xb0, 0xe2, + 0xec, 0x47, 0x81, 0x82, 0x89, 0x24, 0x76, 0xe2, 0x20, 0x6a, 0x99, 0xe2, 0xa7, 0x5a, 0xb0, 0x40, + }; + + var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CTR_192_Length16() + { + var input = new byte[] + { + 0x9a, 0x70, 0x11, 0xcf, 0x7f, 0xb6, 0xee, 0x3b, 0x2e, 0x48, 0x7e, 0x97, 0x32, 0xbb, 0xa1, 0xbb, + }; + var key = new byte[] + { + 0xd5, 0x56, 0xaf, 0x09, 0xd0, 0xcc, 0xfe, 0xda, 0x66, 0x76, 0x0a, 0xf5, 0xaf, 0xbc, 0x22, 0x3b, + 0xe6, 0x39, 0x65, 0x7d, 0x0a, 0x70, 0x4c, 0xdc, + }; + var iv = new byte[] + { + 0xec, 0xa8, 0x10, 0x66, 0x10, 0xfb, 0xe1, 0xb6, 0xb5, 0x15, 0xca, 0xb9, 0xb9, 0xba, 0xf0, 0xcd, + }; + + // echo -n -e '\x9a\x70\x11\xcf\x7f\xb6\xee\x3b\x2e\x48\x7e\x97\x32\xbb\xa1\xbb' | openssl enc -e -aes-192-ctr -K D556AF09D0CCFEDA66760AF5AFBC223BE639657D0A704CDC -iv ECA8106610FBE1B6B515CAB9B9BAF0CD -nopad | hd + var expected = new byte[] + { + 0xc4, 0x4e, 0x81, 0x32, 0xe6, 0x6d, 0x0a, 0x78, 0x49, 0xe5, 0x64, 0x6c, 0xe6, 0xc2, 0x91, 0xc9, + }; + + var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CTR_192_Length32() + { + var input = new byte[] + { + 0x72, 0x37, 0x68, 0x09, 0xab, 0xf9, 0x8c, 0x72, 0x26, 0x42, 0xb1, 0xf9, 0x55, 0x24, 0xb1, 0x64, + 0x09, 0xd2, 0x1c, 0x28, 0xbb, 0x97, 0xc9, 0x6b, 0x94, 0x54, 0x3f, 0x9a, 0xf2, 0x69, 0x82, 0x2b, + }; + var key = new byte[] + { + 0x48, 0x97, 0x0a, 0xd3, 0x07, 0x43, 0x30, 0xf3, 0x1c, 0x9d, 0x40, 0xce, 0x49, 0xe8, 0x60, 0x91, + 0x64, 0x65, 0xaf, 0xe6, 0x9e, 0xc8, 0x12, 0xdb, + }; + var iv = new byte[] + { + 0x6d, 0xfd, 0x74, 0x57, 0xb9, 0xf2, 0x80, 0xbd, 0xbf, 0x85, 0xb0, 0xbd, 0x19, 0xdd, 0x5d, 0xc6, + }; + + // echo -n -e '\x72\x37\x68\x09\xab\xf9\x8c\x72\x26\x42\xb1\xf9\x55\x24\xb1\x64\x09\xd2\x1c\x28\xbb\x97\xc9\x6b\x94\x54\x3f\x9a\xf2\x69\x82\x2b' | openssl enc -e -aes-192-ctr -K 48970AD3074330F31C9D40CE49E860916465AFE69EC812DB -iv 6DFD7457B9F280BDBF85B0BD19DD5DC6 -nopad | hd + var expected = new byte[] + { + 0xfa, 0x30, 0x3f, 0x12, 0x3c, 0x7a, 0xa8, 0x1e, 0xfd, 0xaa, 0x17, 0x71, 0xbd, 0x01, 0xeb, 0xac, + 0x85, 0xcd, 0x88, 0xa8, 0x25, 0xc8, 0xbd, 0xf8, 0xc3, 0xa9, 0x74, 0x36, 0x82, 0x19, 0xfc, 0xb3, + }; + + var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CTR_192_Length64() + { + var input = new byte[] + { + 0xa2, 0x28, 0x0b, 0x1e, 0x56, 0xfb, 0x21, 0xac, 0xf3, 0xae, 0x35, 0x8c, 0xb9, 0x9c, 0x8d, 0x80, + 0x85, 0x2f, 0x66, 0x09, 0xce, 0xd8, 0x3a, 0x2a, 0x1d, 0x82, 0x0e, 0xc4, 0x37, 0xa3, 0x77, 0x86, + 0x07, 0xe9, 0x43, 0x75, 0xbc, 0xf3, 0x84, 0x72, 0xdb, 0xc8, 0x63, 0x0b, 0xbc, 0xf3, 0x03, 0x23, + 0xf7, 0x30, 0x38, 0xea, 0x77, 0x53, 0xf7, 0xc9, 0xee, 0xe0, 0x00, 0xd4, 0xec, 0x5d, 0x75, 0x50, + }; + var key = new byte[] + { + 0x36, 0xaf, 0x84, 0xcf, 0x58, 0x17, 0xc3, 0x91, 0xaa, 0xf3, 0x2d, 0x06, 0x74, 0x2e, 0x6e, 0x29, + 0x7e, 0xeb, 0xcc, 0x06, 0x6b, 0x8d, 0x0f, 0xb4, + }; + var iv = new byte[] + { + 0xf1, 0x7a, 0x87, 0xdb, 0xf3, 0xb0, 0x86, 0x7e, 0x52, 0x13, 0xd4, 0x0c, 0x6f, 0x34, 0xca, 0xe0, + }; + + // echo -n -e '\xa2\x28\x0b\x1e\x56\xfb\x21\xac\xf3\xae\x35\x8c\xb9\x9c\x8d\x80\x85\x2f\x66\x09\xce\xd8\x3a\x2a\x1d\x82\x0e\xc4\x37\xa3\x77\x86\x07\xe9\x43\x75\xbc\xf3\x84\x72\xdb\xc8\x63\x0b\xbc\xf3\x03\x23\xf7\x30\x38\xea\x77\x53\xf7\xc9\xee\xe0\x00\xd4\xec\x5d\x75\x50' | openssl enc -e -aes-192-ctr -K 36AF84CF5817C391AAF32D06742E6E297EEBCC066B8D0FB4 -iv F17A87DBF3B0867E5213D40C6F34CAE0 -nopad | hd + var expected = new byte[] + { + 0x81, 0xb8, 0x35, 0xd5, 0x95, 0xa3, 0xe4, 0x01, 0xaf, 0x87, 0x90, 0x45, 0xaa, 0x03, 0x8e, 0x25, + 0x20, 0x6e, 0xb4, 0x97, 0x51, 0xd3, 0xb1, 0xaa, 0x6c, 0x14, 0x98, 0x11, 0x25, 0x7f, 0x9c, 0xc0, + 0xba, 0x65, 0x2d, 0xe3, 0x7b, 0x60, 0x9c, 0x64, 0x4e, 0xcc, 0x32, 0xb5, 0x38, 0xa4, 0xed, 0x69, + 0x2d, 0x26, 0x4a, 0x22, 0x97, 0x7a, 0x94, 0x5e, 0xb0, 0xb2, 0x3d, 0x42, 0x2b, 0x4a, 0x5e, 0x5d, + }; + + var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CTR_256_Length16() + { + var input = new byte[] + { + 0x6d, 0xa6, 0x3f, 0x83, 0x25, 0xf1, 0x54, 0xbf, 0x72, 0xd7, 0x55, 0x00, 0x90, 0x6f, 0xe5, 0xa9, + }; + var key = new byte[] + { + 0x9f, 0xd0, 0xde, 0xde, 0x8f, 0xe7, 0x9e, 0xfa, 0x6d, 0xaf, 0xb3, 0x61, 0x5a, 0x61, 0xba, 0x4a, + 0x21, 0xec, 0x98, 0xc4, 0x4d, 0x8b, 0x8e, 0x00, 0x25, 0xc8, 0x69, 0x1b, 0x5b, 0x85, 0xee, 0xe3, + }; + var iv = new byte[] + { + 0x2e, 0x2b, 0x6d, 0x9e, 0x56, 0xeb, 0x50, 0x85, 0x07, 0x45, 0x16, 0x76, 0x3d, 0xf3, 0x64, 0x11, + }; + + // echo -n -e '\x6d\xa6\x3f\x83\x25\xf1\x54\xbf\x72\xd7\x55\x00\x90\x6f\xe5\xa9' | openssl enc -e -aes-256-ctr -K 9FD0DEDE8FE79EFA6DAFB3615A61BA4A21EC98C44D8B8E0025C8691B5B85EEE3 -iv 2E2B6D9E56EB5085074516763DF36411 -nopad | hd + var expected = new byte[] + { + 0xa6, 0x46, 0x19, 0x9d, 0x3e, 0xa5, 0x53, 0xc8, 0xd9, 0xb3, 0x46, 0xbc, 0x0b, 0x3e, 0x47, 0xf4, + }; + + var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CTR_256_Length32() + { + var input = new byte[] + { + 0x1d, 0x0a, 0xdf, 0xa4, 0xd6, 0x20, 0x5c, 0x14, 0x41, 0xdd, 0xb9, 0xc6, 0x7e, 0x83, 0x9f, 0xe7, + 0xc0, 0xd0, 0x32, 0x2f, 0xf4, 0x1b, 0xf4, 0x35, 0x9b, 0x13, 0xbd, 0x08, 0x74, 0x18, 0xc2, 0x32, + }; + var key = new byte[] + { + 0x64, 0x58, 0xfe, 0x51, 0xa5, 0x49, 0x0c, 0x0d, 0xcf, 0x58, 0x5d, 0x78, 0x32, 0x8a, 0x07, 0x84, + 0xa5, 0x2f, 0xb5, 0x6d, 0xc0, 0x35, 0x1c, 0x01, 0x15, 0xaa, 0x09, 0xc3, 0x63, 0x53, 0xa0, 0x28, + }; + var iv = new byte[] + { + 0x1a, 0x87, 0x62, 0x25, 0x84, 0x4e, 0x41, 0x76, 0xc3, 0x24, 0x5f, 0x9b, 0xbe, 0x7c, 0x02, 0x11, + }; + + // echo -n -e '\x1d\x0a\xdf\xa4\xd6\x20\x5c\x14\x41\xdd\xb9\xc6\x7e\x83\x9f\xe7\xc0\xd0\x32\x2f\xf4\x1b\xf4\x35\x9b\x13\xbd\x08\x74\x18\xc2\x32' | openssl enc -e -aes-256-ctr -K 6458FE51A5490C0DCF585D78328A0784A52FB56DC0351C0115AA09C36353A028 -iv 1A876225844E4176C3245F9BBE7C0211 -nopad | hd + var expected = new byte[] + { + 0x72, 0xb6, 0xb0, 0x78, 0xae, 0x36, 0xaa, 0x9e, 0x6b, 0xb7, 0x63, 0x7a, 0x77, 0x68, 0x8b, 0x42, + 0x1d, 0x7e, 0xe7, 0xe7, 0xa0, 0xae, 0x31, 0x9b, 0xb3, 0x21, 0xb8, 0x0c, 0x47, 0x3e, 0xaf, 0xdd, + }; + + var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_CTR_256_Length64() + { + var input = new byte[] + { + 0x0b, 0x38, 0x62, 0x45, 0x62, 0x55, 0x71, 0x2e, 0x3b, 0xfc, 0x3b, 0xfb, 0x40, 0x49, 0xaa, 0x7b, + 0xb8, 0x34, 0x5d, 0xab, 0x27, 0xe1, 0xff, 0x57, 0xed, 0x3e, 0xa9, 0x9b, 0xd5, 0x80, 0x43, 0x98, + 0xa7, 0xf7, 0xb7, 0x2a, 0xf0, 0x5a, 0xc6, 0xc4, 0x15, 0x34, 0xea, 0x88, 0x12, 0x46, 0x36, 0x79, + 0x7a, 0xe4, 0xe3, 0x89, 0x1e, 0x57, 0xe9, 0x29, 0x39, 0x0b, 0x58, 0x23, 0xac, 0xd6, 0x58, 0xba, + }; + var key = new byte[] + { + 0xb9, 0xa2, 0x53, 0x48, 0x92, 0x7f, 0x8b, 0x5d, 0x6e, 0x98, 0x96, 0xf3, 0xf7, 0x77, 0x44, 0xa6, + 0x08, 0x2f, 0x20, 0xf1, 0x9d, 0xb9, 0x7a, 0x50, 0x0e, 0x8e, 0xf1, 0xe5, 0x02, 0xa2, 0x18, 0x3e, + }; + var iv = new byte[] + { + 0xdb, 0x2f, 0xcf, 0x6f, 0xf2, 0xed, 0xe7, 0xfb, 0x59, 0x86, 0x1b, 0x85, 0xc1, 0xf5, 0x32, 0xc2, + }; + + // echo -n -e '\x0b\x38\x62\x45\x62\x55\x71\x2e\x3b\xfc\x3b\xfb\x40\x49\xaa\x7b\xb8\x34\x5d\xab\x27\xe1\xff\x57\xed\x3e\xa9\x9b\xd5\x80\x43\x98\xa7\xf7\xb7\x2a\xf0\x5a\xc6\xc4\x15\x34\xea\x88\x12\x46\x36\x79\x7a\xe4\xe3\x89\x1e\x57\xe9\x29\x39\x0b\x58\x23\xac\xd6\x58\xba' | openssl enc -e -aes-256-ctr -K B9A25348927F8B5D6E9896F3F77744A6082F20F19DB97A500E8EF1E502A2183E -iv DB2FCF6FF2EDE7FB59861B85C1F532C2 -nopad | hd + var expected = new byte[] + { + 0x88, 0x04, 0x50, 0xe6, 0x92, 0x0b, 0x86, 0x43, 0x26, 0x8d, 0x5f, 0x38, 0x85, 0xd7, 0x9f, 0x06, + 0x75, 0x66, 0xae, 0x7f, 0x20, 0x3b, 0xfc, 0x49, 0x78, 0x69, 0x63, 0x18, 0x86, 0xe7, 0x7d, 0x3e, + 0x15, 0xcc, 0x98, 0xc9, 0xe4, 0x6f, 0x29, 0x13, 0xf9, 0x61, 0x33, 0x77, 0x6b, 0x43, 0x44, 0xde, + 0x92, 0xb0, 0x7b, 0x7a, 0x77, 0x65, 0xf0, 0xcc, 0xbd, 0xe4, 0x41, 0xea, 0x9e, 0xfd, 0xdf, 0x41, + }; + + var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_OFB_128_Length16() + { + var input = new byte[] + { + 0xc7, 0xb1, 0x1b, 0x7c, 0xb5, 0x66, 0x1d, 0xff, 0x28, 0x03, 0x3a, 0x03, 0x8d, 0xa6, 0x5b, 0xcc, + }; + var key = new byte[] + { + 0x80, 0x57, 0x18, 0xc8, 0xa7, 0xd4, 0xb3, 0x1b, 0x48, 0x25, 0x98, 0x16, 0x9e, 0xf4, 0x8e, 0x19, + }; + var iv = new byte[] + { + 0x5c, 0x2f, 0x1d, 0x50, 0x86, 0x9c, 0x89, 0x74, 0x11, 0xd0, 0x46, 0xef, 0xb2, 0xe3, 0x6d, 0xb3, + }; + + // echo -n -e '\xc7\xb1\x1b\x7c\xb5\x66\x1d\xff\x28\x03\x3a\x03\x8d\xa6\x5b\xcc' | openssl enc -e -aes-128-ofb -K 805718C8A7D4B31B482598169EF48E19 -iv 5C2F1D50869C897411D046EFB2E36DB3 -nopad | hd + var expected = new byte[] + { + 0xb0, 0x65, 0x77, 0x03, 0xb4, 0x54, 0x82, 0x92, 0x05, 0x82, 0x93, 0x1f, 0x8d, 0x7b, 0xb6, 0xf0, + }; + + var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_OFB_128_Length32() + { + var input = new byte[] + { + 0x2a, 0x4f, 0x05, 0x69, 0xdd, 0x69, 0x1a, 0xf2, 0xfe, 0xff, 0x34, 0x8f, 0xcd, 0x06, 0x60, 0x34, + 0x74, 0x21, 0xa7, 0x5d, 0x88, 0x0a, 0x45, 0xe4, 0xcd, 0xa3, 0xb7, 0xd7, 0x8e, 0xc4, 0x68, 0x64, + }; + var key = new byte[] + { + 0xb8, 0xe5, 0xec, 0x4e, 0xee, 0x24, 0x3b, 0xf2, 0x15, 0x2b, 0x52, 0x86, 0x67, 0xf9, 0xa7, 0x0a, + }; + var iv = new byte[] + { + 0x6f, 0x12, 0x7a, 0x91, 0x3b, 0x0f, 0x2b, 0x20, 0x0a, 0x21, 0x9c, 0x39, 0xb2, 0x43, 0x64, 0x39, + }; + + // echo -n -e '\x2a\x4f\x05\x69\xdd\x69\x1a\xf2\xfe\xff\x34\x8f\xcd\x06\x60\x34\x74\x21\xa7\x5d\x88\x0a\x45\xe4\xcd\xa3\xb7\xd7\x8e\xc4\x68\x64' | openssl enc -e -aes-128-ofb -K B8E5EC4EEE243BF2152B528667F9A70A -iv 6F127A913B0F2B200A219C39B2436439 -nopad | hd + var expected = new byte[] + { + 0x11, 0x2d, 0xdf, 0xcf, 0x49, 0xc9, 0xd8, 0x0a, 0x7d, 0xd3, 0x2f, 0xf5, 0xc5, 0xec, 0x7e, 0xc9, + 0x11, 0xb9, 0xd6, 0x67, 0x6c, 0xe7, 0xaa, 0x09, 0x93, 0xe3, 0x5f, 0xed, 0x38, 0x46, 0x37, 0xd2, + }; + + var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_OFB_128_Length64() + { + var input = new byte[] + { + 0x97, 0xd0, 0xd7, 0xe8, 0x1a, 0x11, 0x45, 0x4f, 0xe5, 0xb5, 0x48, 0x5c, 0xb7, 0xbe, 0x7c, 0xd4, + 0xfc, 0xac, 0x68, 0x7b, 0x49, 0xd7, 0x28, 0xa8, 0xba, 0xcb, 0x44, 0xcd, 0x88, 0x01, 0x3f, 0xd2, + 0xc7, 0x19, 0xef, 0x97, 0x21, 0xbe, 0xef, 0x5d, 0xcc, 0x2b, 0xac, 0x86, 0xc7, 0xce, 0x69, 0x4b, + 0xa4, 0xc7, 0x3d, 0x05, 0xda, 0xe8, 0xf0, 0xc0, 0xa7, 0x2f, 0x2d, 0x4f, 0xcd, 0x77, 0xc6, 0xe3, + }; + var key = new byte[] + { + 0x75, 0x76, 0x94, 0x9e, 0xce, 0xe5, 0xb2, 0x3d, 0xbd, 0x0a, 0xae, 0x1e, 0x2b, 0xa2, 0xe1, 0xeb, + }; + var iv = new byte[] + { + 0x61, 0xf8, 0x28, 0xc1, 0xc4, 0x39, 0xf7, 0xdf, 0x28, 0x2f, 0xef, 0xf2, 0x91, 0x9f, 0x90, 0x54, + }; + + // echo -n -e '\x97\xd0\xd7\xe8\x1a\x11\x45\x4f\xe5\xb5\x48\x5c\xb7\xbe\x7c\xd4\xfc\xac\x68\x7b\x49\xd7\x28\xa8\xba\xcb\x44\xcd\x88\x01\x3f\xd2\xc7\x19\xef\x97\x21\xbe\xef\x5d\xcc\x2b\xac\x86\xc7\xce\x69\x4b\xa4\xc7\x3d\x05\xda\xe8\xf0\xc0\xa7\x2f\x2d\x4f\xcd\x77\xc6\xe3' | openssl enc -e -aes-128-ofb -K 7576949ECEE5B23DBD0AAE1E2BA2E1EB -iv 61F828C1C439F7DF282FEFF2919F9054 -nopad | hd + var expected = new byte[] + { + 0xc9, 0x2c, 0x55, 0x6b, 0x28, 0x79, 0x3a, 0xe8, 0x82, 0x9c, 0x37, 0xb6, 0xb5, 0xf9, 0xd9, 0x7f, + 0xd4, 0xdd, 0xc7, 0xf0, 0x45, 0x48, 0x44, 0xc4, 0x18, 0x3e, 0x86, 0x60, 0xbc, 0xdc, 0x0d, 0xae, + 0x5e, 0xb0, 0xdb, 0x23, 0xc7, 0x33, 0x2b, 0x06, 0x0d, 0x01, 0x1e, 0x9b, 0xb8, 0xf1, 0xde, 0x27, + 0xda, 0xad, 0x1b, 0xa5, 0x20, 0x67, 0xd2, 0xa6, 0x18, 0x26, 0x30, 0x43, 0x2f, 0xa2, 0x66, 0x0b, + }; + + var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_OFB_192_Length16() + { + var input = new byte[] + { + 0x64, 0xc8, 0x10, 0x50, 0x3a, 0xcb, 0x7d, 0xbf, 0x14, 0x00, 0x48, 0xd0, 0x39, 0xd2, 0x94, 0x05, + }; + var key = new byte[] + { + 0x4d, 0x41, 0xed, 0xd4, 0x4f, 0x05, 0x1f, 0x3c, 0x7e, 0xb5, 0x75, 0x9e, 0xf5, 0xc0, 0xab, 0x1d, + 0x79, 0x59, 0xba, 0x62, 0x91, 0x90, 0xb1, 0x96, + }; + var iv = new byte[] + { + 0x7b, 0x69, 0xac, 0xc3, 0xf1, 0x26, 0xa5, 0x56, 0x9a, 0xe9, 0xa4, 0x4f, 0xb1, 0xbc, 0x05, 0x5e, + }; + + // echo -n -e '\x64\xc8\x10\x50\x3a\xcb\x7d\xbf\x14\x00\x48\xd0\x39\xd2\x94\x05' | openssl enc -e -aes-192-ofb -K 4D41EDD44F051F3C7EB5759EF5C0AB1D7959BA629190B196 -iv 7B69ACC3F126A5569AE9A44FB1BC055E -nopad | hd + var expected = new byte[] + { + 0x79, 0x41, 0x28, 0xc9, 0x3b, 0x89, 0x6f, 0x69, 0x92, 0xb0, 0x3e, 0x38, 0x11, 0x2c, 0xe5, 0xd8, + }; + + var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_OFB_192_Length32() + { + var input = new byte[] + { + 0xa9, 0xd4, 0xd2, 0x85, 0x55, 0xde, 0xc9, 0x54, 0x54, 0x2a, 0x56, 0xe0, 0x17, 0x32, 0x74, 0xbd, + 0x90, 0x57, 0x58, 0xe5, 0x59, 0x5b, 0x4a, 0x58, 0x0f, 0x1f, 0x04, 0x0b, 0x1b, 0x5c, 0x6b, 0xbd, + }; + var key = new byte[] + { + 0x54, 0x5b, 0xb9, 0xbd, 0xbe, 0x2c, 0x41, 0x9c, 0x9f, 0x57, 0x6e, 0xc6, 0xd0, 0xc5, 0x3e, 0x68, + 0x75, 0xe6, 0xbf, 0x5a, 0x63, 0x1f, 0x05, 0x4d, + }; + var iv = new byte[] + { + 0x89, 0x79, 0x75, 0x36, 0xda, 0xbd, 0x39, 0xf8, 0xbe, 0x98, 0x8c, 0xbc, 0x79, 0xb6, 0xff, 0x64, + }; + + // echo -n -e '\xa9\xd4\xd2\x85\x55\xde\xc9\x54\x54\x2a\x56\xe0\x17\x32\x74\xbd\x90\x57\x58\xe5\x59\x5b\x4a\x58\x0f\x1f\x04\x0b\x1b\x5c\x6b\xbd' | openssl enc -e -aes-192-ofb -K 545BB9BDBE2C419C9F576EC6D0C53E6875E6BF5A631F054D -iv 89797536DABD39F8BE988CBC79B6FF64 -nopad | hd + var expected = new byte[] + { + 0x23, 0x79, 0x22, 0x9c, 0xa4, 0xfe, 0xc4, 0xf4, 0xd9, 0xc7, 0x4f, 0x63, 0x01, 0x54, 0xca, 0xe6, + 0xe8, 0xe8, 0x8e, 0x1a, 0xa6, 0x25, 0xa5, 0x65, 0x0d, 0x5a, 0xe2, 0x9c, 0xd2, 0x7e, 0x06, 0x14, + }; + + var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_OFB_192_Length64() + { + var input = new byte[] + { + 0x15, 0xbc, 0x46, 0x01, 0xed, 0x84, 0x87, 0x4a, 0xe0, 0x9c, 0x96, 0x34, 0x9d, 0x11, 0x5a, 0x34, + 0x56, 0x6b, 0x33, 0x44, 0xb7, 0x0b, 0xc2, 0xe1, 0x1e, 0x76, 0x07, 0x37, 0x39, 0x82, 0xee, 0xbe, + 0xe7, 0x5b, 0x44, 0xa7, 0xd9, 0x03, 0x60, 0x04, 0xf1, 0x2a, 0x55, 0x3e, 0x27, 0x04, 0x5a, 0xad, + 0x3e, 0x57, 0x65, 0x0d, 0x83, 0xbb, 0xac, 0x0a, 0xf9, 0x64, 0xe2, 0x76, 0x7d, 0x50, 0x11, 0x5e, + }; + var key = new byte[] + { + 0xad, 0xd7, 0x4d, 0x42, 0xcc, 0xb3, 0x5a, 0x52, 0x0b, 0x2e, 0x52, 0x8c, 0xb5, 0x84, 0xb9, 0x1a, + 0x1c, 0x59, 0xf9, 0xe1, 0x1c, 0xe0, 0x3b, 0x2c, + }; + var iv = new byte[] + { + 0xae, 0x39, 0xad, 0x74, 0x21, 0xea, 0x87, 0xa1, 0x18, 0xf6, 0x91, 0x50, 0xb7, 0x18, 0xe1, 0x8a, + }; + + // echo -n -e '\x15\xbc\x46\x01\xed\x84\x87\x4a\xe0\x9c\x96\x34\x9d\x11\x5a\x34\x56\x6b\x33\x44\xb7\x0b\xc2\xe1\x1e\x76\x07\x37\x39\x82\xee\xbe\xe7\x5b\x44\xa7\xd9\x03\x60\x04\xf1\x2a\x55\x3e\x27\x04\x5a\xad\x3e\x57\x65\x0d\x83\xbb\xac\x0a\xf9\x64\xe2\x76\x7d\x50\x11\x5e' | openssl enc -e -aes-192-ofb -K ADD74D42CCB35A520B2E528CB584B91A1C59F9E11CE03B2C -iv AE39AD7421EA87A118F69150B718E18A -nopad | hd + var expected = new byte[] + { + 0x49, 0x73, 0xbd, 0x44, 0x22, 0x0b, 0xc5, 0x00, 0x81, 0x80, 0x3e, 0x94, 0x47, 0xf9, 0x60, 0xba, + 0x45, 0x10, 0x5a, 0xce, 0xf0, 0xc0, 0xf7, 0xe5, 0x3d, 0xa0, 0xb4, 0x53, 0x3e, 0xee, 0xa2, 0xea, + 0xdf, 0x14, 0x8b, 0xe4, 0xa9, 0x74, 0x3b, 0xc2, 0x50, 0xc3, 0x23, 0xfe, 0xc6, 0x27, 0x0d, 0x74, + 0xc7, 0xd0, 0x21, 0x0a, 0x40, 0x1d, 0x32, 0x32, 0x88, 0x86, 0x40, 0xa9, 0x4c, 0x59, 0x9c, 0xb4, + }; + + var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_OFB_256_Length16() + { + var input = new byte[] + { + 0xfd, 0x13, 0x02, 0x54, 0x68, 0x20, 0x55, 0x75, 0xab, 0xc8, 0x5a, 0x23, 0x57, 0x30, 0x42, 0xcc, + }; + var key = new byte[] + { + 0x9c, 0x20, 0x94, 0x92, 0x06, 0xe6, 0x31, 0x21, 0xa6, 0xb1, 0x73, 0xbf, 0xf2, 0x69, 0x63, 0x03, + 0x78, 0x6e, 0xe4, 0x08, 0xde, 0xe6, 0xc3, 0x8d, 0xe4, 0x37, 0xc9, 0x58, 0x8f, 0x64, 0x4a, 0xe8, + }; + var iv = new byte[] + { + 0xb4, 0xc4, 0xb4, 0x96, 0x84, 0x4e, 0x84, 0x16, 0xe1, 0xe1, 0xad, 0xb7, 0xac, 0x95, 0x82, 0x41, + }; + + // echo -n -e '\xfd\x13\x02\x54\x68\x20\x55\x75\xab\xc8\x5a\x23\x57\x30\x42\xcc' | openssl enc -e -aes-256-ofb -K 9C20949206E63121A6B173BFF2696303786EE408DEE6C38DE437C9588F644AE8 -iv B4C4B496844E8416E1E1ADB7AC958241 -nopad | hd + var expected = new byte[] + { + 0x98, 0x85, 0x21, 0xeb, 0x42, 0x0c, 0x8b, 0xb3, 0xab, 0x64, 0x78, 0xe5, 0x67, 0xdd, 0xee, 0x36, + }; + + var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_OFB_256_Length32() + { + var input = new byte[] + { + 0x65, 0x56, 0xab, 0xe9, 0x4c, 0x39, 0xed, 0xb5, 0x5c, 0x06, 0xae, 0xce, 0x1d, 0xd8, 0x91, 0x42, + 0x67, 0x8b, 0x0b, 0x2e, 0xb5, 0xcd, 0x7f, 0x29, 0xe9, 0xcd, 0x26, 0xfd, 0x39, 0x0c, 0xe1, 0x4e, + }; + var key = new byte[] + { + 0xb4, 0x87, 0xf3, 0x39, 0xb9, 0x60, 0x9c, 0x7a, 0xd6, 0xfe, 0x39, 0x7d, 0xa0, 0xb6, 0xf9, 0x09, + 0x4f, 0x6b, 0x50, 0x20, 0x8a, 0x54, 0x8c, 0x97, 0xd6, 0x81, 0xff, 0x7e, 0x12, 0xf0, 0x7b, 0x50, + }; + var iv = new byte[] + { + 0x24, 0x5f, 0x19, 0x95, 0xe5, 0x58, 0x89, 0x06, 0xef, 0x90, 0x57, 0xb6, 0x94, 0x02, 0x89, 0x32, + }; + + // echo -n -e '\x65\x56\xab\xe9\x4c\x39\xed\xb5\x5c\x06\xae\xce\x1d\xd8\x91\x42\x67\x8b\x0b\x2e\xb5\xcd\x7f\x29\xe9\xcd\x26\xfd\x39\x0c\xe1\x4e' | openssl enc -e -aes-256-ofb -K B487F339B9609C7AD6FE397DA0B6F9094F6B50208A548C97D681FF7E12F07B50 -iv 245F1995E5588906EF9057B694028932 -nopad | hd + var expected = new byte[] + { + 0x46, 0xe6, 0x18, 0x3c, 0x18, 0xf9, 0x6d, 0x4f, 0xc2, 0x75, 0x89, 0xea, 0x0d, 0xc9, 0x9a, 0x4c, + 0x39, 0x54, 0x2e, 0x9f, 0x81, 0x49, 0xd3, 0x6b, 0x58, 0x20, 0x03, 0x21, 0x8d, 0x41, 0x9a, 0x42, + }; + + var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] + public void AES_OFB_256_Length64() + { + var input = new byte[] + { + 0xd4, 0x1d, 0xad, 0xce, 0xbc, 0xc0, 0xc4, 0x60, 0xfb, 0x5b, 0x62, 0x37, 0x61, 0x1d, 0x68, 0xe6, + 0x82, 0xe8, 0x58, 0x41, 0x9d, 0x63, 0x23, 0xf7, 0xe1, 0x49, 0x31, 0xfa, 0xfd, 0xd5, 0x03, 0xd4, + 0xf8, 0xcd, 0xaa, 0xf4, 0x43, 0xad, 0x93, 0x64, 0x9b, 0xb8, 0x9a, 0x89, 0xf6, 0x51, 0xa5, 0xd1, + 0x28, 0x71, 0x34, 0xab, 0xa9, 0x47, 0x95, 0x70, 0xf9, 0xb5, 0xec, 0x72, 0x8f, 0xc9, 0x63, 0x26, + }; + var key = new byte[] + { + 0x57, 0x8d, 0x3f, 0x94, 0x73, 0x73, 0xa3, 0xd5, 0x54, 0xf4, 0xa6, 0xe4, 0xc9, 0x9a, 0x01, 0x8f, + 0xa4, 0x60, 0xd1, 0x8b, 0xa1, 0x58, 0x2b, 0xb0, 0x37, 0x39, 0xfa, 0x8d, 0xc1, 0x21, 0xd5, 0xd1, + }; + var iv = new byte[] + { + 0x55, 0x74, 0x31, 0x68, 0x12, 0x10, 0x5d, 0xb4, 0xcd, 0x5e, 0x56, 0xb5, 0xa1, 0xb1, 0xa6, 0x5f, + }; + + // echo -n -e '\xd4\x1d\xad\xce\xbc\xc0\xc4\x60\xfb\x5b\x62\x37\x61\x1d\x68\xe6\x82\xe8\x58\x41\x9d\x63\x23\xf7\xe1\x49\x31\xfa\xfd\xd5\x03\xd4\xf8\xcd\xaa\xf4\x43\xad\x93\x64\x9b\xb8\x9a\x89\xf6\x51\xa5\xd1\x28\x71\x34\xab\xa9\x47\x95\x70\xf9\xb5\xec\x72\x8f\xc9\x63\x26' | openssl enc -e -aes-256-ofb -K 578D3F947373A3D554F4A6E4C99A018FA460D18BA1582BB03739FA8DC121D5D1 -iv 5574316812105DB4CD5E56B5A1B1A65F -nopad | hd + var expected = new byte[] + { + 0x9c, 0x60, 0x07, 0xb3, 0xda, 0xda, 0x67, 0xaa, 0xa8, 0xdc, 0xa6, 0xe4, 0xca, 0x6f, 0x71, 0x51, + 0xaf, 0x2c, 0x99, 0xdb, 0x58, 0xe1, 0x89, 0x4e, 0x18, 0x26, 0xc4, 0xeb, 0xf4, 0xdc, 0x07, 0xc0, + 0x5e, 0xa5, 0x16, 0x3f, 0x9b, 0x18, 0x86, 0x4e, 0x94, 0xe2, 0x60, 0x70, 0x1f, 0x39, 0xa9, 0x4d, + 0x7a, 0x3a, 0x43, 0xa6, 0x8f, 0x48, 0xfe, 0x6e, 0x64, 0xf6, 0x01, 0x0d, 0xdf, 0x9d, 0x34, 0xee, + }; + + var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } } } From 6ec6dc13fded12b4f05ad88cea939e1fdae607f0 Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Sat, 21 Oct 2023 16:58:18 +0200 Subject: [PATCH 59/96] Remove byte order mark, set eol=lf in key files --- .gitattributes | 3 +++ test/Data/Key.ECDSA.Encrypted.txt | 2 +- test/Data/Key.ECDSA.txt | 2 +- test/Data/Key.ECDSA384.Encrypted.txt | 2 +- test/Data/Key.ECDSA384.txt | 2 +- test/Data/Key.ECDSA521.Encrypted.txt | 2 +- test/Data/Key.ECDSA521.txt | 2 +- test/Data/Key.OPENSSH.ECDSA.Encrypted.txt | 2 +- test/Data/Key.OPENSSH.ECDSA.txt | 2 +- test/Data/Key.OPENSSH.ECDSA384.Encrypted.txt | 2 +- test/Data/Key.OPENSSH.ECDSA384.txt | 2 +- test/Data/Key.OPENSSH.ECDSA521.Encrypted.txt | 2 +- test/Data/Key.OPENSSH.ECDSA521.txt | 2 +- test/Data/Key.OPENSSH.ED25519.Encrypted.txt | 2 +- test/Data/Key.OPENSSH.ED25519.txt | 2 +- test/Data/Key.OPENSSH.RSA.Encrypted.txt | 2 +- test/Data/Key.OPENSSH.RSA.txt | 2 +- test/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt | 2 +- test/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt | 2 +- test/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt | 2 +- test/Data/Key.RSA.Encrypted.Des.CBC.12345.txt | 2 +- test/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt | 2 +- test/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt | 2 +- test/Data/Key.RSA.txt | 2 +- test/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt | 2 +- test/Data/Key.SSH2.RSA.txt | 2 +- 26 files changed, 28 insertions(+), 25 deletions(-) diff --git a/.gitattributes b/.gitattributes index 700825a76..83d35b020 100644 --- a/.gitattributes +++ b/.gitattributes @@ -15,3 +15,6 @@ *.nupkg binary *.pdf binary *.snk binary + +# Ensure key files have LF endings for easier usage with ssh-keygen +test/Data/* eol=lf \ No newline at end of file diff --git a/test/Data/Key.ECDSA.Encrypted.txt b/test/Data/Key.ECDSA.Encrypted.txt index f0af5ba7d..405b4105c 100644 --- a/test/Data/Key.ECDSA.Encrypted.txt +++ b/test/Data/Key.ECDSA.Encrypted.txt @@ -1,4 +1,4 @@ -锘-----BEGIN EC PRIVATE KEY----- +-----BEGIN EC PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,54D46F498C989115AAE14FEA21E3AF11 diff --git a/test/Data/Key.ECDSA.txt b/test/Data/Key.ECDSA.txt index 13ac9fb49..3c1c9ed81 100644 --- a/test/Data/Key.ECDSA.txt +++ b/test/Data/Key.ECDSA.txt @@ -1,4 +1,4 @@ -锘-----BEGIN EC PRIVATE KEY----- +-----BEGIN EC PRIVATE KEY----- MHcCAQEEIEdqaFKgJBIibVjyUh1v7Y35LwIQJrocdTaYFLwl7iB0oAoGCCqGSM49 AwEHoUQDQgAEQD5MO/n9yqSDTszwzVpApLx5SQFecE5ZfDkgxqVdHQecm1BAPozZ 4eKGNhKn72hT79mLlp9HXX+oNEcuVT83Hw== diff --git a/test/Data/Key.ECDSA384.Encrypted.txt b/test/Data/Key.ECDSA384.Encrypted.txt index 00072ce24..c0e1a360a 100644 --- a/test/Data/Key.ECDSA384.Encrypted.txt +++ b/test/Data/Key.ECDSA384.Encrypted.txt @@ -1,4 +1,4 @@ -锘-----BEGIN EC PRIVATE KEY----- +-----BEGIN EC PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,1D64653C5E18C2AACB0B17E3FE43C219 diff --git a/test/Data/Key.ECDSA384.txt b/test/Data/Key.ECDSA384.txt index f2d658ea4..43edbf09c 100644 --- a/test/Data/Key.ECDSA384.txt +++ b/test/Data/Key.ECDSA384.txt @@ -1,4 +1,4 @@ -锘-----BEGIN EC PRIVATE KEY----- +-----BEGIN EC PRIVATE KEY----- MIGkAgEBBDCQawHdHLR7NvKa2vPV0sVkbzOE8c0enp95iEysGcGV66RXE1EH//nh gu5UzeTR4KigBwYFK4EEACKhZANiAAQUk4rVvoOPI1hQzWpNx09Uo6qG+srGcbvB q15eFK0GnK/T0UBKxdbZ2+//KAYI6SeDHM9t3ORF1aX5EpjTEBI4d7ZY/lV9jX6M diff --git a/test/Data/Key.ECDSA521.Encrypted.txt b/test/Data/Key.ECDSA521.Encrypted.txt index 381b30be8..79b339079 100644 --- a/test/Data/Key.ECDSA521.Encrypted.txt +++ b/test/Data/Key.ECDSA521.Encrypted.txt @@ -1,4 +1,4 @@ -锘-----BEGIN EC PRIVATE KEY----- +-----BEGIN EC PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,F995028237EBD79C928530CC6C3E957F diff --git a/test/Data/Key.ECDSA521.txt b/test/Data/Key.ECDSA521.txt index 31abe917a..27a74ff9a 100644 --- a/test/Data/Key.ECDSA521.txt +++ b/test/Data/Key.ECDSA521.txt @@ -1,4 +1,4 @@ -锘-----BEGIN EC PRIVATE KEY----- +-----BEGIN EC PRIVATE KEY----- MIHcAgEBBEIBn2DAme7AU8sCA+/sd6s3c2FNW26IiPvulGd3FC8k5q+fjBZ5LUWR iJMGrsf2rJLO8hXMGJYoF9tjZEGaabQ8KVagBwYFK4EEACOhgYkDgYYABABrpVjs ANqcvqMUo1wo0I1uVCXQ6xrauy4iU86FiOwFmkYRrle4w3oYdRJwniC3TwGMuBuM diff --git a/test/Data/Key.OPENSSH.ECDSA.Encrypted.txt b/test/Data/Key.OPENSSH.ECDSA.Encrypted.txt index ab76db4a2..2de37354f 100644 --- a/test/Data/Key.OPENSSH.ECDSA.Encrypted.txt +++ b/test/Data/Key.OPENSSH.ECDSA.Encrypted.txt @@ -1,4 +1,4 @@ -锘-----BEGIN OPENSSH PRIVATE KEY----- +-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCPSPglZ3 w/7DmCJxYohONLAAAAEAAAAAEAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz dHAyNTYAAABBBK6YY2NwwLDSMnJTD+a4OfitCDuG/MnY/AstPgh54xMrZF6Qr0U1H6kRMK diff --git a/test/Data/Key.OPENSSH.ECDSA.txt b/test/Data/Key.OPENSSH.ECDSA.txt index 94f16bcbd..c27521b4e 100644 --- a/test/Data/Key.OPENSSH.ECDSA.txt +++ b/test/Data/Key.OPENSSH.ECDSA.txt @@ -1,4 +1,4 @@ -锘-----BEGIN OPENSSH PRIVATE KEY----- +-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS 1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSP3ZTb37LFvSmKweu03A5s/cwcw3+3 jL1LqQK6D929xY1J2J6S91LXOBpBfz4l+8Ng7sWhu9P/hF/wmB2QRygrAAAAqMq583bKuf diff --git a/test/Data/Key.OPENSSH.ECDSA384.Encrypted.txt b/test/Data/Key.OPENSSH.ECDSA384.Encrypted.txt index 500654500..636ed56a2 100644 --- a/test/Data/Key.OPENSSH.ECDSA384.Encrypted.txt +++ b/test/Data/Key.OPENSSH.ECDSA384.Encrypted.txt @@ -1,4 +1,4 @@ -锘-----BEGIN OPENSSH PRIVATE KEY----- +-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAMZphcrt UKJMlSabtzt2GdAAAAEAAAAAEAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlz dHAzODQAAABhBFL5NEL9uRhgkF2q+8m58EvtZq4mDGgcVEzafPRuNIn1018m9KuqNpOQ6d diff --git a/test/Data/Key.OPENSSH.ECDSA384.txt b/test/Data/Key.OPENSSH.ECDSA384.txt index e5e6e06a9..5c30b2281 100644 --- a/test/Data/Key.OPENSSH.ECDSA384.txt +++ b/test/Data/Key.OPENSSH.ECDSA384.txt @@ -1,4 +1,4 @@ -锘-----BEGIN OPENSSH PRIVATE KEY----- +-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS 1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRTP1DMXoHgW+RX+S/NxUEElou1cmLD 6CEiR+zpzaGG6mzl6LhUY+Z3f2M3u4u7tcM8TgB/jiHbnI9TaeN5QK4HX1D9DXkH5RhfnL diff --git a/test/Data/Key.OPENSSH.ECDSA521.Encrypted.txt b/test/Data/Key.OPENSSH.ECDSA521.Encrypted.txt index da831cf9c..8c78b5a64 100644 --- a/test/Data/Key.OPENSSH.ECDSA521.Encrypted.txt +++ b/test/Data/Key.OPENSSH.ECDSA521.Encrypted.txt @@ -1,4 +1,4 @@ -锘-----BEGIN OPENSSH PRIVATE KEY----- +-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBWjIyzbM MQ3UPE8BiQ0n4LAAAAEAAAAAEAAACsAAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlz dHA1MjEAAACFBAH9BVM6bRhbELtgdMGsin5lM42R2EWoT+6Akakl5rQy2tHHLIYGLEfaqI diff --git a/test/Data/Key.OPENSSH.ECDSA521.txt b/test/Data/Key.OPENSSH.ECDSA521.txt index 0ad09eb24..96ab26a54 100644 --- a/test/Data/Key.OPENSSH.ECDSA521.txt +++ b/test/Data/Key.OPENSSH.ECDSA521.txt @@ -1,4 +1,4 @@ -锘-----BEGIN OPENSSH PRIVATE KEY----- +-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS 1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAa7p4WVga+08qu160BrdzKyRNJMQC eGhFluNdq73/uaW3qlqoEiaNtc5uB7HHyjCWQTmfzrSRLRZ7YBwUancwyh4Aq6gBgGsXVz diff --git a/test/Data/Key.OPENSSH.ED25519.Encrypted.txt b/test/Data/Key.OPENSSH.ED25519.Encrypted.txt index 50b4d9689..7fd7bad85 100644 --- a/test/Data/Key.OPENSSH.ED25519.Encrypted.txt +++ b/test/Data/Key.OPENSSH.ED25519.Encrypted.txt @@ -1,4 +1,4 @@ -锘-----BEGIN OPENSSH PRIVATE KEY----- +-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABBg HWh+J0IG6OfYxD74SoT9AAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIGFd yflleGqSPOhgSYZf7ZQFlG0zEL9VDGC69UbtaaByAAAAoDLm8u8wFwlqjzZRfVxj diff --git a/test/Data/Key.OPENSSH.ED25519.txt b/test/Data/Key.OPENSSH.ED25519.txt index 84811f653..488da8b52 100644 --- a/test/Data/Key.OPENSSH.ED25519.txt +++ b/test/Data/Key.OPENSSH.ED25519.txt @@ -1,4 +1,4 @@ -锘-----BEGIN OPENSSH PRIVATE KEY----- +-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz c2gtZWQyNTUxOQAAACANCWZw0K8UGXDQC32WBuyzwFtTGBBr1VuZ43uzpTBjIgAA AKBATgCiQE4AogAAAAtzc2gtZWQyNTUxOQAAACANCWZw0K8UGXDQC32WBuyzwFtT diff --git a/test/Data/Key.OPENSSH.RSA.Encrypted.txt b/test/Data/Key.OPENSSH.RSA.Encrypted.txt index b9eed58be..05f7a4409 100644 --- a/test/Data/Key.OPENSSH.RSA.Encrypted.txt +++ b/test/Data/Key.OPENSSH.RSA.Encrypted.txt @@ -1,4 +1,4 @@ -锘-----BEGIN OPENSSH PRIVATE KEY----- +-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCoWhCSaG psKT80oPIOAlqJAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQCxOfnmxC1g mmX18LCBG/X73BoCXQEBEAJz3V9w0FMTgUBebK3fkfOMLNzWn5aMR608wQHOEPYhHffCJf diff --git a/test/Data/Key.OPENSSH.RSA.txt b/test/Data/Key.OPENSSH.RSA.txt index 893001ebb..9586730eb 100644 --- a/test/Data/Key.OPENSSH.RSA.txt +++ b/test/Data/Key.OPENSSH.RSA.txt @@ -1,4 +1,4 @@ -锘-----BEGIN OPENSSH PRIVATE KEY----- +-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn NhAAAAAwEAAQAAAQEA7W7Oigi7Hj1msa2l8HimLPzagVmE/CseMKCRxPMTtWTvoZdMt7hf kthWA7h20a7oSSeH2t7FqeOpVNGFYvRV3BVWsKZJMRcdJiTCZAjH38rYk90XvZ3mKrKN/3 diff --git a/test/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt b/test/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt index cc017a909..c86a05726 100644 --- a/test/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt +++ b/test/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.txt @@ -1,4 +1,4 @@ -锘-----BEGIN RSA PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,AD7A2024C208E41F91C191B89AB9515A diff --git a/test/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt b/test/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt index 51e902101..41945ff22 100644 --- a/test/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt +++ b/test/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.txt @@ -1,4 +1,4 @@ -锘-----BEGIN RSA PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-192-CBC,0E34605476FC4C57886CE6350CD6F61E diff --git a/test/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt b/test/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt index cb31e913c..a26bdef3d 100644 --- a/test/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt +++ b/test/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.txt @@ -1,4 +1,4 @@ -锘-----BEGIN RSA PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-256-CBC,063DE67AE11456C89BCE9D4A21BE3DFB diff --git a/test/Data/Key.RSA.Encrypted.Des.CBC.12345.txt b/test/Data/Key.RSA.Encrypted.Des.CBC.12345.txt index 32734a07a..9ce0163d3 100644 --- a/test/Data/Key.RSA.Encrypted.Des.CBC.12345.txt +++ b/test/Data/Key.RSA.Encrypted.Des.CBC.12345.txt @@ -1,4 +1,4 @@ -锘-----BEGIN RSA PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-CBC,BD35E157CDD07CAD diff --git a/test/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt b/test/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt index aa9250a6d..a0f4b0e75 100644 --- a/test/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt +++ b/test/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.txt @@ -1,4 +1,4 @@ -锘-----BEGIN RSA PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,AF373EFF708479DF diff --git a/test/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt b/test/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt index 066d39fb3..8021cda6d 100644 --- a/test/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt +++ b/test/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.txt @@ -1,4 +1,4 @@ -锘-----BEGIN RSA PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CFB,81C75CC63A21DFFB diff --git a/test/Data/Key.RSA.txt b/test/Data/Key.RSA.txt index cf2cc9795..76971dfe2 100644 --- a/test/Data/Key.RSA.txt +++ b/test/Data/Key.RSA.txt @@ -1,4 +1,4 @@ -锘-----BEGIN RSA PRIVATE KEY----- +-----BEGIN RSA PRIVATE KEY----- MIIEoQIBAAKCAQEAuTtXn+BatX1oJuvhqfJZw5jc/pcIxJUPmuoFCH3+bXfKBJ/9 4ixNETzZBasyvT/ozboAbCG3qcJOYxf2BEeTAIXe1jLAoTd1GKCwMvZOyjnsPN95 /lChwfdnBbMzpZYTGfoUylXme/mzjjLu/J0qXgR5lyk9HFT+x5YEtRl8VSHiDkLK diff --git a/test/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt b/test/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt index 2a81a23d5..952b012f9 100644 --- a/test/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt +++ b/test/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.txt @@ -1,4 +1,4 @@ -锘---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ---- +---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ---- Comment: "imported-openssh-key" P2/56wAAA/MAAAA3aWYtbW9kbntzaWdue3JzYS1wa2NzMS1zaGExfSxlbmNyeXB0e3JzYS 1wa2NzMXYyLW9hZXB9fQAAAAgzZGVzLWNiYwAAA6A6Wt6IR5cz0PCsSJDOjcs3MdQscfdN diff --git a/test/Data/Key.SSH2.RSA.txt b/test/Data/Key.SSH2.RSA.txt index 04f9a3ce7..2de7f0f80 100644 --- a/test/Data/Key.SSH2.RSA.txt +++ b/test/Data/Key.SSH2.RSA.txt @@ -1,4 +1,4 @@ -锘---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ---- +---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ---- Comment: "imported-openssh-key" P2/56wAAA+4AAAA3aWYtbW9kbntzaWdue3JzYS1wa2NzMS1zaGExfSxlbmNyeXB0e3JzYS 1wa2NzMXYyLW9hZXB9fQAAAARub25lAAADnwAAA5sAAAARAQABAAAIAJoF62h2fdR02ncN From 60ba1dd090ec2b07d4e38d13967cd343e6298f42 Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Sat, 21 Oct 2023 17:04:20 +0200 Subject: [PATCH 60/96] Change the passphrase of Key.OPENSSH.ED25519.Encrypted to "12345" --- test/Data/Key.OPENSSH.ED25519.Encrypted.txt | 14 +++++++------- .../Classes/PrivateKeyFileTest.cs | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/Data/Key.OPENSSH.ED25519.Encrypted.txt b/test/Data/Key.OPENSSH.ED25519.Encrypted.txt index 7fd7bad85..1a3059c3a 100644 --- a/test/Data/Key.OPENSSH.ED25519.Encrypted.txt +++ b/test/Data/Key.OPENSSH.ED25519.Encrypted.txt @@ -1,9 +1,9 @@ -----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jYmMAAAAGYmNyeXB0AAAAGAAAABBg -HWh+J0IG6OfYxD74SoT9AAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIGFd -yflleGqSPOhgSYZf7ZQFlG0zEL9VDGC69UbtaaByAAAAoDLm8u8wFwlqjzZRfVxj -wzGTYFJFtfkHRqfFBE4xKgknHNRbCT1OQb7rgE7nZbUXIlb1NCTZLbXti9AYNZpz -ycvPD4Dc6lB03b8pNHoFVSkrCwxrWB5bKtIM4OZNcDK1lZDBEWE2aZXf9puRHbu3 -ccrK/F5GjRi2pUa8qnfqThN1mNPZwFTx4oSKeRaUMdeHBrNwDtaxq32A6Q4KHoYO -KPM= +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBo +8cgEId3kXTJ0Twaww5FdAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIGFd +yflleGqSPOhgSYZf7ZQFlG0zEL9VDGC69UbtaaByAAAAoGL3a75gsGjSetMX80al +sILhKOBvsS92PbIxrlqiG8bwqxOIPC9MHQCabSwrIKaKZkYp4wsJVLKnm/aQ+R+L +9enjT4TubBMbj2ULJ5ALyOMKnUfwtRh42RyXbBZOSEha610nYrBk83rI8iBNFEtl +BZdGeDg93HTLYGIz03rw3z0u2paW9HCETXi03hpHFSIpe9AsWs99Oi2iCqNJGFSh +rnc= -----END OPENSSH PRIVATE KEY----- diff --git a/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index 879dfa840..c536dc5c1 100644 --- a/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs +++ b/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs @@ -566,7 +566,7 @@ public void Test_PrivateKey_OPENSSH_ED25519_ENCRYPTED() { using (var stream = GetData("Key.OPENSSH.ED25519.Encrypted.txt")) { - _ = new PrivateKeyFile(stream, "password"); + _ = new PrivateKeyFile(stream, "12345"); } } From 9d6f3ef979f057caa1c6515e2825a830e27f4847 Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Sat, 21 Oct 2023 17:18:52 +0200 Subject: [PATCH 61/96] Normalize the OpenSSH files Change the data to be in 64-wide columns instead of 70, and add a newline at the end of the file. ssh-keygen does not like it otherwise. puttygen Key.OPENSSH.ECDSA.Encrypted.txt -O private-openssh-new -C Key.OPENSSH.ECDSA.Encrypted puttygen Key.OPENSSH.ECDSA.txt -O private-openssh-new -C Key.OPENSSH.ECDSA puttygen Key.OPENSSH.ECDSA384.Encrypted.txt -O private-openssh-new -C Key.OPENSSH.ECDSA384.Encrypted puttygen Key.OPENSSH.ECDSA384.txt -O private-openssh-new -C Key.OPENSSH.ECDSA384 puttygen Key.OPENSSH.ECDSA521.Encrypted.txt -O private-openssh-new -C Key.OPENSSH.ECDSA521.Encrypted puttygen Key.OPENSSH.ECDSA521.txt -O private-openssh-new -C Key.OPENSSH.ECDSA521 puttygen Key.OPENSSH.ED25519.Encrypted.txt -O private-openssh-new -C Key.OPENSSH.ED25519.Encrypted puttygen Key.OPENSSH.ED25519.txt -O private-openssh-new -C Key.OPENSSH.ED25519 puttygen Key.OPENSSH.RSA.Encrypted.txt -O private-openssh-new -C Key.OPENSSH.RSA.Encrypted puttygen Key.OPENSSH.RSA.txt -O private-openssh-new -C Key.OPENSSH.RSA (the -C flag changes the comment, otherwise puttygen refuses to do anything) --- test/Data/Key.OPENSSH.ECDSA.Encrypted.txt | 17 +++--- test/Data/Key.OPENSSH.ECDSA.txt | 16 +++--- test/Data/Key.OPENSSH.ECDSA384.Encrypted.txt | 21 ++++---- test/Data/Key.OPENSSH.ECDSA384.txt | 19 +++---- test/Data/Key.OPENSSH.ECDSA521.Encrypted.txt | 22 ++++---- test/Data/Key.OPENSSH.ECDSA521.txt | 23 ++++---- test/Data/Key.OPENSSH.ED25519.Encrypted.txt | 14 ++--- test/Data/Key.OPENSSH.ED25519.txt | 6 +-- test/Data/Key.OPENSSH.RSA.Encrypted.txt | 56 ++++++++++---------- test/Data/Key.OPENSSH.RSA.txt | 55 ++++++++++--------- 10 files changed, 130 insertions(+), 119 deletions(-) diff --git a/test/Data/Key.OPENSSH.ECDSA.Encrypted.txt b/test/Data/Key.OPENSSH.ECDSA.Encrypted.txt index 2de37354f..d2f158941 100644 --- a/test/Data/Key.OPENSSH.ECDSA.Encrypted.txt +++ b/test/Data/Key.OPENSSH.ECDSA.Encrypted.txt @@ -1,9 +1,10 @@ -----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCPSPglZ3 -w/7DmCJxYohONLAAAAEAAAAAEAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlz -dHAyNTYAAABBBK6YY2NwwLDSMnJTD+a4OfitCDuG/MnY/AstPgh54xMrZF6Qr0U1H6kRMK -Y6JJsj31CI97qDYrnTA00Sx5Jy6ywAAACwq4qisorVCP6yvrmf/fcPacX4+FVEmrHNn3fW -TiYsat7oKoItqTiDaHkIloSX93ue3fzcKXpGPR/qnpu4SezkhL9Uk6ntiwO4coB/kbEnjk -IFY6ZK0HENRXkdIuDG9qmoB0wjVPJ6L9e5RWZwiCPvNI2O60bpKOUs+tUSah1W7eTWy5Ss -ttdTgmwqS84c5+uitK1DJh2jsDqfdGm7h1XpDJsRmIEXxTVu/EdtD0hZ/x4= ------END OPENSSH PRIVATE KEY----- \ No newline at end of file +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCY +dyRpKP91m/llh14yqcTgAAAAEAAAAAEAAABoAAAAE2VjZHNhLXNoYTItbmlzdHAy +NTYAAAAIbmlzdHAyNTYAAABBBK6YY2NwwLDSMnJTD+a4OfitCDuG/MnY/AstPgh5 +4xMrZF6Qr0U1H6kRMKY6JJsj31CI97qDYrnTA00Sx5Jy6ywAAADAE2+HapLgUUft +e6Nl4XWsAEQdjicejaI1F1+ByHcpmd0Sudqd+P33KliXt48HKcygeqi86QVv3YOj +IpyXj5ndP6Luy7U5kMIJDyfWi1eRKouFfmektEp3KIktpSHO62NykMK6D1U5rzDo +7QRdKWUXaVU7P/OGPsaWL7T+/xDn7J/EZVhNrIuV71gyQifID1gbM8mGDdyAa8qd +peeYuVaKQt3qltAZsRN0q8WC0EHbxeh40hrvwWTAY+wKfGMxS5cf +-----END OPENSSH PRIVATE KEY----- diff --git a/test/Data/Key.OPENSSH.ECDSA.txt b/test/Data/Key.OPENSSH.ECDSA.txt index c27521b4e..d61dfead9 100644 --- a/test/Data/Key.OPENSSH.ECDSA.txt +++ b/test/Data/Key.OPENSSH.ECDSA.txt @@ -1,9 +1,9 @@ -----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS -1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSP3ZTb37LFvSmKweu03A5s/cwcw3+3 -jL1LqQK6D929xY1J2J6S91LXOBpBfz4l+8Ng7sWhu9P/hF/wmB2QRygrAAAAqMq583bKuf -N2AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBI/dlNvfssW9KYrB -67TcDmz9zBzDf7eMvUupAroP3b3FjUnYnpL3Utc4GkF/PiX7w2DuxaG70/+EX/CYHZBHKC -sAAAAhALVqID3K/N7IazKNbhrg09r7rLLtjy81RLV+VDxloQnxAAAAC3NyaW5rZXNATkVP -AQIDBA== ------END OPENSSH PRIVATE KEY----- \ No newline at end of file +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNl +Y2RzYS1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQSP3ZTb37LFvSmKweu0 +3A5s/cwcw3+3jL1LqQK6D929xY1J2J6S91LXOBpBfz4l+8Ng7sWhu9P/hF/wmB2Q +RygrAAAAsC+6dPMvunTzAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy +NTYAAABBBI/dlNvfssW9KYrB67TcDmz9zBzDf7eMvUupAroP3b3FjUnYnpL3Utc4 +GkF/PiX7w2DuxaG70/+EX/CYHZBHKCsAAAAhALVqID3K/N7IazKNbhrg09r7rLLt +jy81RLV+VDxloQnxAAAAEUtleS5PUEVOU1NILkVDRFNBAQIDBAUG +-----END OPENSSH PRIVATE KEY----- diff --git a/test/Data/Key.OPENSSH.ECDSA384.Encrypted.txt b/test/Data/Key.OPENSSH.ECDSA384.Encrypted.txt index 636ed56a2..5083342db 100644 --- a/test/Data/Key.OPENSSH.ECDSA384.Encrypted.txt +++ b/test/Data/Key.OPENSSH.ECDSA384.Encrypted.txt @@ -1,11 +1,12 @@ -----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAMZphcrt -UKJMlSabtzt2GdAAAAEAAAAAEAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlz -dHAzODQAAABhBFL5NEL9uRhgkF2q+8m58EvtZq4mDGgcVEzafPRuNIn1018m9KuqNpOQ6d -+435n+MRYThe4MUdijSIDuopX2i14Z35oKZ9x2LsV+RxQczjmbnoWZdvgcvdOo6jiJdY7X -JwAAAOBvXOaTq8vPRy7y5BBzr26QAYouJfGprYOqpywiIAZaICu0FJ8EXmmen6310CTG6Z -CZ4VhC5MWCWRYTaOnPNn8FvGqo2bxEqWZmyZfVvv1Z35MtSAZEfwgfXaOZKJ/lPKsRndg5 -okpqNU1aG2u+4J7eZ7QyCD/1RCCEL5wwVcrDeuMkTDPpnJc1NEGz8HbfcZ5xZavrz6Wa9t -tX7pFICqK9IIeOGMJ2WRXR6sQGyag+jNn9KmsIya7hkNJVeZeY2GKAk2s/0vxfYx9RFD55 -ewB34oHyTdxAQT3L+FZT6XfRHw== ------END OPENSSH PRIVATE KEY----- \ No newline at end of file +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAi +RxrKRE4zQH82w0Rd0v/ZAAAAEAAAAAEAAACIAAAAE2VjZHNhLXNoYTItbmlzdHAz +ODQAAAAIbmlzdHAzODQAAABhBFL5NEL9uRhgkF2q+8m58EvtZq4mDGgcVEzafPRu +NIn1018m9KuqNpOQ6d+435n+MRYThe4MUdijSIDuopX2i14Z35oKZ9x2LsV+RxQc +zjmbnoWZdvgcvdOo6jiJdY7XJwAAAPADDlLFKHgORBmNlg6LYOSdYyZFCVjmRbwm +j1X1qDSxgr48+OEJYr/nEfd6jMBKyS1mAHuvStxe1rA0PQMCrjyk/pmjbFQ6uEC4 +u31RHE9N0ZgKCgYLeT7s30ODh5TChmubbjdzHDXNYm3oKTGoaGYRBI6Yp+9+DFId +qEXVZzZV+w7dnPWh4L6YjBIoqnwlxW9XOSqizXOcjUbZrrZIA13rbYKVlCmVXlMW +SgWjbdg4+L/ijwZdO2O5XrcLmpU3rTa2wjlREE1fqH7Wm/qKMF28YF1Ytuus+XSr +BoU/lLWDW4BL1lyROGByxz3zYUpVgfo= +-----END OPENSSH PRIVATE KEY----- diff --git a/test/Data/Key.OPENSSH.ECDSA384.txt b/test/Data/Key.OPENSSH.ECDSA384.txt index 5c30b2281..620bd7ee3 100644 --- a/test/Data/Key.OPENSSH.ECDSA384.txt +++ b/test/Data/Key.OPENSSH.ECDSA384.txt @@ -1,10 +1,11 @@ -----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS -1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRTP1DMXoHgW+RX+S/NxUEElou1cmLD -6CEiR+zpzaGG6mzl6LhUY+Z3f2M3u4u7tcM8TgB/jiHbnI9TaeN5QK4HX1D9DXkH5RhfnL -frm3kCTNoCFKd0Wa/QAvKrlNKiRi8AAADYlABjHJQAYxwAAAATZWNkc2Etc2hhMi1uaXN0 -cDM4NAAAAAhuaXN0cDM4NAAAAGEEUz9QzF6B4FvkV/kvzcVBBJaLtXJiw+ghIkfs6c2hhu -ps5ei4VGPmd39jN7uLu7XDPE4Af44h25yPU2njeUCuB19Q/Q15B+UYX5y365t5AkzaAhSn -dFmv0ALyq5TSokYvAAAAMAXLUgK32yWzUrpeLzpdFB2/eiNnkxQlu5OneTPukKcZYclfgo -jv0YHK5LCvAtF8lwAAAAtzcmlua2VzQE5FTwECAwQF ------END OPENSSH PRIVATE KEY----- \ No newline at end of file +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNl +Y2RzYS1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQRTP1DMXoHgW+RX+S/N +xUEElou1cmLD6CEiR+zpzaGG6mzl6LhUY+Z3f2M3u4u7tcM8TgB/jiHbnI9TaeN5 +QK4HX1D9DXkH5RhfnLfrm3kCTNoCFKd0Wa/QAvKrlNKiRi8AAADgj+zzrY/s860A +AAATZWNkc2Etc2hhMi1uaXN0cDM4NAAAAAhuaXN0cDM4NAAAAGEEUz9QzF6B4Fvk +V/kvzcVBBJaLtXJiw+ghIkfs6c2hhups5ei4VGPmd39jN7uLu7XDPE4Af44h25yP +U2njeUCuB19Q/Q15B+UYX5y365t5AkzaAhSndFmv0ALyq5TSokYvAAAAMAXLUgK3 +2yWzUrpeLzpdFB2/eiNnkxQlu5OneTPukKcZYclfgojv0YHK5LCvAtF8lwAAABRL +ZXkuT1BFTlNTSC5FQ0RTQTM4NAECAwQ= +-----END OPENSSH PRIVATE KEY----- diff --git a/test/Data/Key.OPENSSH.ECDSA521.Encrypted.txt b/test/Data/Key.OPENSSH.ECDSA521.Encrypted.txt index 8c78b5a64..e87218820 100644 --- a/test/Data/Key.OPENSSH.ECDSA521.Encrypted.txt +++ b/test/Data/Key.OPENSSH.ECDSA521.Encrypted.txt @@ -1,12 +1,14 @@ -----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBWjIyzbM -MQ3UPE8BiQ0n4LAAAAEAAAAAEAAACsAAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlz -dHA1MjEAAACFBAH9BVM6bRhbELtgdMGsin5lM42R2EWoT+6Akakl5rQy2tHHLIYGLEfaqI -+0iUo2V6MxEf9w0hVz6SEsF+yDgyrYPQCIieaB1oBvIl+PZmL1XsuAXs2uMRsNJb4myGU/ -DiekxqzIPa0LMrBZ4xmErcn5Gazkw1EA0B3HoaW5wj+geI/efQAAARDi+GGTYH1T+5Dd8N -EVCiL+J7fm8uP8yAcvQNh3JBYIf1g/GZ0hJDuA47fcTzXEfTGZLGWdgaE8cxIUICpjBoak -EpNS1HyhqYZAt2J8o/14t2GbXczJfoQLOIQl2S1zXQ9shof12odu9DGcBhSAz9hswlndBE -d99uCz/ymzwQ0i2Pp+urUXo7+YXB6HMh9YTMeGQAiDJFO3NPDqDczfUECtTUkQMhy8r06m -hAp/oZ6K1KBbZzdc0xyqDePKAqqyHnN4FD7Wfv11SWoOhlUcEVg2ZvNj/O+CsoWzMpN+dt -DPKZHmH/kegWKBsdtAC9f5Hg3b2oQAK0pKghms1+/J9iilnIMwv80CPzGdv0YAG9Vx5w== +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCr +ps+rr4kkPvUVZfJpoR4GAAAAEAAAAAEAAACsAAAAE2VjZHNhLXNoYTItbmlzdHA1 +MjEAAAAIbmlzdHA1MjEAAACFBAH9BVM6bRhbELtgdMGsin5lM42R2EWoT+6Akakl +5rQy2tHHLIYGLEfaqI+0iUo2V6MxEf9w0hVz6SEsF+yDgyrYPQCIieaB1oBvIl+P +ZmL1XsuAXs2uMRsNJb4myGU/DiekxqzIPa0LMrBZ4xmErcn5Gazkw1EA0B3HoaW5 +wj+geI/efQAAASD6gdu6JHpiY92v0ED6YQ9FjYvjaRrIDUAbFv3jnuQ+sWsyaxTk +lSHI+4A/jxxIT/MMtNNLZiArZXD889BNA+mXrZIQ7i2DiYoLJWRHvmmPSxcGlHUF +PfwPwwPlK/nkR6NKuT7zP0daGMQYf8Njq727qpltkPmGQGDknN8tbX4RUOUGBPNh +UuRHRwqK3tHF5vDpUrJ09bsnClqGP6ufq3Zf+yb1r1tQK3uXadoE0wl8P8WZJRXo +JX8ngVVy6JMOiyAWZkTukKzVBAE1CMW8FOgX6ErqghqBD6s7YCxITXcyvwkWyQuc +oEr+BCLpwvXZ44CsOH96R+QevFz5ZI/dJx67Ccvdj2+8v5rECN4U8zpK7t5BYjla +hOkBkliF7QD8OmI= -----END OPENSSH PRIVATE KEY----- diff --git a/test/Data/Key.OPENSSH.ECDSA521.txt b/test/Data/Key.OPENSSH.ECDSA521.txt index 96ab26a54..85e3b07e5 100644 --- a/test/Data/Key.OPENSSH.ECDSA521.txt +++ b/test/Data/Key.OPENSSH.ECDSA521.txt @@ -1,12 +1,13 @@ -----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS -1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAa7p4WVga+08qu160BrdzKyRNJMQC -eGhFluNdq73/uaW3qlqoEiaNtc5uB7HHyjCWQTmfzrSRLRZ7YBwUancwyh4Aq6gBgGsXVz -wNvY3kxRDlGrSfMmsHlXz41dgw9wm1fBcf97niexRQ/xGlhkyf7IYlQ/s5BpXF2lS9l0H5 -hBippRgAAAEI/9prf//aa38AAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ -AAAIUEAGu6eFlYGvtPKrtetAa3cyskTSTEAnhoRZbjXau9/7mlt6paqBImjbXObgexx8ow -lkE5n860kS0We2AcFGp3MMoeAKuoAYBrF1c8Db2N5MUQ5Rq0nzJrB5V8+NXYMPcJtXwXH/ -e54nsUUP8RpYZMn+yGJUP7OQaVxdpUvZdB+YQYqaUYAAAAQXwQnI20tNxwLKHPMDmumblD -b0sBqW5Y9248L//x4sWFrkjk6k1LcZno9KLqz8+tIFMJ5sji+axRoUZCXb3cIPzPAAAAC3 -NyaW5rZXNATkVP ------END OPENSSH PRIVATE KEY----- \ No newline at end of file +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNl +Y2RzYS1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAa7p4WVga+08qu160 +BrdzKyRNJMQCeGhFluNdq73/uaW3qlqoEiaNtc5uB7HHyjCWQTmfzrSRLRZ7YBwU +ancwyh4Aq6gBgGsXVzwNvY3kxRDlGrSfMmsHlXz41dgw9wm1fBcf97niexRQ/xGl +hkyf7IYlQ/s5BpXF2lS9l0H5hBippRgAAAEgzPWTIsz1kyIAAAATZWNkc2Etc2hh +Mi1uaXN0cDUyMQAAAAhuaXN0cDUyMQAAAIUEAGu6eFlYGvtPKrtetAa3cyskTSTE +AnhoRZbjXau9/7mlt6paqBImjbXObgexx8owlkE5n860kS0We2AcFGp3MMoeAKuo +AYBrF1c8Db2N5MUQ5Rq0nzJrB5V8+NXYMPcJtXwXH/e54nsUUP8RpYZMn+yGJUP7 +OQaVxdpUvZdB+YQYqaUYAAAAQXwQnI20tNxwLKHPMDmumblDb0sBqW5Y9248L//x +4sWFrkjk6k1LcZno9KLqz8+tIFMJ5sji+axRoUZCXb3cIPzPAAAAFEtleS5PUEVO +U1NILkVDRFNBNTIxAQIDBAUGBwgJCgsMDQ4P +-----END OPENSSH PRIVATE KEY----- diff --git a/test/Data/Key.OPENSSH.ED25519.Encrypted.txt b/test/Data/Key.OPENSSH.ED25519.Encrypted.txt index 1a3059c3a..b0f4e4d78 100644 --- a/test/Data/Key.OPENSSH.ED25519.Encrypted.txt +++ b/test/Data/Key.OPENSSH.ED25519.Encrypted.txt @@ -1,9 +1,9 @@ -----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBo -8cgEId3kXTJ0Twaww5FdAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIGFd -yflleGqSPOhgSYZf7ZQFlG0zEL9VDGC69UbtaaByAAAAoGL3a75gsGjSetMX80al -sILhKOBvsS92PbIxrlqiG8bwqxOIPC9MHQCabSwrIKaKZkYp4wsJVLKnm/aQ+R+L -9enjT4TubBMbj2ULJ5ALyOMKnUfwtRh42RyXbBZOSEha610nYrBk83rI8iBNFEtl -BZdGeDg93HTLYGIz03rw3z0u2paW9HCETXi03hpHFSIpe9AsWs99Oi2iCqNJGFSh -rnc= +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABAb +LdF3aDTKufq+4lmfYt9wAAAAEAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIGFd +yflleGqSPOhgSYZf7ZQFlG0zEL9VDGC69UbtaaByAAAAsPooI5L5r84607ib9qOp +QLZYY2fVriZcZZ5TTnCj8rb3SkiZ+vS7Or+HjsAszKkvEO3We8OslmYoAUjuFJsc +D4IImAKZAO345IGBMELO71tUtpn9OGII5uyeINsnCiPz83My7mxNt1nJHluFTja5 +aoAqW30nnvwpJ2Dt82BITEmGsAmOkP9BqJNWL+p7jEEI0CXjKbzv/Sg7l7IraKJL +A1XoNHcjTXd5LGr1gYSD5LCe -----END OPENSSH PRIVATE KEY----- diff --git a/test/Data/Key.OPENSSH.ED25519.txt b/test/Data/Key.OPENSSH.ED25519.txt index 488da8b52..34cab676a 100644 --- a/test/Data/Key.OPENSSH.ED25519.txt +++ b/test/Data/Key.OPENSSH.ED25519.txt @@ -1,8 +1,8 @@ -----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtz c2gtZWQyNTUxOQAAACANCWZw0K8UGXDQC32WBuyzwFtTGBBr1VuZ43uzpTBjIgAA -AKBATgCiQE4AogAAAAtzc2gtZWQyNTUxOQAAACANCWZw0K8UGXDQC32WBuyzwFtT +AKCgIja8oCI2vAAAAAtzc2gtZWQyNTUxOQAAACANCWZw0K8UGXDQC32WBuyzwFtT GBBr1VuZ43uzpTBjIgAAAEAAzBF1MPUxrs+ycpJh28zzo/F3m6WcKO+orsSbR5Lw -KQ0JZnDQrxQZcNALfZYG7LPAW1MYEGvVW5nje7OlMGMiAAAAFGVkMjU1MTkta2V5 -LTIwMTgxMTI3AQIDBAUGBwgJ +KQ0JZnDQrxQZcNALfZYG7LPAW1MYEGvVW5nje7OlMGMiAAAAE0tleS5PUEVOU1NI +LkVEMjU1MTkBAgMEBQYHCAkK -----END OPENSSH PRIVATE KEY----- diff --git a/test/Data/Key.OPENSSH.RSA.Encrypted.txt b/test/Data/Key.OPENSSH.RSA.Encrypted.txt index 05f7a4409..62586de3e 100644 --- a/test/Data/Key.OPENSSH.RSA.Encrypted.txt +++ b/test/Data/Key.OPENSSH.RSA.Encrypted.txt @@ -1,28 +1,30 @@ -----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABCoWhCSaG -psKT80oPIOAlqJAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQCxOfnmxC1g -mmX18LCBG/X73BoCXQEBEAJz3V9w0FMTgUBebK3fkfOMLNzWn5aMR608wQHOEPYhHffCJf -dJR6lUWLHZz5+EZRfM9oHpysMtToYQoGtb9xM7D5J3lnWZgSea2R7xSeqpClN5nQUMGu8y -2d2S3g9o1vrTdeu71u09QFOx2AXBPUmCjpCuBlNyYEEQMfRMtQ6PDbPdvLM1uylbQqB+/6 -jMsCyEFvlLit9GcZ7ItKQN+jsZNmP+f7ytVXLsZTjPLd5mWWrf6T1T1Xt9DBoLXnMrmDiC -f/EXiTYonIO6B0FHvNUCrDzZ7rxIebqePLes1Q2yoUqmC8g+cww3AAADwNRNGSnB7cRpgU -BxdyC0ofj0hUONXjmoT+OGPph9lgZMUnzcon9Z1bpsJuMoRXL14Cdbds7YPmw1YB94Uc+S -8QexLJG0wGel2yvzJhU+QFsLeVRS4tayERFXGCoVpu7RunEYy+hvaiX5CD+luEkiarfj9I -N8+9QUMhDYkELwWBV4rde18Vr8m1P1FuFgqikY0TfSKUGCkvjl4FvDxrxqsewaEkkzwRTI -PhOFCCM5jBPWE+uWVcwKoidvAqcNbmwIzDNZGwXtrAvYYzZa62C/MNLHuFU1weuJiM8sYa -6iKrk681BrrpGcSEZEXd41CFY3BWlIDTozrWn03xFlIpeLG2YMPcuYqFhR/41BJfa+fW5B -Ei0SuUx2xjdRiamqpPku4H6ulkjl0KlFCr976Y2V1JZMQh7bd0huubmf4P4poBk6ZgGpSf -snhcv1HjCVkvfA2yhOcXogzK2HOZgDS5sdSb/kUGURdjlj6ccSzc3OYaHAy9gZXj8Q58pA -4KrXTDlCJ9BTR8PIND54j6gMKu5ijX0TP9nJf/hG9GXx+Xss8T3xdPxdNBapPCcuxGZGJN -H+KFqrpmZYHm0evqFPS7BCUp2VvID6SMgrTYiH0IIbMHLStfdNchtn3EudMbW9vRhxg3Do -npT7Px2JYp87PNoHg2eOx0yGy9r81n2+Wi7SpGCWD8MFfxqd4JIQ8+zjrIRAA1q53uuSUh -m/hlmJWEjQWmcBw5bKrOU0CfGGoT3o6HWYRQ9d5+kKeoS+dOINxxf80G5b7vOrE3PbFxT3 -W8zwRd90Msr3LXgPaN0V4RJeBX38e0EvVbArL2MgSs/BC5aID0N0Sqiu+13AqqNYxj6RH2 -FA7FN+BBa16fvdi5h5kNnZUrQUKOAImjEE494O8uGKQImviGqB5PY6DJqHPTtn7RSwFx9E -rR7nbAZPTucIN/OIfURxTedhROk0PXjWnwpjuz+UpaMRWqgWTv3bLOuqorqMLibAFLRQEQ -6pR0wbmTpTfEW1jNmAohxB4N14YdSfhThzkCAgpQW6UCLc83y3EDzQFi5862a+2ixULKhK -220tZRk2GU7OFAPRpgQ/sxptGqZbNdOV80wk1MgykoFkoptRkm7bfJcdLHZnP7E6yU0ssP -rCbQlfD0/dD2QE/7HqxHsipNNuEagULjK6WUYXkpx1Siq2vecjZw8dNp7EBh+KlujEm+Dr -R7KFdFCw8DUwrzXwfMIogeRVbW8H0/fQEqsX5oPLTEOnNBjzf8pHush7CCrprbo0ZK3xFp -Vr3LUCoA== ------END OPENSSH PRIVATE KEY----- \ No newline at end of file +b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBG +IAWU/wNbg8olz6BhAdPiAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAAB +AQCxOfnmxC1gmmX18LCBG/X73BoCXQEBEAJz3V9w0FMTgUBebK3fkfOMLNzWn5aM +R608wQHOEPYhHffCJfdJR6lUWLHZz5+EZRfM9oHpysMtToYQoGtb9xM7D5J3lnWZ +gSea2R7xSeqpClN5nQUMGu8y2d2S3g9o1vrTdeu71u09QFOx2AXBPUmCjpCuBlNy +YEEQMfRMtQ6PDbPdvLM1uylbQqB+/6jMsCyEFvlLit9GcZ7ItKQN+jsZNmP+f7yt +VXLsZTjPLd5mWWrf6T1T1Xt9DBoLXnMrmDiCf/EXiTYonIO6B0FHvNUCrDzZ7rxI +ebqePLes1Q2yoUqmC8g+cww3AAAD0FJlZT8ZlW/a4ZLCYzZw1XpWsoHxrrFkmO4C +bLYeMnpHge24Cx7vV5DT9L3GIPrKvHwDMn0a0fW3GNPRWWV6dCTNiN+YZYUFCJQT +TIFRQMqLqXOiAneDYOpGK739jp/v8joEPGirpnQ6kNW3dMgjgWsrYe8mMwqQ4Q/W +yFyYfEcZHK0/rKBs3pYKT5dH4EemCOnbxIGxf1FBp6++F9J4cIOFF7kDEsdaBZff +PHsxFheIEP7yeZM6IMchJQ4EbfXb61f62IHjRMfXkENzTDnMklxM3wgNLIgV9sXt +XDhYq/mVYrbts7sLKyFQvhM79GcDmxI+ZU7qPQ2cjuOtw734GAWsOmXyA/NUii9l +AjIZp2N/xDAUTypBNcsp7T0ijmTvJVlsVyKIPX4bzl2wPgJth4+IqgFftOUHDsVX +D6/+pu64rYG5g2YQOeL5Cs2kngqtFEVs2Kgz8i8C7Rse7Fkckfwg3bDXOjU/3GRR +XYfAgOCsOQ8sFbfnyuRqC55sW7Nc0BGEJ5aEliByF0gNnlAxrX6BJwO8EVQlP5GQ +dtN91F6TvdKgSJvshINKrr8D39JoK9MtjyeZ/t1mPZiRfwtjtd52T+BwKq+oM7HB +D/pgDlsdvHnTE2b7sGIq6MP8vMAXpuTcaTgvFj/lzhJ8193ufTwU1U6WJ5egSEkk +k8HXbaLo0g5vaBmpM6ImLJD7REgOEV3TWxKWDRscdZhcNTiDZMY6/1K0SoFjJQ1t +a3rzqS4lGaexsT2RlBdSAl7f0A6VHMRM9CNUJFogpjw6BzxTWXhJbRzgLPPxlity +sRMmdBVzV+O4l+Xht3eVrC2pk/qGytlmlWku2Wto+mHA/FUj7NdEBElevgHeXjhL +fKHsumP7Wr1P5KYFOFBnZqNvHU1CmQ4vm3/YEyClhJNzvMFou80i1ll4rBTnLozV +jDbIy5An8qFmB566CdHg/iGbdq85iL4ae8PrFb9Qc5mCJf8OCmNeeYu4f3yCeXZu +TjCVJHwx7wVEegS2MZbLWDL1Jds0d7kx0h24zn8QI0EdZrugQc3gZxpbLmmua5Kd +XWJw4zqaFFP9QU+OLVDBAn+RFF/rj6aHa18v6Udyulj5mGaSDANv3JcAHxy7QVZ2 +Kc3qlD49SKL8H6zj1ozeh0M2J5GRHEPS1DUmauW+Qkl8admEsctunjbbNMjCRc5J +M1U8tI5NyPAihovpIRMnz8yhuFgcL9jLREokw/eNNRpayWSwKfLKdn2/DC2ZLx2n +CgP5dGDweT48SE9BveF0SfO2/6c/9QxkYEvA8YFWRB4Bd/NtiL0= +-----END OPENSSH PRIVATE KEY----- diff --git a/test/Data/Key.OPENSSH.RSA.txt b/test/Data/Key.OPENSSH.RSA.txt index 9586730eb..ac60a2ff0 100644 --- a/test/Data/Key.OPENSSH.RSA.txt +++ b/test/Data/Key.OPENSSH.RSA.txt @@ -1,27 +1,30 @@ -----BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn -NhAAAAAwEAAQAAAQEA7W7Oigi7Hj1msa2l8HimLPzagVmE/CseMKCRxPMTtWTvoZdMt7hf -kthWA7h20a7oSSeH2t7FqeOpVNGFYvRV3BVWsKZJMRcdJiTCZAjH38rYk90XvZ3mKrKN/3 -fcQsh4OiPnWqT6HSqg14oiV8UPtUwnE65skWSxvxt+ELlVpCqG5vE2O/GNDKQE7FzYt6vQ -ihMFSABBqjvau0mjX002KYiCMr6vgl8XYkDA4n5+JyQSQxznnfrL93ZoaqujRP2bT5UhXg -bzr8HFwuqQGvURECZTTI8Biv/6tOIn9x2hEaN6vxDLtXc99E2d6NW6cdriwaGFJ4jgVWDE -5mU006XdPQAAA8jzN6zf8zes3wAAAAdzc2gtcnNhAAABAQDtbs6KCLsePWaxraXweKYs/N -qBWYT8Kx4woJHE8xO1ZO+hl0y3uF+S2FYDuHbRruhJJ4fa3sWp46lU0YVi9FXcFVawpkkx -Fx0mJMJkCMffytiT3Re9neYqso3/d9xCyHg6I+dapPodKqDXiiJXxQ+1TCcTrmyRZLG/G3 -4QuVWkKobm8TY78Y0MpATsXNi3q9CKEwVIAEGqO9q7SaNfTTYpiIIyvq+CXxdiQMDifn4n -JBJDHOed+sv3dmhqq6NE/ZtPlSFeBvOvwcXC6pAa9REQJlNMjwGK//q04if3HaERo3q/EM -u1dz30TZ3o1bpx2uLBoYUniOBVYMTmZTTTpd09AAAAAwEAAQAAAQEA6Xgq+gppzOt9nrts -z5Ajf1tHlSesn7XaYuCRVgPb3mOZSuEW3BUdTa0Sr2fk1nzSBpUrfqnN3idyK2g3bD1sbB -RDgUKR+AaNcCN3TpxfxgyVeJhQLvEkEdovzQRUfwrXRfxmE3jkRGfVbvxylrG8p35xcmXy -del46r2i8dj8gIY3tKp0RMvZ4ZlNbhWHPd5OxyHWL9e3gbOSyIyjQgTKZezhzErS/X/KJ/ -XYqzyBAqNqZ2Rg1kKiHRlHS6KEI2tyFwYfh+Rb6L9xch1SqOtQhTWirmxS25dpGD2jgalX -eyiw8PmuqTiWCqUmUMx6MdF3tFsirr54K4QA9kqMeaRLtQAAAIEAsUQT0Uhq7l0ugTd4Y9 -89bH6eW0fol21/m7B5zkJQepNadUPTs188uvv4inW8n2O3RCanXWHZfCJ1AsR/MEEW2C6Q -DtvqKXHbzfWQlCYSVxB17CjURKa8fNaIAk98zgmNNwO53NBleyrUhPgvm3xt7ACgpzXY5R -wNJL8/a0WOmgwAAACBAP508Op6wWPAwn1JfBZuqQtjcfnJeN4NkYQBdybn0vVu5UdyqSQL -a8hlAzROhA+qJvrlsZgM9h8CyLTyuim8likZHocwO13zBTdVaQ8c2lJvf2uXTIXNZHseS7 -ITkfBiO1hSB4z8RDkOr35mGfdbyJIFAwFZF4Xs8WnQF+vHEadrAAAAgQDu329eCwVFf9g0 -zNHfZu31p0WtErcsRv57fq+UoPtov8nxUF71oOWe5KSGnGtMICI31kBtPhUbvfOmuqNrgJ -BjgjbPQmi0xSAE5L3QuEKRNjlaE3/WadKBwzhJDtauuYk1ifkrdAVp67XyQ5puyuGgVaQB -NPbrxA9g1IbyeL4/9wAAAAtzcmlua2VzQE5FTwECAwQFBg== ------END OPENSSH PRIVATE KEY----- \ No newline at end of file +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdz +c2gtcnNhAAAAAwEAAQAAAQEA7W7Oigi7Hj1msa2l8HimLPzagVmE/CseMKCRxPMT +tWTvoZdMt7hfkthWA7h20a7oSSeH2t7FqeOpVNGFYvRV3BVWsKZJMRcdJiTCZAjH +38rYk90XvZ3mKrKN/3fcQsh4OiPnWqT6HSqg14oiV8UPtUwnE65skWSxvxt+ELlV +pCqG5vE2O/GNDKQE7FzYt6vQihMFSABBqjvau0mjX002KYiCMr6vgl8XYkDA4n5+ +JyQSQxznnfrL93ZoaqujRP2bT5UhXgbzr8HFwuqQGvURECZTTI8Biv/6tOIn9x2h +EaN6vxDLtXc99E2d6NW6cdriwaGFJ4jgVWDE5mU006XdPQAAA9DGPmJsxj5ibAAA +AAdzc2gtcnNhAAABAQDtbs6KCLsePWaxraXweKYs/NqBWYT8Kx4woJHE8xO1ZO+h +l0y3uF+S2FYDuHbRruhJJ4fa3sWp46lU0YVi9FXcFVawpkkxFx0mJMJkCMffytiT +3Re9neYqso3/d9xCyHg6I+dapPodKqDXiiJXxQ+1TCcTrmyRZLG/G34QuVWkKobm +8TY78Y0MpATsXNi3q9CKEwVIAEGqO9q7SaNfTTYpiIIyvq+CXxdiQMDifn4nJBJD +HOed+sv3dmhqq6NE/ZtPlSFeBvOvwcXC6pAa9REQJlNMjwGK//q04if3HaERo3q/ +EMu1dz30TZ3o1bpx2uLBoYUniOBVYMTmZTTTpd09AAAAAwEAAQAAAQEA6Xgq+gpp +zOt9nrtsz5Ajf1tHlSesn7XaYuCRVgPb3mOZSuEW3BUdTa0Sr2fk1nzSBpUrfqnN +3idyK2g3bD1sbBRDgUKR+AaNcCN3TpxfxgyVeJhQLvEkEdovzQRUfwrXRfxmE3jk +RGfVbvxylrG8p35xcmXydel46r2i8dj8gIY3tKp0RMvZ4ZlNbhWHPd5OxyHWL9e3 +gbOSyIyjQgTKZezhzErS/X/KJ/XYqzyBAqNqZ2Rg1kKiHRlHS6KEI2tyFwYfh+Rb +6L9xch1SqOtQhTWirmxS25dpGD2jgalXeyiw8PmuqTiWCqUmUMx6MdF3tFsirr54 +K4QA9kqMeaRLtQAAAIEAsUQT0Uhq7l0ugTd4Y989bH6eW0fol21/m7B5zkJQepNa +dUPTs188uvv4inW8n2O3RCanXWHZfCJ1AsR/MEEW2C6QDtvqKXHbzfWQlCYSVxB1 +7CjURKa8fNaIAk98zgmNNwO53NBleyrUhPgvm3xt7ACgpzXY5RwNJL8/a0WOmgwA +AACBAP508Op6wWPAwn1JfBZuqQtjcfnJeN4NkYQBdybn0vVu5UdyqSQLa8hlAzRO +hA+qJvrlsZgM9h8CyLTyuim8likZHocwO13zBTdVaQ8c2lJvf2uXTIXNZHseS7IT +kfBiO1hSB4z8RDkOr35mGfdbyJIFAwFZF4Xs8WnQF+vHEadrAAAAgQDu329eCwVF +f9g0zNHfZu31p0WtErcsRv57fq+UoPtov8nxUF71oOWe5KSGnGtMICI31kBtPhUb +vfOmuqNrgJBjgjbPQmi0xSAE5L3QuEKRNjlaE3/WadKBwzhJDtauuYk1ifkrdAVp +67XyQ5puyuGgVaQBNPbrxA9g1IbyeL4/9wAAAA9LZXkuT1BFTlNTSC5SU0EBAgME +BQYHCAkK +-----END OPENSSH PRIVATE KEY----- From d36e7f552d0ed596e8803370d4acdb3fadcac85e Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Sat, 21 Oct 2023 17:25:26 +0200 Subject: [PATCH 62/96] Add OpenSSH public key files Generated with puttygen Key.OPENSSH.ECDSA.Encrypted.txt -o Key.OPENSSH.ECDSA.Encrypted.pub -O public-openssh puttygen Key.OPENSSH.ECDSA.txt -o Key.OPENSSH.ECDSA.pub -O public-openssh puttygen Key.OPENSSH.ECDSA384.Encrypted.txt -o Key.OPENSSH.ECDSA384.Encrypted.pub -O public-openssh puttygen Key.OPENSSH.ECDSA384.txt -o Key.OPENSSH.ECDSA384.pub -O public-openssh puttygen Key.OPENSSH.ECDSA521.Encrypted.txt -o Key.OPENSSH.ECDSA521.Encrypted.pub -O public-openssh puttygen Key.OPENSSH.ECDSA521.txt -o Key.OPENSSH.ECDSA521.pub -O public-openssh puttygen Key.OPENSSH.ED25519.Encrypted.txt -o Key.OPENSSH.ED25519.Encrypted.pub -O public-openssh puttygen Key.OPENSSH.ED25519.txt -o Key.OPENSSH.ED25519.pub -O public-openssh puttygen Key.OPENSSH.RSA.Encrypted.txt -o Key.OPENSSH.RSA.Encrypted.pub -O public-openssh puttygen Key.OPENSSH.RSA.txt -o Key.OPENSSH.RSA.pub -O public-openssh and so forth. Some whose ciphers are unsupported by puttygen were generated with e.g. sudo ssh-keygen -f Key.RSA.Encrypted.Des.CBC.12345.txt -y > Key.RSA.Encrypted.Des.CBC.12345.pub --- test/Data/Key.ECDSA.Encrypted.pub | 1 + test/Data/Key.ECDSA.pub | 1 + test/Data/Key.ECDSA384.Encrypted.pub | 1 + test/Data/Key.ECDSA384.pub | 1 + test/Data/Key.ECDSA521.Encrypted.pub | 1 + test/Data/Key.ECDSA521.pub | 1 + test/Data/Key.OPENSSH.ECDSA.Encrypted.pub | 1 + test/Data/Key.OPENSSH.ECDSA.pub | 1 + test/Data/Key.OPENSSH.ECDSA384.Encrypted.pub | 1 + test/Data/Key.OPENSSH.ECDSA384.pub | 1 + test/Data/Key.OPENSSH.ECDSA521.Encrypted.pub | 1 + test/Data/Key.OPENSSH.ECDSA521.pub | 1 + test/Data/Key.OPENSSH.ED25519.Encrypted.pub | 1 + test/Data/Key.OPENSSH.ED25519.pub | 1 + test/Data/Key.OPENSSH.RSA.Encrypted.pub | 1 + test/Data/Key.OPENSSH.RSA.pub | 1 + .../Key.RSA.Encrypted.Aes.128.CBC.12345.pub | 1 + .../Key.RSA.Encrypted.Aes.192.CBC.12345.pub | 1 + .../Key.RSA.Encrypted.Aes.256.CBC.12345.pub | 1 + test/Data/Key.RSA.Encrypted.Des.CBC.12345.pub | 1 + .../Key.RSA.Encrypted.Des.Ede3.CBC.12345.pub | 1 + ...ey.RSA.Encrypted.Des.Ede3.CFB.1234567890.pub | 1 + test/Data/Key.RSA.pub | 1 + .../Key.SSH2.DSA.Encrypted.Des.CBC.12345.pub | 1 + test/Data/Key.SSH2.DSA.pub | 1 + .../Key.SSH2.RSA.Encrypted.Des.CBC.12345.pub | 1 + test/Data/Key.SSH2.RSA.pub | 1 + .../Renci.SshNet.Benchmarks.csproj | 2 +- .../Renci.SshNet.Tests.csproj | 17 +---------------- 29 files changed, 29 insertions(+), 17 deletions(-) create mode 100644 test/Data/Key.ECDSA.Encrypted.pub create mode 100644 test/Data/Key.ECDSA.pub create mode 100644 test/Data/Key.ECDSA384.Encrypted.pub create mode 100644 test/Data/Key.ECDSA384.pub create mode 100644 test/Data/Key.ECDSA521.Encrypted.pub create mode 100644 test/Data/Key.ECDSA521.pub create mode 100644 test/Data/Key.OPENSSH.ECDSA.Encrypted.pub create mode 100644 test/Data/Key.OPENSSH.ECDSA.pub create mode 100644 test/Data/Key.OPENSSH.ECDSA384.Encrypted.pub create mode 100644 test/Data/Key.OPENSSH.ECDSA384.pub create mode 100644 test/Data/Key.OPENSSH.ECDSA521.Encrypted.pub create mode 100644 test/Data/Key.OPENSSH.ECDSA521.pub create mode 100644 test/Data/Key.OPENSSH.ED25519.Encrypted.pub create mode 100644 test/Data/Key.OPENSSH.ED25519.pub create mode 100644 test/Data/Key.OPENSSH.RSA.Encrypted.pub create mode 100644 test/Data/Key.OPENSSH.RSA.pub create mode 100644 test/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.pub create mode 100644 test/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.pub create mode 100644 test/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.pub create mode 100644 test/Data/Key.RSA.Encrypted.Des.CBC.12345.pub create mode 100644 test/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.pub create mode 100644 test/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.pub create mode 100644 test/Data/Key.RSA.pub create mode 100644 test/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.pub create mode 100644 test/Data/Key.SSH2.DSA.pub create mode 100644 test/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.pub create mode 100644 test/Data/Key.SSH2.RSA.pub diff --git a/test/Data/Key.ECDSA.Encrypted.pub b/test/Data/Key.ECDSA.Encrypted.pub new file mode 100644 index 000000000..17df3f932 --- /dev/null +++ b/test/Data/Key.ECDSA.Encrypted.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOwUDIZhrxd1VJ7ByUuB25kdZlU0iCl/vru8VZcwmd0ROMLe0FruHkhG54JWTKcOxOOA1ITzEVXVTMpgN9ruRLs= imported-openssh-key diff --git a/test/Data/Key.ECDSA.pub b/test/Data/Key.ECDSA.pub new file mode 100644 index 000000000..61919aa53 --- /dev/null +++ b/test/Data/Key.ECDSA.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEA+TDv5/cqkg07M8M1aQKS8eUkBXnBOWXw5IMalXR0HnJtQQD6M2eHihjYSp+9oU+/Zi5afR11/qDRHLlU/Nx8= imported-openssh-key diff --git a/test/Data/Key.ECDSA384.Encrypted.pub b/test/Data/Key.ECDSA384.Encrypted.pub new file mode 100644 index 000000000..5131ee4c8 --- /dev/null +++ b/test/Data/Key.ECDSA384.Encrypted.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBAKCegTbmw9KKkPpn6qMsTmPMp9yCr+xOyrRgQOFaToNzFq57mT1jxfIXRL0wyAgINVGNTyHpS2sMalvOYD2lKQkD/i3SlgQXXiGx9yopulY07Q1n2pNk1g8ay4k4Yt24Q== imported-openssh-key diff --git a/test/Data/Key.ECDSA384.pub b/test/Data/Key.ECDSA384.pub new file mode 100644 index 000000000..1253fba19 --- /dev/null +++ b/test/Data/Key.ECDSA384.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBBSTitW+g48jWFDNak3HT1Sjqob6ysZxu8GrXl4UrQacr9PRQErF1tnb7/8oBgjpJ4Mcz23c5EXVpfkSmNMQEjh3tlj+VX2Nfoycnhe4a14mx6UzaIybL6n1ljDzcFgHVg== imported-openssh-key diff --git a/test/Data/Key.ECDSA521.Encrypted.pub b/test/Data/Key.ECDSA521.Encrypted.pub new file mode 100644 index 000000000..6e85066c4 --- /dev/null +++ b/test/Data/Key.ECDSA521.Encrypted.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACwzN70vaXBOSasttYWPYsPTwe4aQWx86wSig5xddvJXwX0Wzg0KYRkF5f2wJbk59JufZVaLcQpOQ/kN/2EOHVzhgA1V1BcBFbmoKSnMMwx/pQUVOu54tPC3CTAIN1CeG9UaBWcz44YXmSRQM5vz4OzZnzVFusFvY6+fnldTeNgQYqz9g== imported-openssh-key diff --git a/test/Data/Key.ECDSA521.pub b/test/Data/Key.ECDSA521.pub new file mode 100644 index 000000000..5d1ba5185 --- /dev/null +++ b/test/Data/Key.ECDSA521.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBABrpVjsANqcvqMUo1wo0I1uVCXQ6xrauy4iU86FiOwFmkYRrle4w3oYdRJwniC3TwGMuBuMPMIoCTXr0UtUzn1vkQESNR/J/jAxVseLlVe+KDfZHKvsvk2+O4XaSa1qMfLwN3spwlj08+ylKjlO6V3g0hbz4ZaSVwuiRS7Xsv8W2MV6rg== imported-openssh-key diff --git a/test/Data/Key.OPENSSH.ECDSA.Encrypted.pub b/test/Data/Key.OPENSSH.ECDSA.Encrypted.pub new file mode 100644 index 000000000..30e33d96b --- /dev/null +++ b/test/Data/Key.OPENSSH.ECDSA.Encrypted.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK6YY2NwwLDSMnJTD+a4OfitCDuG/MnY/AstPgh54xMrZF6Qr0U1H6kRMKY6JJsj31CI97qDYrnTA00Sx5Jy6yw= Key.OPENSSH.ECDSA.Encrypted diff --git a/test/Data/Key.OPENSSH.ECDSA.pub b/test/Data/Key.OPENSSH.ECDSA.pub new file mode 100644 index 000000000..f0398673c --- /dev/null +++ b/test/Data/Key.OPENSSH.ECDSA.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBI/dlNvfssW9KYrB67TcDmz9zBzDf7eMvUupAroP3b3FjUnYnpL3Utc4GkF/PiX7w2DuxaG70/+EX/CYHZBHKCs= Key.OPENSSH.ECDSA diff --git a/test/Data/Key.OPENSSH.ECDSA384.Encrypted.pub b/test/Data/Key.OPENSSH.ECDSA384.Encrypted.pub new file mode 100644 index 000000000..2ca7e4d3f --- /dev/null +++ b/test/Data/Key.OPENSSH.ECDSA384.Encrypted.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFL5NEL9uRhgkF2q+8m58EvtZq4mDGgcVEzafPRuNIn1018m9KuqNpOQ6d+435n+MRYThe4MUdijSIDuopX2i14Z35oKZ9x2LsV+RxQczjmbnoWZdvgcvdOo6jiJdY7XJw== Key.OPENSSH.ECDSA384.Encrypted diff --git a/test/Data/Key.OPENSSH.ECDSA384.pub b/test/Data/Key.OPENSSH.ECDSA384.pub new file mode 100644 index 000000000..33a0bcab6 --- /dev/null +++ b/test/Data/Key.OPENSSH.ECDSA384.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFM/UMxegeBb5Ff5L83FQQSWi7VyYsPoISJH7OnNoYbqbOXouFRj5nd/Yze7i7u1wzxOAH+OIducj1Np43lArgdfUP0NeQflGF+ct+ubeQJM2gIUp3RZr9AC8quU0qJGLw== Key.OPENSSH.ECDSA384 diff --git a/test/Data/Key.OPENSSH.ECDSA521.Encrypted.pub b/test/Data/Key.OPENSSH.ECDSA521.Encrypted.pub new file mode 100644 index 000000000..1dcc63771 --- /dev/null +++ b/test/Data/Key.OPENSSH.ECDSA521.Encrypted.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAH9BVM6bRhbELtgdMGsin5lM42R2EWoT+6Akakl5rQy2tHHLIYGLEfaqI+0iUo2V6MxEf9w0hVz6SEsF+yDgyrYPQCIieaB1oBvIl+PZmL1XsuAXs2uMRsNJb4myGU/DiekxqzIPa0LMrBZ4xmErcn5Gazkw1EA0B3HoaW5wj+geI/efQ== Key.OPENSSH.ECDSA521.Encrypted diff --git a/test/Data/Key.OPENSSH.ECDSA521.pub b/test/Data/Key.OPENSSH.ECDSA521.pub new file mode 100644 index 000000000..8db24c3ba --- /dev/null +++ b/test/Data/Key.OPENSSH.ECDSA521.pub @@ -0,0 +1 @@ +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBABrunhZWBr7Tyq7XrQGt3MrJE0kxAJ4aEWW412rvf+5pbeqWqgSJo21zm4HscfKMJZBOZ/OtJEtFntgHBRqdzDKHgCrqAGAaxdXPA29jeTFEOUatJ8yaweVfPjV2DD3CbV8Fx/3ueJ7FFD/EaWGTJ/shiVD+zkGlcXaVL2XQfmEGKmlGA== Key.OPENSSH.ECDSA521 diff --git a/test/Data/Key.OPENSSH.ED25519.Encrypted.pub b/test/Data/Key.OPENSSH.ED25519.Encrypted.pub new file mode 100644 index 000000000..62327be27 --- /dev/null +++ b/test/Data/Key.OPENSSH.ED25519.Encrypted.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGFdyflleGqSPOhgSYZf7ZQFlG0zEL9VDGC69UbtaaBy Key.OPENSSH.ED25519.Encrypted diff --git a/test/Data/Key.OPENSSH.ED25519.pub b/test/Data/Key.OPENSSH.ED25519.pub new file mode 100644 index 000000000..a4c452e63 --- /dev/null +++ b/test/Data/Key.OPENSSH.ED25519.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA0JZnDQrxQZcNALfZYG7LPAW1MYEGvVW5nje7OlMGMi Key.OPENSSH.ED25519 diff --git a/test/Data/Key.OPENSSH.RSA.Encrypted.pub b/test/Data/Key.OPENSSH.RSA.Encrypted.pub new file mode 100644 index 000000000..a4479683d --- /dev/null +++ b/test/Data/Key.OPENSSH.RSA.Encrypted.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCxOfnmxC1gmmX18LCBG/X73BoCXQEBEAJz3V9w0FMTgUBebK3fkfOMLNzWn5aMR608wQHOEPYhHffCJfdJR6lUWLHZz5+EZRfM9oHpysMtToYQoGtb9xM7D5J3lnWZgSea2R7xSeqpClN5nQUMGu8y2d2S3g9o1vrTdeu71u09QFOx2AXBPUmCjpCuBlNyYEEQMfRMtQ6PDbPdvLM1uylbQqB+/6jMsCyEFvlLit9GcZ7ItKQN+jsZNmP+f7ytVXLsZTjPLd5mWWrf6T1T1Xt9DBoLXnMrmDiCf/EXiTYonIO6B0FHvNUCrDzZ7rxIebqePLes1Q2yoUqmC8g+cww3 Key.OPENSSH.RSA.Encrypted diff --git a/test/Data/Key.OPENSSH.RSA.pub b/test/Data/Key.OPENSSH.RSA.pub new file mode 100644 index 000000000..3e77649c4 --- /dev/null +++ b/test/Data/Key.OPENSSH.RSA.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDtbs6KCLsePWaxraXweKYs/NqBWYT8Kx4woJHE8xO1ZO+hl0y3uF+S2FYDuHbRruhJJ4fa3sWp46lU0YVi9FXcFVawpkkxFx0mJMJkCMffytiT3Re9neYqso3/d9xCyHg6I+dapPodKqDXiiJXxQ+1TCcTrmyRZLG/G34QuVWkKobm8TY78Y0MpATsXNi3q9CKEwVIAEGqO9q7SaNfTTYpiIIyvq+CXxdiQMDifn4nJBJDHOed+sv3dmhqq6NE/ZtPlSFeBvOvwcXC6pAa9REQJlNMjwGK//q04if3HaERo3q/EMu1dz30TZ3o1bpx2uLBoYUniOBVYMTmZTTTpd09 Key.OPENSSH.RSA diff --git a/test/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.pub b/test/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.pub new file mode 100644 index 000000000..2147fb08a --- /dev/null +++ b/test/Data/Key.RSA.Encrypted.Aes.128.CBC.12345.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCha/vKqT3Nf07l0b/7A5BtSdTy+WnCt9z8QVMq85RjgYc4n3cCh0tEmyE3EjR9Bmc9bBIR2wWUHnLc2gmDXe4Y1YGKQyWCPTVnPPpBN+eama+BYPbfQDn8wRNsEghtc2TgXH2Oj28yGnGf7JM46rSCsyJwx9doEvrFptQGiAdXCk6aLnRzFhC4reVe9iBi1y1A4T5mVkljjwdVRpIMZYshHEi8mc/mvV+f7t9aXG33WZ+r6rGUT4cs6hpcxyg8AStnlpwYuLApeX6I/1rqGLktJCPGFeFAJS+Oy/I1sK7IgvKqSMSikKRT5hKoBra4EHRspe4giqRQFf402jfr4EKr imported-openssh-key diff --git a/test/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.pub b/test/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.pub new file mode 100644 index 000000000..4fc4b25c0 --- /dev/null +++ b/test/Data/Key.RSA.Encrypted.Aes.192.CBC.12345.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4nJsl4i410AyFpLbh7AWSq+X+q6lbRSUW8XqhSb6b2AClQ7pBkwPm2/VL1Jk3+d1itzChHAQgQWjt0E9uh/BL/Rz0fHXqzrbOn1Yuwq0N9ZMsIss8ue6q2Txi8tn2qBIhhB37MZcOZYH2Vp4+kLf5SmqOr/0/Iyz4H77NnJz9H8VWNnmIC/lVmFnpdrzCkn5RzKrlfZElrQPfYXMwM6ivKoB3j5S5EThn0RAyLpGJsD2nB+/0bLbPyvIa+EEzzfsIBvO9Q9ULWPEBGJdSLsz++NvNGay40uVT7PDsUB59n/vsT1/gZ+kbl6gneM+qnhTxZUFzxtDqJXx9dXwymZqz diff --git a/test/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.pub b/test/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.pub new file mode 100644 index 000000000..8b041597f --- /dev/null +++ b/test/Data/Key.RSA.Encrypted.Aes.256.CBC.12345.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6KpJwRX4HfoFimrRTxqHsyAoPgMD+dm2/6NjIZiy2CPuNGfci+EKjSmdQHhqM8jlhBKhSiAnsEuW46WGlCzpQm2uSA1hFCz/pdExNw9onfY2hdJwOrFlDO9rOcedeZhSQ5gDW/c/MreQQDgEST8tBBM8Yuuk9h6763+Cbd7TAvOskfmx9RXRMeFaqYOe8uVvNQDAYKlcfhjRESfkDtUvJSUyjZYkKR0wnm9fFGL6K/jQrbDYG75wEyB6+bSPHl3ZLakjHJiNOXVlOgJVk9Gw147hLPd+zxyE4eJV5J7rQv96QUWouYPFcMD4EfginfkIbNg02A5onkjTTVUBnIK31 diff --git a/test/Data/Key.RSA.Encrypted.Des.CBC.12345.pub b/test/Data/Key.RSA.Encrypted.Des.CBC.12345.pub new file mode 100644 index 000000000..0c98bc9f0 --- /dev/null +++ b/test/Data/Key.RSA.Encrypted.Des.CBC.12345.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCs7PAiYUZLgiAKPJpJ62JFBrE1d4lfG0w5vbTkMuwJvYmvWyBPU+Hc7jXxgK1iqsz/s0wDZutENyE9VBilTHAYDBOauXjSfQwlo7zHmK1HZ7h87jcIhltpY0NzBGmd/lQ+yDeXiSFGGoFyjwW6VpOfs0AR+oLA2Hpy4b9lI/QWzGPnSz53LVpALI9ssx15OgwjCNxUW+gjMMNrDN4Gz8EryvY28fwGVgPt6uZeT7bU02aSdcsTvWneGwoNeKIGWuwfIXghiTzIosijMbftWnWVNylM5hQOYlQloxVtCCKe5vnz5PeYfwE38yElu7XV6LqEibFNjor9Mcsc+Rr7d/rN diff --git a/test/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.pub b/test/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.pub new file mode 100644 index 000000000..d5265ace0 --- /dev/null +++ b/test/Data/Key.RSA.Encrypted.Des.Ede3.CBC.12345.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCY3ezaIynwdqwNBagUkBVhXETR16+KFGBy9bKcocgAmfvJR1HZc1xiyYPFMh32bN8ZNM6n9PVoBWwtSEmUyUbULa2/EOjOR+Vg9KzFC2Sw1yvu5DyRZngFWpZXZ4rYHVXZCF2cNeQ2uC5zilgdxmSmdDGokHBDuVv89n2DzqwymuCPFOkw+FXCdyaELro2tUmF1VBKHPj5It5U9HauPfcVmWX4ZD1wsEEVmKZS/03h+MDGCjUQE59DGIwZrWsIkOY9/QIU0040XYVOWsHdXlL58fjveOoSDz78dVaVbTE7HRJv0iO71o7xwyc/6js1SoHjRFlQNP4b6q5Z8NYqiL6T imported-openssh-key diff --git a/test/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.pub b/test/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.pub new file mode 100644 index 000000000..9bd8adc51 --- /dev/null +++ b/test/Data/Key.RSA.Encrypted.Des.Ede3.CFB.1234567890.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAs8tm1pWW8JOQTpuvsGlf/x7su38XuKo7zOLiY/6gB+ZBWs6UC3TnP1UnG13qyS9euWmIWqVz/3d6OM/O9ysjwgzBjRGQIyekxbXxDb+IpYrZR8T5QHXFjPp/yXGcknurUYF8G4ubxqJAULe5lCzg/b4aN9Vxv1tMTRdaArLPldc= diff --git a/test/Data/Key.RSA.pub b/test/Data/Key.RSA.pub new file mode 100644 index 000000000..071cafa1b --- /dev/null +++ b/test/Data/Key.RSA.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuTtXn+BatX1oJuvhqfJZw5jc/pcIxJUPmuoFCH3+bXfKBJ/94ixNETzZBasyvT/ozboAbCG3qcJOYxf2BEeTAIXe1jLAoTd1GKCwMvZOyjnsPN95/lChwfdnBbMzpZYTGfoUylXme/mzjjLu/J0qXgR5lyk9HFT+x5YEtRl8VSHiDkLKTZ37dwhsqgcs+PkfvYMUK+C8evnfE0tgWgKZk0Eatl87nLWyVXB4LzhSDtGKLCPAOgrX7fYfplDwJ2WK1N6nG0FnxW1HhDeSK7e2TbAa2vZQgvFXMWnO4O/NZKp4COpOReyliWhdtKAjr/+cD4yDfPjhjjKOYfxbvdRG4Q== imported-openssh-key diff --git a/test/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.pub b/test/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.pub new file mode 100644 index 000000000..3b07844b3 --- /dev/null +++ b/test/Data/Key.SSH2.DSA.Encrypted.Des.CBC.12345.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAI8gyHFchkVhkPiwkhkjFDqN6w2nFWTqVy9sLjFs38oEWLMpAw9+c132erUptAhNQ6JZUAVZGllv/3V5hksSDyChe9WY5IfsOlh6X0dcZCwBKysEzQlPyMFqAtbc9uv7oUWNzBfvEbtV6WN/VmcmXf7dyo3EBVXbBFdPl1NKC7W9AAAAFQDY1+bTt7s2iNmYoBE4C9hdWRCyeQAAAIAEtj09ugx/Tdl6bo7X6mX17hcgVgIxcYj5VNONg2k6IHmRFriLviYaS68mIB4SG3jmvvxbXAGqR1bWBUrv90n0wpxxcuuNoCFylJQyuqUkzSsUHb0WMcncZ/tBQt+NJnRB1Zp9sw8n20ocpg3WVPdaXTtc4pk83NYB6ywG6UFPvgAAAIAX+De5dwo33LMl9W8IvA4dY8Q1wshdycAGJzhy+qYF9dCcwD1Pg+4EbPjYPmzJopsVrK97v9QhxyYcXMr/iHhngGwd9nYNzzSKx665vkSjzyeJWpeQ+fvNV3CLItP01ypbUreM+s+Vz1wor5joLKcDS4X0oQ0RIVZNEHnekuLuFg== diff --git a/test/Data/Key.SSH2.DSA.pub b/test/Data/Key.SSH2.DSA.pub new file mode 100644 index 000000000..3b07844b3 --- /dev/null +++ b/test/Data/Key.SSH2.DSA.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBAI8gyHFchkVhkPiwkhkjFDqN6w2nFWTqVy9sLjFs38oEWLMpAw9+c132erUptAhNQ6JZUAVZGllv/3V5hksSDyChe9WY5IfsOlh6X0dcZCwBKysEzQlPyMFqAtbc9uv7oUWNzBfvEbtV6WN/VmcmXf7dyo3EBVXbBFdPl1NKC7W9AAAAFQDY1+bTt7s2iNmYoBE4C9hdWRCyeQAAAIAEtj09ugx/Tdl6bo7X6mX17hcgVgIxcYj5VNONg2k6IHmRFriLviYaS68mIB4SG3jmvvxbXAGqR1bWBUrv90n0wpxxcuuNoCFylJQyuqUkzSsUHb0WMcncZ/tBQt+NJnRB1Zp9sw8n20ocpg3WVPdaXTtc4pk83NYB6ywG6UFPvgAAAIAX+De5dwo33LMl9W8IvA4dY8Q1wshdycAGJzhy+qYF9dCcwD1Pg+4EbPjYPmzJopsVrK97v9QhxyYcXMr/iHhngGwd9nYNzzSKx665vkSjzyeJWpeQ+fvNV3CLItP01ypbUreM+s+Vz1wor5joLKcDS4X0oQ0RIVZNEHnekuLuFg== diff --git a/test/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.pub b/test/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.pub new file mode 100644 index 000000000..128dbc936 --- /dev/null +++ b/test/Data/Key.SSH2.RSA.Encrypted.Des.CBC.12345.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVwZxtc4I5nngC8qAu7uJsl9yEqccA5MbUHEyTHL/SkKhM9IMBeIfI3GM3iqOTyeqDV1+w92NcJGlb54GxAyElnU+oiHhYHt+Qrv5abi3CGpCEtDu4/COc1+U1ipGLN5gnnBSh+4rYjfQOCI1CPDaFXpOizyKS9UDsYJ52OdJxFhtRq5XyutcLr5efLqYPYXcEYT8JB1hNlc2zuYoiQKlv3OIlcwzuO4J8FI6pBLBnLtd4Qq4yrM/12IcIHKqoJyKmkdzRFlMs40JNZrud2ioB2FmmST+kOqYVMRYQm5Q83yNYKq6RLhHPFcQTeVvNlsidiayV2Vch5uhCgUkz7hZf imported-openssh-key diff --git a/test/Data/Key.SSH2.RSA.pub b/test/Data/Key.SSH2.RSA.pub new file mode 100644 index 000000000..128dbc936 --- /dev/null +++ b/test/Data/Key.SSH2.RSA.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVwZxtc4I5nngC8qAu7uJsl9yEqccA5MbUHEyTHL/SkKhM9IMBeIfI3GM3iqOTyeqDV1+w92NcJGlb54GxAyElnU+oiHhYHt+Qrv5abi3CGpCEtDu4/COc1+U1ipGLN5gnnBSh+4rYjfQOCI1CPDaFXpOizyKS9UDsYJ52OdJxFhtRq5XyutcLr5efLqYPYXcEYT8JB1hNlc2zuYoiQKlv3OIlcwzuO4J8FI6pBLBnLtd4Qq4yrM/12IcIHKqoJyKmkdzRFlMs40JNZrud2ioB2FmmST+kOqYVMRYQm5Q83yNYKq6RLhHPFcQTeVvNlsidiayV2Vch5uhCgUkz7hZf imported-openssh-key diff --git a/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj b/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj index ee97588d6..3f1186f39 100644 --- a/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj +++ b/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj @@ -15,6 +15,6 @@ - + diff --git a/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index a4bce13e7..085a17e75 100644 --- a/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -4,24 +4,9 @@ - + - - - $(MSBuildProgramFiles32)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll - $(MSTestV1UnitTestFrameworkAssemblyCandidate) - - $(MSBuildProgramFiles32)\Microsoft Visual Studio\2019\Professional\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll - $(MSTestV1UnitTestFrameworkAssemblyCandidate) - - $(MSBuildProgramFiles32)\Microsoft Visual Studio\2019\Community\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll - $(MSTestV1UnitTestFrameworkAssemblyCandidate) - - $(MSBuildProgramFiles32)\Microsoft Visual Studio\2019\Preview\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.QualityTools.UnitTestFramework.dll - $(MSTestV1UnitTestFrameworkAssemblyCandidate) - - From 1fc6360cf8325be04af2c5105ff4a49b420bd19d Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Sat, 21 Oct 2023 18:03:10 +0200 Subject: [PATCH 63/96] Remove duplicate GetManifestResourceStream helpers --- .../AuthenticationMethodFactory.cs | 25 ++++++------------- .../PrivateKeyAuthenticationTests.cs | 10 ++------ .../SftpTests.cs | 13 +--------- .../Renci.SshNet.IntegrationTests/TestBase.cs | 13 ++++------ ...Test_Connect_OnConnectedThrowsException.cs | 6 ++--- .../Classes/Common/HostKeyEventArgsTest.cs | 5 +--- ...st_Connect_NetConfSessionConnectFailure.cs | 6 ++--- ...tTest_Connect_SftpSessionConnectFailure.cs | 12 ++------- test/Renci.SshNet.Tests/Common/TestBase.cs | 7 ++++-- 9 files changed, 27 insertions(+), 70 deletions(-) diff --git a/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs b/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs index 638b285d8..421bdc1ec 100644 --- a/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs +++ b/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs @@ -10,32 +10,32 @@ public PasswordAuthenticationMethod CreatePowerUserPasswordAuthenticationMethod( public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyAuthenticationMethod() { - var privateKeyFile = GetPrivateKey("Renci.SshNet.IntegrationTests.resources.client.id_rsa"); + var privateKeyFile = GetPrivateKey("resources.client.id_rsa"); return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile); } public PrivateKeyAuthenticationMethod CreateRegularUserMultiplePrivateKeyAuthenticationMethod() { - var privateKeyFile1 = GetPrivateKey("Renci.SshNet.IntegrationTests.resources.client.id_rsa"); - var privateKeyFile2 = GetPrivateKey("Renci.SshNet.IntegrationTests.resources.client.id_rsa"); + var privateKeyFile1 = GetPrivateKey("resources.client.id_rsa"); + var privateKeyFile2 = GetPrivateKey("resources.client.id_rsa"); return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile1, privateKeyFile2); } public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyWithPassPhraseAuthenticationMethod() { - var privateKeyFile = GetPrivateKey("Renci.SshNet.IntegrationTests.resources.client.id_rsa_with_pass", "tester"); + var privateKeyFile = GetPrivateKey("resources.client.id_rsa_with_pass", "tester"); return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile); } public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyWithEmptyPassPhraseAuthenticationMethod() { - var privateKeyFile = GetPrivateKey("Renci.SshNet.IntegrationTests.resources.client.id_rsa_with_pass", null); + var privateKeyFile = GetPrivateKey("resources.client.id_rsa_with_pass", null); return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile); } public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey() { - var privateKeyFile = GetPrivateKey("Renci.SshNet.IntegrationTests.resources.client.id_noaccess.rsa"); + var privateKeyFile = GetPrivateKey("resources.client.id_noaccess.rsa"); return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile); } @@ -64,21 +64,10 @@ public KeyboardInteractiveAuthenticationMethod CreateRegularUserKeyboardInteract private PrivateKeyFile GetPrivateKey(string resourceName, string passPhrase = null) { - using (var stream = GetResourceStream(resourceName)) + using (var stream = TestBase.GetData(resourceName)) { return new PrivateKeyFile(stream, passPhrase); } } - - private Stream GetResourceStream(string resourceName) - { - var type = GetType(); - var resourceStream = type.Assembly.GetManifestResourceStream(resourceName); - if (resourceStream == null) - { - throw new ArgumentException($"Resource '{resourceName}' not found in assembly '{type.Assembly.FullName}'.", nameof(resourceName)); - } - return resourceStream; - } } } diff --git a/test/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs b/test/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs index 05b6c4787..e17855aab 100644 --- a/test/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs +++ b/test/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs @@ -87,15 +87,9 @@ private void DoTest(PublicKeyAlgorithm publicKeyAlgorithm, string keyResource) private PrivateKeyAuthenticationMethod CreatePrivateKeyAuthenticationMethod(string keyResource) { - var privateKey = CreatePrivateKeyFromManifestResource("Renci.SshNet.IntegrationTests.resources.client." + keyResource); - return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKey); - } - - private PrivateKeyFile CreatePrivateKeyFromManifestResource(string resourceName) - { - using (var stream = GetManifestResourceStream(resourceName)) + using (var stream = GetData($"resources.client.{keyResource}")) { - return new PrivateKeyFile(stream); + return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, new PrivateKeyFile(stream)); } } } diff --git a/test/Renci.SshNet.IntegrationTests/SftpTests.cs b/test/Renci.SshNet.IntegrationTests/SftpTests.cs index 7fb18c709..8c1f91660 100644 --- a/test/Renci.SshNet.IntegrationTests/SftpTests.cs +++ b/test/Renci.SshNet.IntegrationTests/SftpTests.cs @@ -300,7 +300,7 @@ public void Sftp_Create_FileDoesNotExist() try { - using (var imageStream = GetResourceStream("Renci.SshNet.IntegrationTests.resources.issue #70.png")) + using (var imageStream = GetData("resources.issue #70.png")) { using (var fs = client.Create(remoteFile)) { @@ -6301,17 +6301,6 @@ private static byte[] GetBytesWithPreamble(string text, Encoding encoding) return textBytes; } - private static Stream GetResourceStream(string resourceName) - { - var type = typeof(SftpTests); - var resourceStream = type.Assembly.GetManifestResourceStream(resourceName); - if (resourceStream == null) - { - throw new ArgumentException($"Resource '{resourceName}' not found in assembly '{type.Assembly.FullName}'.", nameof(resourceName)); - } - return resourceStream; - } - private static decimal CalculateTransferSpeed(long length, long elapsedMilliseconds) { return (length / 1024m) / (elapsedMilliseconds / 1000m); diff --git a/test/Renci.SshNet.IntegrationTests/TestBase.cs b/test/Renci.SshNet.IntegrationTests/TestBase.cs index 511bb144d..edca2d509 100644 --- a/test/Renci.SshNet.IntegrationTests/TestBase.cs +++ b/test/Renci.SshNet.IntegrationTests/TestBase.cs @@ -66,15 +66,12 @@ protected static void CreateFile(string fileName, int size) } } - protected Stream GetManifestResourceStream(string resourceName) + internal static Stream GetData(string name) { - var type = GetType(); - var resourceStream = type.Assembly.GetManifestResourceStream(resourceName); - if (resourceStream == null) - { - throw new ArgumentException($"Resource '{resourceName}' not found in assembly '{type.Assembly.FullName}'.", nameof(resourceName)); - } - return resourceStream; + string resourceName = $"Renci.SshNet.IntegrationTests.{name}"; + + return typeof(TestBase).Assembly.GetManifestResourceStream(resourceName) + ?? throw new ArgumentException($"Resource '{resourceName}' not found in assembly '{typeof(TestBase).Assembly.FullName}'.", nameof(resourceName)); } } } diff --git a/test/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs b/test/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs index 806f6c30a..543a5089c 100644 --- a/test/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs +++ b/test/Renci.SshNet.Tests/Classes/BaseClientTest_Connect_OnConnectedThrowsException.cs @@ -1,11 +1,11 @@ 锘縰sing System; using System.Linq; -using System.Reflection; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Renci.SshNet.Common; using Renci.SshNet.Security; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes { @@ -136,9 +136,7 @@ public void IsConnectedShouldReturnFalse() private static KeyHostAlgorithm GetKeyHostAlgorithm() { - var executingAssembly = Assembly.GetExecutingAssembly(); - - using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) + using (var s = TestBase.GetData("Key.RSA.txt")) { var privateKey = new PrivateKeyFile(s); return (KeyHostAlgorithm) privateKey.HostKeyAlgorithms.First(); diff --git a/test/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs index 39ff85d7b..f3d0ae55b 100644 --- a/test/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs @@ -3,7 +3,6 @@ using Renci.SshNet.Security; using Renci.SshNet.Tests.Common; using System.Linq; -using System.Reflection; namespace Renci.SshNet.Tests.Classes.Common { @@ -86,9 +85,7 @@ public void CanTrustTest() private static KeyHostAlgorithm GetKeyHostAlgorithm() { - var executingAssembly = Assembly.GetExecutingAssembly(); - - using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) + using (var s = GetData("Key.RSA.txt")) { var privateKey = new PrivateKeyFile(s); return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First(); diff --git a/test/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs b/test/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs index 41c285a84..1585d8734 100644 --- a/test/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs +++ b/test/Renci.SshNet.Tests/Classes/NetConfClientTest_Connect_NetConfSessionConnectFailure.cs @@ -1,6 +1,5 @@ 锘縰sing System; using System.Linq; -using System.Reflection; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -9,6 +8,7 @@ using Renci.SshNet.Common; using Renci.SshNet.Security; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes { @@ -109,9 +109,7 @@ public void HostKeyReceivedOnSessionShouldNoLongerBeSignaledViaHostKeyReceivedOn private static KeyHostAlgorithm GetKeyHostAlgorithm() { - var executingAssembly = Assembly.GetExecutingAssembly(); - - using (var s = executingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"))) + using (var s = TestBase.GetData("Key.RSA.txt")) { var privateKey = new PrivateKeyFile(s); return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First(); diff --git a/test/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs index 92f29113a..1b2a068c1 100644 --- a/test/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs +++ b/test/Renci.SshNet.Tests/Classes/SftpClientTest_Connect_SftpSessionConnectFailure.cs @@ -1,6 +1,5 @@ 锘縰sing System; using System.Linq; -using System.Reflection; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -9,6 +8,7 @@ using Renci.SshNet.Common; using Renci.SshNet.Security; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes { @@ -118,16 +118,8 @@ public void HostKeyReceivedOnSessionShouldNoLongerBeSignaledViaHostKeyReceivedOn private static KeyHostAlgorithm GetKeyHostAlgorithm() { - var executingAssembly = Assembly.GetExecutingAssembly(); - var resourceName = string.Format("Renci.SshNet.Tests.Data.{0}", "Key.RSA.txt"); - - using (var s = executingAssembly.GetManifestResourceStream(resourceName)) + using (var s = TestBase.GetData("Key.RSA.txt")) { - if (s is null) - { - throw new ArgumentException($"Resource '{resourceName}' does not exist in assembly '{executingAssembly.GetName().Name}'."); - } - var privateKey = new PrivateKeyFile(s); return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First(); } diff --git a/test/Renci.SshNet.Tests/Common/TestBase.cs b/test/Renci.SshNet.Tests/Common/TestBase.cs index 5973aa4a3..fb3768f21 100644 --- a/test/Renci.SshNet.Tests/Common/TestBase.cs +++ b/test/Renci.SshNet.Tests/Common/TestBase.cs @@ -49,9 +49,12 @@ protected void CreateTestFile(string fileName, int size) } } - protected static Stream GetData(string name) + internal static Stream GetData(string name) { - return ExecutingAssembly.GetManifestResourceStream(string.Format("Renci.SshNet.Tests.Data.{0}", name)); + string resourceName = $"Renci.SshNet.Tests.Data.{name}"; + + return ExecutingAssembly.GetManifestResourceStream(resourceName) + ?? throw new ArgumentException($"Resource '{resourceName}' not found in assembly '{typeof(TestBase).Assembly.FullName}'."); } } } From 0829fce6e4860d4f2295ee275822d5056821ddb5 Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Sat, 21 Oct 2023 18:57:02 +0200 Subject: [PATCH 64/96] Use shared Data folder for client keys in integration tests --- test/.editorconfig | 3 ++ test/Data/Key.DSA.pub | 1 + .../client/id_dsa => Data/Key.DSA.txt} | 0 .../AuthenticationMethodFactory.cs | 44 ++++++++++++++++--- .../PrivateKeyAuthenticationTests.cs | 26 +++++------ .../Renci.SshNet.IntegrationTests.csproj | 10 +---- .../Renci.SshNet.IntegrationTests/TestBase.cs | 2 +- .../resources/client/id_dsa.ppk | 17 ------- .../resources/client/id_noaccess.rsa | 27 ------------ .../resources/client/id_rsa | 27 ------------ .../resources/client/id_rsa.pub | 1 - .../resources/client/id_rsa_with_pass | 28 ------------ .../resources/client/key_ecdsa_256_openssh | 9 ---- .../client/key_ecdsa_256_openssh.pub | 1 - .../resources/client/key_ecdsa_384_openssh | 10 ----- .../client/key_ecdsa_384_openssh.pub | 1 - .../resources/client/key_ecdsa_521_openssh | 12 ----- .../client/key_ecdsa_521_openssh.pub | 1 - .../resources/client/key_ed25519_openssh | 7 --- .../user/sshnet/authorized_keys | 13 +++--- 20 files changed, 63 insertions(+), 177 deletions(-) create mode 100644 test/Data/Key.DSA.pub rename test/{Renci.SshNet.IntegrationTests/resources/client/id_dsa => Data/Key.DSA.txt} (100%) delete mode 100644 test/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk delete mode 100644 test/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa delete mode 100644 test/Renci.SshNet.IntegrationTests/resources/client/id_rsa delete mode 100644 test/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub delete mode 100644 test/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass delete mode 100644 test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh delete mode 100644 test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub delete mode 100644 test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh delete mode 100644 test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub delete mode 100644 test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh delete mode 100644 test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub delete mode 100644 test/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh diff --git a/test/.editorconfig b/test/.editorconfig index 60515fd14..d6a4af76e 100644 --- a/test/.editorconfig +++ b/test/.editorconfig @@ -28,6 +28,9 @@ dotnet_diagnostic.S1854.severity = none # https://github.com/meziantou/Meziantou.Analyzer/blob/main/docs/Rules/MA0089.md dotnet_diagnostic.MA0089.severity = suggestion +#MA0136 - Raw String contains an implicit end of line character +dotnet_diagnostic.MA0136.severity = none + #### StyleCop rules #### # SA1202: Elements must be ordered by access diff --git a/test/Data/Key.DSA.pub b/test/Data/Key.DSA.pub new file mode 100644 index 000000000..f32c6fae0 --- /dev/null +++ b/test/Data/Key.DSA.pub @@ -0,0 +1 @@ +ssh-dss AAAAB3NzaC1kc3MAAACBALVl3fae2O4qwsAK95SUShX0KMUNP+yl/uT3lGH9T/ZptnHSlrTxnTWXCl0g91KEeCaEnDDhLxm4aCv1Ag4B/yvcM4u34qkmaNLy2LiAxiqdobZcNG61Pqwqd5IDkp38LBsn8tmb12xu9NalpUfOiSEB1cyCr4zFZMrm0wtdyJQVAAAAFQCu+iNkqf/YOAYjYrHSCHFmWAfEYQAAAIAOVJ434UAR3Hn6lA5nWNfFOuUVH3W7nJaP0FQJiIPx7GUbdxO9qtDNTbWkWL3c9qx5+B7Ole4xM7cvyXPrNQUYDHCFlS+Ue2x3IeJrkdfZkH9ePP25y5A0J4/c+8XXvQaj4zA5nfw13oy5Ptyd7d3Kq5tEDM8KiVdIhwkXjUA3PQAAAIEAm8IGZQatS7M6AfNITNWG4TI7Z2aRQjLb9/MWJIID7c/VQ4zdTZdG3kpk0Gj9n4xreopK5NmYAdj8rtFfPBgmXltsLqt+bBcXkpxW//7WC29WOXW3t90ySTh+cWuWfr9fV7mf4Ql/6u/ZIgpQNvnNYezazt3fK8EXjI1dAXEuQxE= diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/id_dsa b/test/Data/Key.DSA.txt similarity index 100% rename from test/Renci.SshNet.IntegrationTests/resources/client/id_dsa rename to test/Data/Key.DSA.txt diff --git a/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs b/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs index 421bdc1ec..17e4c75b6 100644 --- a/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs +++ b/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs @@ -10,33 +10,63 @@ public PasswordAuthenticationMethod CreatePowerUserPasswordAuthenticationMethod( public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyAuthenticationMethod() { - var privateKeyFile = GetPrivateKey("resources.client.id_rsa"); + var privateKeyFile = GetPrivateKey("Data.Key.RSA.txt"); return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile); } public PrivateKeyAuthenticationMethod CreateRegularUserMultiplePrivateKeyAuthenticationMethod() { - var privateKeyFile1 = GetPrivateKey("resources.client.id_rsa"); - var privateKeyFile2 = GetPrivateKey("resources.client.id_rsa"); + var privateKeyFile1 = GetPrivateKey("Data.Key.RSA.txt"); + var privateKeyFile2 = GetPrivateKey("Data.Key.RSA.txt"); return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile1, privateKeyFile2); } public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyWithPassPhraseAuthenticationMethod() { - var privateKeyFile = GetPrivateKey("resources.client.id_rsa_with_pass", "tester"); + var privateKeyFile = GetPrivateKey("Data.Key.RSA.Encrypted.Aes.256.CBC.12345.txt", "12345"); return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile); } public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyWithEmptyPassPhraseAuthenticationMethod() { - var privateKeyFile = GetPrivateKey("resources.client.id_rsa_with_pass", null); + var privateKeyFile = GetPrivateKey("Data.Key.RSA.Encrypted.Aes.256.CBC.12345.txt", null); return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile); } public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey() { - var privateKeyFile = GetPrivateKey("resources.client.id_noaccess.rsa"); - return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, privateKeyFile); + string unauthorizedKey = """ + -----BEGIN RSA PRIVATE KEY----- + MIIEpAIBAAKCAQEAuK3OhcrEnQbbE1+WaE57tUCcTz1yqdE2AwvMfs3of1nyfGcS + Rz9vzAFYU+3uEEApk0QOsIeWCyB2DIlPnlQHyjVWRYPqiTtQ7GmdzbF0ISa7dr23 + EHJKgtJxSm3O/sb5F9JyqlxFMhKpz5NVgnN7NFcej93opHZN6h9LaP8cHgJIepWV + IkZqhcv8v6SpAgei0muoPHB+ZA6Rycnv+2//WUBzu+3AJu0PiHUkTTVC8M5svMRV + Ah8CnLsCkAAx7ld4AH7McRlFjymmkwxTSewFJYkloI/OqDOjsmuW03Gmx+eytPWa + HEPGeRhcz1kZ6eOmqrPMlTaLPV1MbFn86nauAQIDAQABAoIBAGEiWauZOMx2nKeV + 8SAvl3V/5DbxVOvotAXqIMbZOl4xSw8Pj1eWEBE26+RJEpvNg5CHjUpgJhT4H978 + Ibpe7DH418V8WtGPN0MBUhSsLy54lsUfh7fIxVQFp7zEAMmUkdNrxw+/tE1f75zU + G3efkb+3ysVUrFZEOzrW9uzksT8+gm2Ll/IKuDy2r5k9mJr2cX5OYKxXjtNo5duO + UK+M3jW9Sk1k23Jzpq2GwuJGTTjgtI41ND6CDkrY7COdRQdIx3eQ0uQSXosKNREe + lv0VTlboVyh8JXt+G1tkfA6+Al77/mzycaZVX26C8Io7Y/S7JVG7TT1p1RsFGZM8 + kcqvpBkCgYEA7vD3S+6T+8Ql8U877nDi/Ttf16NEUUQllgjWgCP+DiWcqQGWaiaB + JTYyM4Ydb4jy2jAcAdf3HfImE4QO3+u/wyuQrdlvWByHo2NqOxYMdyqKqwGh7qhU + zZFbGfHRD/gV4hWXfzj65wA8uMBVc5J3/ug7nmkTWywiDH/SsPdbxmcCgYEAxd0c + EbJ3dlIyK5Ul1Gw5dASyE91Nx/NHAvB+5QHH5rIe/IqbtxbXmEMKcxwEPN8hvpzs + g487TQFkNPze6X8vZkiuaNLUq9vwRlQwr/LIdjLLKOA69wKfFDSkei8LEMgEz7Wg + ZEm8ifJP75hGozx31bW4dYX2o2X75SbXneMVF1cCgYEAo4h8WJXC5o9KwKtQA1Nz + p4lZgUaW3V/csaD+3djEan5HiEwz3BbaUNOU7DqgLtP2EmrW4FQlJ3Oxp628WHkL + V9KbRMEKOa3dD3BdJm9ivLR7D6sgXy0KTV9skIc2ZM2QfJn2g/ZFkpBQ/sl0MpNO + WUIse7DCtKWx8AgT9VZ2k4UCgYB1G8JSQyPrtwiUvQkP6iIzJdhUY4Z20ulztu4U + EvLC+yfV5x/0xKNELmHP8YQclyA81loyH6NEl488wXIaFznxuxDnX+mZ8moK5ieO + 7A5zzuppvhWIP1fyOJok6xUMkKYwXdqZoP7jUrS3JZShZteyeIS9olVxLpphbZTu + kQnZrwKBgQDhO2+iGXwNLS+OFKwEiyUgvi6jb5OrIsdwWgqaqQarm6h0QWtxrCs6 + CMFFEusswZEGRo83J6lQxtcXvhWzTkVPu69J8YvTQqcKlvUSA9TEG2iX9bwXSWzy + LeGb5NjBZ3szfzp9l5Utnj5GuAGoDDDKpf7M6S95Lg6F58Mhd/tCFA== + -----END RSA PRIVATE KEY----- + """; + + using MemoryStream memoryStream = new(Encoding.UTF8.GetBytes(unauthorizedKey)); + return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, new PrivateKeyFile(memoryStream)); } public PasswordAuthenticationMethod CreateRegulatUserPasswordAuthenticationMethod() diff --git a/test/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs b/test/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs index e17855aab..19414999e 100644 --- a/test/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs +++ b/test/Renci.SshNet.IntegrationTests/PrivateKeyAuthenticationTests.cs @@ -25,59 +25,59 @@ public void TearDown() [TestMethod] public void SshDss() { - DoTest(PublicKeyAlgorithm.SshDss, "id_dsa"); + DoTest(PublicKeyAlgorithm.SshDss, "Data.Key.SSH2.DSA.Encrypted.Des.CBC.12345.txt", "12345"); } [TestMethod] public void SshRsa() { - DoTest(PublicKeyAlgorithm.SshRsa, "id_rsa"); + DoTest(PublicKeyAlgorithm.SshRsa, "Data.Key.RSA.txt"); } [TestMethod] public void SshRsaSha256() { - DoTest(PublicKeyAlgorithm.RsaSha2256, "id_rsa"); + DoTest(PublicKeyAlgorithm.RsaSha2256, "Data.Key.RSA.txt"); } [TestMethod] public void SshRsaSha512() { - DoTest(PublicKeyAlgorithm.RsaSha2512, "id_rsa"); + DoTest(PublicKeyAlgorithm.RsaSha2512, "Data.Key.RSA.txt"); } [TestMethod] public void Ecdsa256() { - DoTest(PublicKeyAlgorithm.EcdsaSha2Nistp256, "key_ecdsa_256_openssh"); + DoTest(PublicKeyAlgorithm.EcdsaSha2Nistp256, "Data.Key.ECDSA.Encrypted.txt", "12345"); } [TestMethod] public void Ecdsa384() { - DoTest(PublicKeyAlgorithm.EcdsaSha2Nistp384, "key_ecdsa_384_openssh"); + DoTest(PublicKeyAlgorithm.EcdsaSha2Nistp384, "Data.Key.OPENSSH.ECDSA384.Encrypted.txt", "12345"); } [TestMethod] public void Ecdsa521() { - DoTest(PublicKeyAlgorithm.EcdsaSha2Nistp521, "key_ecdsa_521_openssh"); + DoTest(PublicKeyAlgorithm.EcdsaSha2Nistp521, "Data.Key.OPENSSH.ECDSA521.Encrypted.txt", "12345"); } [TestMethod] public void Ed25519() { - DoTest(PublicKeyAlgorithm.SshEd25519, "key_ed25519_openssh"); + DoTest(PublicKeyAlgorithm.SshEd25519, "Data.Key.OPENSSH.ED25519.Encrypted.txt", "12345"); } - private void DoTest(PublicKeyAlgorithm publicKeyAlgorithm, string keyResource) + private void DoTest(PublicKeyAlgorithm publicKeyAlgorithm, string keyResource, string passPhrase = null) { _remoteSshdConfig.ClearPublicKeyAcceptedAlgorithms() .AddPublicKeyAcceptedAlgorithm(publicKeyAlgorithm) .Update() .Restart(); - var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod(keyResource)); + var connectionInfo = _connectionInfoFactory.Create(CreatePrivateKeyAuthenticationMethod(keyResource, passPhrase)); using (var client = new SshClient(connectionInfo)) { @@ -85,11 +85,11 @@ private void DoTest(PublicKeyAlgorithm publicKeyAlgorithm, string keyResource) } } - private PrivateKeyAuthenticationMethod CreatePrivateKeyAuthenticationMethod(string keyResource) + private static PrivateKeyAuthenticationMethod CreatePrivateKeyAuthenticationMethod(string keyResource, string passPhrase) { - using (var stream = GetData($"resources.client.{keyResource}")) + using (var stream = GetData(keyResource)) { - return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, new PrivateKeyFile(stream)); + return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, new PrivateKeyFile(stream, passPhrase)); } } } diff --git a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj index 285ed0f39..a7b798cb3 100644 --- a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj +++ b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj @@ -39,15 +39,7 @@ - - - - - - - - - + diff --git a/test/Renci.SshNet.IntegrationTests/TestBase.cs b/test/Renci.SshNet.IntegrationTests/TestBase.cs index edca2d509..9c9445f65 100644 --- a/test/Renci.SshNet.IntegrationTests/TestBase.cs +++ b/test/Renci.SshNet.IntegrationTests/TestBase.cs @@ -71,7 +71,7 @@ internal static Stream GetData(string name) string resourceName = $"Renci.SshNet.IntegrationTests.{name}"; return typeof(TestBase).Assembly.GetManifestResourceStream(resourceName) - ?? throw new ArgumentException($"Resource '{resourceName}' not found in assembly '{typeof(TestBase).Assembly.FullName}'.", nameof(resourceName)); + ?? throw new ArgumentException($"Resource '{resourceName}' not found in assembly '{typeof(TestBase).Assembly.FullName}'.", nameof(name)); } } } diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk b/test/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk deleted file mode 100644 index b73384f82..000000000 --- a/test/Renci.SshNet.IntegrationTests/resources/client/id_dsa.ppk +++ /dev/null @@ -1,17 +0,0 @@ -PuTTY-User-Key-File-2: ssh-dss -Encryption: none -Comment: imported-openssh-key -Public-Lines: 10 -AAAAB3NzaC1kc3MAAACBALVl3fae2O4qwsAK95SUShX0KMUNP+yl/uT3lGH9T/Zp -tnHSlrTxnTWXCl0g91KEeCaEnDDhLxm4aCv1Ag4B/yvcM4u34qkmaNLy2LiAxiqd -obZcNG61Pqwqd5IDkp38LBsn8tmb12xu9NalpUfOiSEB1cyCr4zFZMrm0wtdyJQV -AAAAFQCu+iNkqf/YOAYjYrHSCHFmWAfEYQAAAIAOVJ434UAR3Hn6lA5nWNfFOuUV -H3W7nJaP0FQJiIPx7GUbdxO9qtDNTbWkWL3c9qx5+B7Ole4xM7cvyXPrNQUYDHCF -lS+Ue2x3IeJrkdfZkH9ePP25y5A0J4/c+8XXvQaj4zA5nfw13oy5Ptyd7d3Kq5tE -DM8KiVdIhwkXjUA3PQAAAIEAm8IGZQatS7M6AfNITNWG4TI7Z2aRQjLb9/MWJIID -7c/VQ4zdTZdG3kpk0Gj9n4xreopK5NmYAdj8rtFfPBgmXltsLqt+bBcXkpxW//7W -C29WOXW3t90ySTh+cWuWfr9fV7mf4Ql/6u/ZIgpQNvnNYezazt3fK8EXjI1dAXEu -QxE= -Private-Lines: 1 -AAAAFBhGOzk+Aimeob964E8+HsQNlyde -Private-MAC: 1c254f3882a6661c98fb82dea1a55638a23633e5 diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa b/test/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa deleted file mode 100644 index cf2cc9795..000000000 --- a/test/Renci.SshNet.IntegrationTests/resources/client/id_noaccess.rsa +++ /dev/null @@ -1,27 +0,0 @@ -锘-----BEGIN RSA PRIVATE KEY----- -MIIEoQIBAAKCAQEAuTtXn+BatX1oJuvhqfJZw5jc/pcIxJUPmuoFCH3+bXfKBJ/9 -4ixNETzZBasyvT/ozboAbCG3qcJOYxf2BEeTAIXe1jLAoTd1GKCwMvZOyjnsPN95 -/lChwfdnBbMzpZYTGfoUylXme/mzjjLu/J0qXgR5lyk9HFT+x5YEtRl8VSHiDkLK -TZ37dwhsqgcs+PkfvYMUK+C8evnfE0tgWgKZk0Eatl87nLWyVXB4LzhSDtGKLCPA -OgrX7fYfplDwJ2WK1N6nG0FnxW1HhDeSK7e2TbAa2vZQgvFXMWnO4O/NZKp4COpO -ReyliWhdtKAjr/+cD4yDfPjhjjKOYfxbvdRG4QIBIwKCAQAqVrTxV9o4HKoXhl93 -TVZYl/f/rX5Y0Z0quSW4zFdpendRg6e+qwpNFTjrWlS9ivNiOSSrAGR+ktAWpmQe -PD7bjFAw9ahfXSIUQfxja3+5Mc+Y4p+KlhZYOIyTlqy4Ik2CR8o84G8yR7QDPteK -Mo1XUXrguPgGedPV2SWlvK60XyAXqsewDhi7SeImZomKzbh33SXjVxakzHfa8BEU -eIIeR9oFlQMuYdo4GrHhFO2T+g/gqw/kVd1zkeEwt06fZVDErVwp+twewxxvwrk4 -CKUCzavfhDfi5sJ5YdzhDBRgkyBgJI+f15dKyqqOiAparV9+uzrD6vIuNnlVoqQA -iugLAoGBAPBliy32e83nshBknBn5HOK2rO3a1zHxvYr/NzITXtdZOjatNyfXtkwi -Ll/el5tZhJvKe9nItSI/4w7mvlvXZfW8h3MR0qb8at4jWa8ya2hwEerqaJonqjjb -+eBhg27ltZIQRk8Bv6ApXTAWkc+dFGhEIysokDQX7V72Bdrizup1AoGBAMVBLHK0 -5IFb8x7danlAmDX6bqCObId4Pce2OeONFIj1jIowvCXaE0t9zU4X5SdN5ujqu4Dq -XgzUdNeKcJxWpFO74MDRxT3CbMz36fikJnvxWl/+q0HalYuCY8gm14VYcThUBAro -3c941INueybGNLIA9jc7RMnsFtyVTvNYpaU9AoGAFJr9TRUgjf3qsPKuS15+0Zqh -G7OsC5hgtCSBEuu3rA72XHU/Pe3rDdcLSgvD2h2dpvQZPo2L3l0/WQx2t2o78H3f -uWftfAcB2Iav6nIJNNZn75BvXaug4E1ej5NUaJdYtL+Q/3UtrqR1s6opwVabWWTt -ElPvGmhzboodwk30en8CgYAyuPzNCfGdm00lMZ8JPH7pTwaBDq4xdrDM9FgHUCna -E0FlXP0uTgT2J6nSQKijtPI75JadfhgvL1E+vTLmX2wViBU45XvcrlZ92Vlr0nBL -wbgnUB1otIzauyD49AuIsFegxSWcZ8QCJmKIMlouir0X1FyR3Apfzv6Qfio+kyNH -vwKBgQCtwxojkzUSfV3zDt6bYSLBzgXgo/Zr9lS+gSggP72DzINmW2gbA0fkM2Zu -JltcfakKv4gVX/1zooz+7t+4bj6dqt+bl7hYz0VnTSDZGuo5LKDif/4gSGrdblC2 -QLTuX2HjWCZdsue7mRwL7cXR4zlIoE99+Ryhdxvc5wHSfYr/JA== ------END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/id_rsa b/test/Renci.SshNet.IntegrationTests/resources/client/id_rsa deleted file mode 100644 index da8f397ea..000000000 --- a/test/Renci.SshNet.IntegrationTests/resources/client/id_rsa +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAuDdE+laKZ8D0mEFMNMGkDYQY89A2BUML5L+DsFmEn//3yRdz -Omx+Nk59ifiJUPuP3whZxN5vfbHleU9ZshI+37LqTbXmNrChRlxDSxrQA/++hTNI -gZl8e+sZUk8mUkpjQyEVOMVEdt3H3PmpfOBeZjtpRJPuWa90J+SVKbnAX4rOL7bt -LDA4GeMNXdLXLl5E/zBCZ9ol9nJ8W0suajQDx7u2/ixH1wb9jqzA6j68f1+kERII -t8OUcS+ZM+274rVrCMCL290k9gEQAKwcG/KRMqdgP8Oadtq5ELS/t4m2fH5JqYJ9 -9399QGT4LTPvoiTwZjyhYwK3FhCfXyFQf+gwIwIDAQABAoIBAGLChsFrKfJr2PXT -dAaIleoFGteDlaKGilbNcc1WgKrCsNXnM4hr59I3jEgurXd0FnKs6GuKEN2jRPIf -X2f/LiQBqGmXDl/dm+i7x/v42PJ75mlE0Cdi4QESTlX5RwMxDDxN/TGdWJIdXmwS -kRH4u8M1ML9qS4tba/uDKZDgG8lcF/z6K0RbXDMxL0azfbd5e+jca1e8Fs93X5s7 -mJotXaA+L33R7lCpBBOa1OY517Ug7bdI+uWh59o0bw8v2q8vr8ISOHU3N+JvKZ62 -2z5O6lLyB94sF6ltXRv9pmfcSBjfB8CJx5q1yejUZKM6VfN98MTSKo8WKMEtGmqk -BtZFTlECgYEA8WYG6vntqXPCHhFFfgCymh8OoXL/mPDSkqsswKfeD4O+Ml9hRUtg -xl6FDxFAMR7WJ4Vb8u9IMOc7Xx+nzlZNsdC5m7FAVRIEUPPjEucte+ZYKjSy+WOd -dAtQ07O3z9fi+JNplSjisKtBWaemfqc2TcYXOeIIgwJnkaCf2C7I2bsCgYEAw1vJ -9c5VLTisPj7ijMeGLWISG5E0aidOrb15E8xcnXuT9TEW1Dc1EgRK/D03tlnoxr1I -CISPx4EmdLTiEl2AVi33DOhCeFAt8TOd/y3chKsbewb+BYEMmBD93mhsKg+YmC5E -284SCV3fCcyFJfo9oy5Z2tIELerjT0cnpHgPCLkCgYEAij3OemRUeTUklol3jXgi -z+Y3P7gWreREAuBqSY4YujPNCRXcI43ORuu8MWvEohyxsYJKrO3hHrhdJNWBCMYd -ylXo5UN1vwIJXL6+bIXdY1X/aXQyhmVItzr/t6z0997/STFKRrRaVahNTWWYEHH7 -xEBL7scF7tjCrQAaafgo558CgYBkrrm3ZU+grsSWj/JSe8I7QX/zlTJeQ0PZZv0v -pvNUdowaoeISHSHM10mOFj7QTCYbxxGI0kkHmRgordCVhnrN74KTtGANgcUrul6D -VS+BcG4JSeFBFPFYreko5shYJRGP3MjAP8Qr76Uzd6RnnkCGCS1mCTb+M0BTa2iS -6w1UgQKBgQDQ2qV4s7xH3dixy4MWhDBFmrQlFpQkNNkrJ/ImHrxI2tFyNaq1fE+Q -PrXJi8mjwb/ETVN2C5iBTtIyVg1pZk3YAWAvIt9SPaRVYQWj8IJeOTTaNEZEvp5K -1LJBWO0ksgJK28f/z7FwejeGbBwg8ch9wVhtFwIV++rZ76smP7C+9Q== ------END RSA PRIVATE KEY----- diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub b/test/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub deleted file mode 100644 index 24ba2f7dd..000000000 --- a/test/Renci.SshNet.IntegrationTests/resources/client/id_rsa.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4N0T6VopnwPSYQUw0waQNhBjz0DYFQwvkv4OwWYSf//fJF3M6bH42Tn2J+IlQ+4/fCFnE3m99seV5T1myEj7fsupNteY2sKFGXENLGtAD/76FM0iBmXx76xlSTyZSSmNDIRU4xUR23cfc+al84F5mO2lEk+5Zr3Qn5JUpucBfis4vtu0sMDgZ4w1d0tcuXkT/MEJn2iX2cnxbSy5qNAPHu7b+LEfXBv2OrMDqPrx/X6QREgi3w5RxL5kz7bvitWsIwIvb3ST2ARAArBwb8pEyp2A/w5p22rkQtL+3ibZ8fkmpgn33f31AZPgtM++iJPBmPKFjArcWEJ9fIVB/6DAj diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass b/test/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass deleted file mode 100644 index 841532d1f..000000000 --- a/test/Renci.SshNet.IntegrationTests/resources/client/id_rsa_with_pass +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABC9v0UCCP -T+1yNEu9m0w939AAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQC4N0T6Vopn -wPSYQUw0waQNhBjz0DYFQwvkv4OwWYSf//fJF3M6bH42Tn2J+IlQ+4/fCFnE3m99seV5T1 -myEj7fsupNteY2sKFGXENLGtAD/76FM0iBmXx76xlSTyZSSmNDIRU4xUR23cfc+al84F5m -O2lEk+5Zr3Qn5JUpucBfis4vtu0sMDgZ4w1d0tcuXkT/MEJn2iX2cnxbSy5qNAPHu7b+LE -fXBv2OrMDqPrx/X6QREgi3w5RxL5kz7bvitWsIwIvb3ST2ARAArBwb8pEyp2A/w5p22rkQ -tL+3ibZ8fkmpgn33f31AZPgtM++iJPBmPKFjArcWEJ9fIVB/6DAjAAADwPBAapXaoQvm3O -2i9sBnmO+d8kCdm2nhGbEXNzswb0toARYyx7/rPON15BHv470NLK4GjtxWb8SbkUBjWIXJ -dpJR1feYAgJQ27yaU6SBEJvnQBFI3EvH+h9ykaikDP/SzgZuGup5NZIoB09PzCPk4SbAwn -skFT3s1v3ufaULYTiAO2xtWzABkjxfw8HOo+PF3UqGIF4145kGLUT1pUN7iy5EQZA8evRb -Yt/9+ChcyBgKONgXdpjLNf02XIM/jQofZkROBg7ZAKCjtL3yGpvtOpwzCKy1hWDmgjtkeK -Xn84/qwXWEobBa2wrDQ4Mjj7AIimRsCciO05bVB5KtNjT+WzCalpTzfj2nazukteNRKTD3 -bQR0gLFfFX4/YodXmtu2n+0R2AKkdPW5ZhoEEpT1FjfYUImAuElSEy5FEeR3bwE5uGQkF4 -uIMJWD+89QxO9PWKTloVI2hrOF9/z+UzUi7p16FQFDlB82qCQAiaIOHgotgDn9+OwMw0ew -Gu/D3T8ZpKXcTAxK1JeoDFh2h+CE37JDvftNIxIhTp7lrhCdioj1DSBorwfke/q4+OvLUH -8SZ6ZgppHjJ4jg6lB9TWCpD5PECDW+NuQQwUb5V4NKoBqnJrPaNUSbI7SL5Pq3mOXXNRmv -q1Va06CfcHL3JupICFifux5xBDlQY0foAt7DFOgA6qANaCnRl2H2oFsEdRhBbL6EPP0bAQ -7PBvWJlt5Aqr1V7QzcCHNZcyGpjiHeXsQxSWXzb1xQprlrDSnlGZpusrBTcZTLWUtOAgqQ -dNbUNeUq1E74rZ/RBiVliaLHNBKwTCE9KyZTl/DcfgInB7DDEd7Vlmujzar7xAXRJot7k2 -a12gT69eVsqiO5si23493JFl0JB5vbQvQWARAvcdNPDPiILoJVpbgyL9oMzVzTjJyqYS1x -cHXKE+rL4ZHeQhcfySXplZlUY9ADVY5QywAj2kl+5gT3Fohu/95axF7w9dAHyMntxbVnA3 -r0zOmqbAKOYEYEXxZ+Vq09YdEyJh33V48PUmvCusWWyeKIfjO4R1nD2+7iyiF7joF7bOBm -o0LXuJdr81BCMueryPUaqSRpGhg/P/nUqzxj7p0mAh9uUOr/CtOpbc6wNY70RgdiMGFWhz -zhO54p7iEg2zZNUZ5zRM1hTBikTeYyInpw8IQiMv9GH7/9gWwqPsh0qRVjj5kjqjSu069d -FeuGjsMGCnLLG6WvOQ9DgH9JR4cfinBL3JwtpHFBIHwhsh2EIuSseVHvQlFlEc1U+7Yoxc -0dn1VVtg== ------END OPENSSH PRIVATE KEY----- diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh b/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh deleted file mode 100644 index 29ecb9073..000000000 --- a/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS -1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQT886z6SLRIzRu7VNA6SSeKZCNNRPXe -iutTik1T3RUEshgnTI/V3T/d5QurCQPvf2ob3+Rd4FhCsVCS9gilIhVsAAAAsH3KX4d9yl -+HAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPzzrPpItEjNG7tU -0DpJJ4pkI01E9d6K61OKTVPdFQSyGCdMj9XdP93lC6sJA+9/ahvf5F3gWEKxUJL2CKUiFW -wAAAAgYxeSyo7MVNup52COOCarcvARKlWhKIP2CKzj4qa5/6EAAAAYc3NobmV0QFVidW50 -dTE5MTBEZXNrdG9w ------END OPENSSH PRIVATE KEY----- diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub b/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub deleted file mode 100644 index 33524cea6..000000000 --- a/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_256_openssh.pub +++ /dev/null @@ -1 +0,0 @@ -ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPzzrPpItEjNG7tU0DpJJ4pkI01E9d6K61OKTVPdFQSyGCdMj9XdP93lC6sJA+9/ahvf5F3gWEKxUJL2CKUiFWw= sshnet@Ubuntu1910Desktop diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh b/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh deleted file mode 100644 index e720d2407..000000000 --- a/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh +++ /dev/null @@ -1,10 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAiAAAABNlY2RzYS -1zaGEyLW5pc3RwMzg0AAAACG5pc3RwMzg0AAAAYQS0rLvxzSomgC4UNulA7/jdABXTG9un -zFazinvOughrumo0n/R1DoSRXY4bHooQdq02pTD6/DK3FzS7n4ouJi/LuJfX1EFxYMJzP2 -aYlT0rOgvvIuLv2Q4OzcdjV8mzSIEAAADo1T5ZUtU+WVIAAAATZWNkc2Etc2hhMi1uaXN0 -cDM4NAAAAAhuaXN0cDM4NAAAAGEEtKy78c0qJoAuFDbpQO/43QAV0xvbp8xWs4p7zroIa7 -pqNJ/0dQ6EkV2OGx6KEHatNqUw+vwytxc0u5+KLiYvy7iX19RBcWDCcz9mmJU9KzoL7yLi -79kODs3HY1fJs0iBAAAAMQDgRb336Dk9e4VxOpSqnwBqHRsJ3QmSME9qMBvx5SXykHFAsK -wzVKEvIQizmg/+sWcAAAAYc3NobmV0QFVidW50dTE5MTBEZXNrdG9wAQIDBAUGBw== ------END OPENSSH PRIVATE KEY----- diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub b/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub deleted file mode 100644 index 99878d2ca..000000000 --- a/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_384_openssh.pub +++ /dev/null @@ -1 +0,0 @@ -ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBLSsu/HNKiaALhQ26UDv+N0AFdMb26fMVrOKe866CGu6ajSf9HUOhJFdjhseihB2rTalMPr8MrcXNLufii4mL8u4l9fUQXFgwnM/ZpiVPSs6C+8i4u/ZDg7Nx2NXybNIgQ== sshnet@Ubuntu1910Desktop diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh b/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh deleted file mode 100644 index 47ee8ff8b..000000000 --- a/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAArAAAABNlY2RzYS -1zaGEyLW5pc3RwNTIxAAAACG5pc3RwNTIxAAAAhQQAgeFoEYBgUaOlJPnEYIPLSTwmxLRl -EUVpVAOzww3q10fj/Tuppty/fRLcbMoeVzWKl8mjDbR+XOdaKDGo6xcHGsgByITz2/F9wr -E8BHyFEPemg8h0DKLW0X55J+rnn3lE0a0jXKngJ3VLVcgKgXam7KtpoCWFx689jVCpTxWI -GrkIvlkAAAEYr0LrEa9C6xEAAAATZWNkc2Etc2hhMi1uaXN0cDUyMQAAAAhuaXN0cDUyMQ -AAAIUEAIHhaBGAYFGjpST5xGCDy0k8JsS0ZRFFaVQDs8MN6tdH4/07qabcv30S3GzKHlc1 -ipfJow20flznWigxqOsXBxrIAciE89vxfcKxPAR8hRD3poPIdAyi1tF+eSfq5595RNGtI1 -yp4Cd1S1XICoF2puyraaAlhcevPY1QqU8ViBq5CL5ZAAAAQQ50pmBidmKTIknaRpdO5WIu -nYEGMUkLqdZ0egk9Ggg63mOHiLykf+XWcGbHbHM95CISXhqlvMtCYeGwOpP6FoMGAAAAGH -NzaG5ldEBVYnVudHUxOTEwRGVza3RvcAECAw== ------END OPENSSH PRIVATE KEY----- diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub b/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub deleted file mode 100644 index 085fa07bf..000000000 --- a/test/Renci.SshNet.IntegrationTests/resources/client/key_ecdsa_521_openssh.pub +++ /dev/null @@ -1 +0,0 @@ -ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACB4WgRgGBRo6Uk+cRgg8tJPCbEtGURRWlUA7PDDerXR+P9O6mm3L99Etxsyh5XNYqXyaMNtH5c51ooMajrFwcayAHIhPPb8X3CsTwEfIUQ96aDyHQMotbRfnkn6uefeUTRrSNcqeAndUtVyAqBdqbsq2mgJYXHrz2NUKlPFYgauQi+WQ== sshnet@Ubuntu1910Desktop diff --git a/test/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh b/test/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh deleted file mode 100644 index 0bcb6e755..000000000 --- a/test/Renci.SshNet.IntegrationTests/resources/client/key_ed25519_openssh +++ /dev/null @@ -1,7 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW -QyNTUxOQAAACAJDRj1Tk7s7ik4Bnx3L3tjEY+e8l4ZmYJFMovUaZia5QAAAKBKTcfHSk3H -xwAAAAtzc2gtZWQyNTUxOQAAACAJDRj1Tk7s7ik4Bnx3L3tjEY+e8l4ZmYJFMovUaZia5Q -AAAEBMMOaGa8RU8Vy0vLFlRT5iVSxl3ji9NBKaO/RS0aFL3QkNGPVOTuzuKTgGfHcve2MR -j57yXhmZgkUyi9RpmJrlAAAAGHNzaG5ldEBVYnVudHUxOTEwRGVza3RvcAECAwQF ------END OPENSSH PRIVATE KEY----- diff --git a/test/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys b/test/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys index d91b4786c..5ba085cb6 100644 --- a/test/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys +++ b/test/Renci.SshNet.IntegrationTests/user/sshnet/authorized_keys @@ -1,6 +1,7 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC4N0T6VopnwPSYQUw0waQNhBjz0DYFQwvkv4OwWYSf//fJF3M6bH42Tn2J+IlQ+4/fCFnE3m99seV5T1myEj7fsupNteY2sKFGXENLGtAD/76FM0iBmXx76xlSTyZSSmNDIRU4xUR23cfc+al84F5mO2lEk+5Zr3Qn5JUpucBfis4vtu0sMDgZ4w1d0tcuXkT/MEJn2iX2cnxbSy5qNAPHu7b+LEfXBv2OrMDqPrx/X6QREgi3w5RxL5kz7bvitWsIwIvb3ST2ARAArBwb8pEyp2A/w5p22rkQtL+3ibZ8fkmpgn33f31AZPgtM++iJPBmPKFjArcWEJ9fIVB/6DAj -ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPzzrPpItEjNG7tU0DpJJ4pkI01E9d6K61OKTVPdFQSyGCdMj9XdP93lC6sJA+9/ahvf5F3gWEKxUJL2CKUiFWw= -ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBLSsu/HNKiaALhQ26UDv+N0AFdMb26fMVrOKe866CGu6ajSf9HUOhJFdjhseihB2rTalMPr8MrcXNLufii4mL8u4l9fUQXFgwnM/ZpiVPSs6C+8i4u/ZDg7Nx2NXybNIgQ== -ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBACB4WgRgGBRo6Uk+cRgg8tJPCbEtGURRWlUA7PDDerXR+P9O6mm3L99Etxsyh5XNYqXyaMNtH5c51ooMajrFwcayAHIhPPb8X3CsTwEfIUQ96aDyHQMotbRfnkn6uefeUTRrSNcqeAndUtVyAqBdqbsq2mgJYXHrz2NUKlPFYgauQi+WQ== -ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAkNGPVOTuzuKTgGfHcve2MRj57yXhmZgkUyi9RpmJrl -ssh-dss AAAAB3NzaC1kc3MAAACBALVl3fae2O4qwsAK95SUShX0KMUNP+yl/uT3lGH9T/ZptnHSlrTxnTWXCl0g91KEeCaEnDDhLxm4aCv1Ag4B/yvcM4u34qkmaNLy2LiAxiqdobZcNG61Pqwqd5IDkp38LBsn8tmb12xu9NalpUfOiSEB1cyCr4zFZMrm0wtdyJQVAAAAFQCu+iNkqf/YOAYjYrHSCHFmWAfEYQAAAIAOVJ434UAR3Hn6lA5nWNfFOuUVH3W7nJaP0FQJiIPx7GUbdxO9qtDNTbWkWL3c9qx5+B7Ole4xM7cvyXPrNQUYDHCFlS+Ue2x3IeJrkdfZkH9ePP25y5A0J4/c+8XXvQaj4zA5nfw13oy5Ptyd7d3Kq5tEDM8KiVdIhwkXjUA3PQAAAIEAm8IGZQatS7M6AfNITNWG4TI7Z2aRQjLb9/MWJIID7c/VQ4zdTZdG3kpk0Gj9n4xreopK5NmYAdj8rtFfPBgmXltsLqt+bBcXkpxW//7WC29WOXW3t90ySTh+cWuWfr9fV7mf4Ql/6u/ZIgpQNvnNYezazt3fK8EXjI1dAXEuQxE= +ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuTtXn+BatX1oJuvhqfJZw5jc/pcIxJUPmuoFCH3+bXfKBJ/94ixNETzZBasyvT/ozboAbCG3qcJOYxf2BEeTAIXe1jLAoTd1GKCwMvZOyjnsPN95/lChwfdnBbMzpZYTGfoUylXme/mzjjLu/J0qXgR5lyk9HFT+x5YEtRl8VSHiDkLKTZ37dwhsqgcs+PkfvYMUK+C8evnfE0tgWgKZk0Eatl87nLWyVXB4LzhSDtGKLCPAOgrX7fYfplDwJ2WK1N6nG0FnxW1HhDeSK7e2TbAa2vZQgvFXMWnO4O/NZKp4COpOReyliWhdtKAjr/+cD4yDfPjhjjKOYfxbvdRG4Q== Key.RSA +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6KpJwRX4HfoFimrRTxqHsyAoPgMD+dm2/6NjIZiy2CPuNGfci+EKjSmdQHhqM8jlhBKhSiAnsEuW46WGlCzpQm2uSA1hFCz/pdExNw9onfY2hdJwOrFlDO9rOcedeZhSQ5gDW/c/MreQQDgEST8tBBM8Yuuk9h6763+Cbd7TAvOskfmx9RXRMeFaqYOe8uVvNQDAYKlcfhjRESfkDtUvJSUyjZYkKR0wnm9fFGL6K/jQrbDYG75wEyB6+bSPHl3ZLakjHJiNOXVlOgJVk9Gw147hLPd+zxyE4eJV5J7rQv96QUWouYPFcMD4EfginfkIbNg02A5onkjTTVUBnIK31 Key.RSA.Encrypted.Aes.256.CBC.12345 +ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOwUDIZhrxd1VJ7ByUuB25kdZlU0iCl/vru8VZcwmd0ROMLe0FruHkhG54JWTKcOxOOA1ITzEVXVTMpgN9ruRLs= Key.ECDSA.Encrypted +ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAzODQAAABhBFL5NEL9uRhgkF2q+8m58EvtZq4mDGgcVEzafPRuNIn1018m9KuqNpOQ6d+435n+MRYThe4MUdijSIDuopX2i14Z35oKZ9x2LsV+RxQczjmbnoWZdvgcvdOo6jiJdY7XJw== Key.OPENSSH.ECDSA384.Encrypted +ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1MjEAAACFBAH9BVM6bRhbELtgdMGsin5lM42R2EWoT+6Akakl5rQy2tHHLIYGLEfaqI+0iUo2V6MxEf9w0hVz6SEsF+yDgyrYPQCIieaB1oBvIl+PZmL1XsuAXs2uMRsNJb4myGU/DiekxqzIPa0LMrBZ4xmErcn5Gazkw1EA0B3HoaW5wj+geI/efQ== Key.OPENSSH.ECDSA521.Encrypted +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGFdyflleGqSPOhgSYZf7ZQFlG0zEL9VDGC69UbtaaBy Key.OPENSSH.ED25519.Encrypted +ssh-dss AAAAB3NzaC1kc3MAAACBAI8gyHFchkVhkPiwkhkjFDqN6w2nFWTqVy9sLjFs38oEWLMpAw9+c132erUptAhNQ6JZUAVZGllv/3V5hksSDyChe9WY5IfsOlh6X0dcZCwBKysEzQlPyMFqAtbc9uv7oUWNzBfvEbtV6WN/VmcmXf7dyo3EBVXbBFdPl1NKC7W9AAAAFQDY1+bTt7s2iNmYoBE4C9hdWRCyeQAAAIAEtj09ugx/Tdl6bo7X6mX17hcgVgIxcYj5VNONg2k6IHmRFriLviYaS68mIB4SG3jmvvxbXAGqR1bWBUrv90n0wpxxcuuNoCFylJQyuqUkzSsUHb0WMcncZ/tBQt+NJnRB1Zp9sw8n20ocpg3WVPdaXTtc4pk83NYB6ywG6UFPvgAAAIAX+De5dwo33LMl9W8IvA4dY8Q1wshdycAGJzhy+qYF9dCcwD1Pg+4EbPjYPmzJopsVrK97v9QhxyYcXMr/iHhngGwd9nYNzzSKx665vkSjzyeJWpeQ+fvNV3CLItP01ypbUreM+s+Vz1wor5joLKcDS4X0oQ0RIVZNEHnekuLuFg== Key.SSH2.DSA.Encrypted.Des.CBC.12345 From 09ad44a823a02a6907051c3843fb1878dae9bb68 Mon Sep 17 00:00:00 2001 From: Robert Hague Date: Sat, 21 Oct 2023 19:27:56 +0200 Subject: [PATCH 65/96] Remove unused symbols --- .../Renci.SshNet.IntegrationTests.csproj | 4 - .../Renci.SshNet.IntegrationTests/ScpTests.cs | 278 ------------------ .../SftpTests.cs | 11 - 3 files changed, 293 deletions(-) diff --git a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj index a7b798cb3..19e104b31 100644 --- a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj +++ b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj @@ -8,10 +8,6 @@ $(NoWarn);SYSLIB0021;SYSLIB1045;SYSLIB0014;IDE0220;IDE0010 - - TRACE;FEATURE_MSTEST_DATATEST;FEATURE_SOCKET_EAP;FEATURE_ENCODING_ASCII;FEATURE_THREAD_SLEEP;FEATURE_THREAD_THREADPOOL - - diff --git a/test/Renci.SshNet.IntegrationTests/ScpTests.cs b/test/Renci.SshNet.IntegrationTests/ScpTests.cs index 2fd4ea0ce..c244b86a8 100644 --- a/test/Renci.SshNet.IntegrationTests/ScpTests.cs +++ b/test/Renci.SshNet.IntegrationTests/ScpTests.cs @@ -19,21 +19,8 @@ public void SetUp() _remotePathTransformation = RemotePathTransformation.ShellQuote; } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpDownloadStreamDirectoryDoesNotExistData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Download_Stream_DirectoryDoesNotExist() - { - foreach (var data in GetScpDownloadStreamDirectoryDoesNotExistData()) - { - Scp_Download_Stream_DirectoryDoesNotExist((IRemotePathTransformation) data[0], - (string) data[1], - (string) data[2]); - } - } -#endif public void Scp_Download_Stream_DirectoryDoesNotExist(IRemotePathTransformation remotePathTransformation, string remotePath, string remoteFile) @@ -106,21 +93,8 @@ public void Scp_Download_Stream_DirectoryDoesNotExist(IRemotePathTransformation } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpDownloadStreamFileDoesNotExistData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Download_Stream_FileDoesNotExist() - { - foreach (var data in GetScpDownloadStreamFileDoesNotExistData()) - { - Scp_Download_Stream_FileDoesNotExist((IRemotePathTransformation)data[0], - (string)data[1], - (string)data[2]); - } - } -#endif public void Scp_Download_Stream_FileDoesNotExist(IRemotePathTransformation remotePathTransformation, string remotePath, string remoteFile) @@ -195,20 +169,8 @@ public void Scp_Download_Stream_FileDoesNotExist(IRemotePathTransformation remot } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpDownloadDirectoryInfoDirectoryDoesNotExistData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Download_DirectoryInfo_DirectoryDoesNotExist() - { - foreach (var data in GetScpDownloadDirectoryInfoDirectoryDoesNotExistData()) - { - Scp_Download_DirectoryInfo_DirectoryDoesNotExist((IRemotePathTransformation)data[0], - (string)data[1]); - } - } -#endif public void Scp_Download_DirectoryInfo_DirectoryDoesNotExist(IRemotePathTransformation remotePathTransformation, string remotePath) { @@ -265,20 +227,8 @@ public void Scp_Download_DirectoryInfo_DirectoryDoesNotExist(IRemotePathTransfor } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpDownloadDirectoryInfoExistingFileData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Download_DirectoryInfo_ExistingFile() - { - foreach (var data in GetScpDownloadDirectoryInfoExistingFileData()) - { - Scp_Download_DirectoryInfo_ExistingFile((IRemotePathTransformation)data[0], - (string)data[1]); - } - } -#endif public void Scp_Download_DirectoryInfo_ExistingFile(IRemotePathTransformation remotePathTransformation, string remotePath) { @@ -340,20 +290,8 @@ public void Scp_Download_DirectoryInfo_ExistingFile(IRemotePathTransformation re } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpDownloadDirectoryInfoExistingDirectoryData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Download_DirectoryInfo_ExistingDirectory() - { - foreach (var data in GetScpDownloadDirectoryInfoExistingDirectoryData()) - { - Scp_Download_DirectoryInfo_ExistingDirectory((IRemotePathTransformation)data[0], - (string)data[1]); - } - } -#endif public void Scp_Download_DirectoryInfo_ExistingDirectory(IRemotePathTransformation remotePathTransformation, string remotePath) { @@ -495,21 +433,8 @@ public void Scp_Download_DirectoryInfo_ExistingDirectory(IRemotePathTransformati } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpDownloadFileInfoDirectoryDoesNotExistData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Download_FileInfo_DirectoryDoesNotExist() - { - foreach (var data in GetScpDownloadFileInfoDirectoryDoesNotExistData()) - { - Scp_Download_FileInfo_DirectoryDoesNotExist((IRemotePathTransformation)data[0], - (string)data[1], - (string)data[2]); - } - } -#endif public void Scp_Download_FileInfo_DirectoryDoesNotExist(IRemotePathTransformation remotePathTransformation, string remotePath, string remoteFile) @@ -580,21 +505,8 @@ public void Scp_Download_FileInfo_DirectoryDoesNotExist(IRemotePathTransformatio } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpDownloadFileInfoFileDoesNotExistData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Download_FileInfo_FileDoesNotExist() - { - foreach (var data in GetScpDownloadFileInfoFileDoesNotExistData()) - { - Scp_Download_FileInfo_FileDoesNotExist((IRemotePathTransformation)data[0], - (string)data[1], - (string)data[2]); - } - } -#endif public void Scp_Download_FileInfo_FileDoesNotExist(IRemotePathTransformation remotePathTransformation, string remotePath, string remoteFile) @@ -667,20 +579,8 @@ public void Scp_Download_FileInfo_FileDoesNotExist(IRemotePathTransformation rem } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpDownloadFileInfoExistingDirectoryData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Download_FileInfo_ExistingDirectory() - { - foreach (var data in GetScpDownloadFileInfoExistingDirectoryData()) - { - Scp_Download_FileInfo_ExistingDirectory((IRemotePathTransformation)data[0], - (string)data[1]); - } - } -#endif public void Scp_Download_FileInfo_ExistingDirectory(IRemotePathTransformation remotePathTransformation, string remotePath) { @@ -748,22 +648,8 @@ public void Scp_Download_FileInfo_ExistingDirectory(IRemotePathTransformation re } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpDownloadFileInfoExistingFileData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Download_FileInfo_ExistingFile() - { - foreach (var data in GetScpDownloadFileInfoExistingFileData()) - { - Scp_Download_FileInfo_ExistingFile((IRemotePathTransformation)data[0], - (string)data[1], - (string)data[2], - (int)data[3]); - } - } -#endif public void Scp_Download_FileInfo_ExistingFile(IRemotePathTransformation remotePathTransformation, string remotePath, string remoteFile, @@ -854,20 +740,8 @@ public void Scp_Download_FileInfo_ExistingFile(IRemotePathTransformation remoteP } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpDownloadStreamExistingDirectoryData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Download_Stream_ExistingDirectory() - { - foreach (var data in GetScpDownloadStreamExistingDirectoryData()) - { - Scp_Download_Stream_ExistingDirectory((IRemotePathTransformation)data[0], - (string)data[1]); - } - } -#endif public void Scp_Download_Stream_ExistingDirectory(IRemotePathTransformation remotePathTransformation, string remotePath) { @@ -934,22 +808,8 @@ public void Scp_Download_Stream_ExistingDirectory(IRemotePathTransformation remo } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpDownloadStreamExistingFileData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Download_Stream_ExistingFile() - { - foreach (var data in GetScpDownloadStreamExistingFileData()) - { - Scp_Download_Stream_ExistingFile((IRemotePathTransformation)data[0], - (string)data[1], - (string)data[2], - (int)data[3]); - } - } -#endif public void Scp_Download_Stream_ExistingFile(IRemotePathTransformation remotePathTransformation, string remotePath, string remoteFile, @@ -1035,21 +895,8 @@ public void Scp_Download_Stream_ExistingFile(IRemotePathTransformation remotePat } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpUploadFileStreamDirectoryDoesNotExistData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Upload_FileStream_DirectoryDoesNotExist() - { - foreach (var data in GetScpUploadFileStreamDirectoryDoesNotExistData()) - { - Scp_Upload_FileStream_DirectoryDoesNotExist((IRemotePathTransformation)data[0], - (string)data[1], - (string)data[2]); - } - } -#endif public void Scp_Upload_FileStream_DirectoryDoesNotExist(IRemotePathTransformation remotePathTransformation, string remotePath, string remoteFile) @@ -1118,20 +965,8 @@ public void Scp_Upload_FileStream_DirectoryDoesNotExist(IRemotePathTransformatio } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpUploadFileStreamExistingDirectoryData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Upload_FileStream_ExistingDirectory() - { - foreach (var data in GetScpUploadFileStreamExistingDirectoryData()) - { - Scp_Upload_FileStream_ExistingDirectory((IRemotePathTransformation)data[0], - (string)data[1]); - } - } -#endif public void Scp_Upload_FileStream_ExistingDirectory(IRemotePathTransformation remotePathTransformation, string remoteFile) { @@ -1193,20 +1028,8 @@ public void Scp_Upload_FileStream_ExistingDirectory(IRemotePathTransformation re } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(ScpUploadFileStreamExistingFileData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Upload_FileStream_ExistingFile() - { - foreach (var data in ScpUploadFileStreamExistingFileData()) - { - Scp_Upload_FileStream_ExistingFile((IRemotePathTransformation)data[0], - (string)data[1]); - } - } -#endif public void Scp_Upload_FileStream_ExistingFile(IRemotePathTransformation remotePathTransformation, string remoteFile) { @@ -1274,22 +1097,8 @@ public void Scp_Upload_FileStream_ExistingFile(IRemotePathTransformation remoteP } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpUploadFileStreamFileDoesNotExistData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Upload_FileStream_FileDoesNotExist() - { - foreach (var data in GetScpUploadFileStreamFileDoesNotExistData()) - { - Scp_Upload_FileStream_FileDoesNotExist((IRemotePathTransformation)data[0], - (string)data[1], - (string)data[2], - (int)data[3]); - } - } -#endif public void Scp_Upload_FileStream_FileDoesNotExist(IRemotePathTransformation remotePathTransformation, string remotePath, string remoteFile, @@ -1387,21 +1196,8 @@ public void Scp_Upload_FileStream_FileDoesNotExist(IRemotePathTransformation rem /// /// https://github.com/sshnet/SSH.NET/issues/289 /// -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpUploadFileInfoDirectoryDoesNotExistData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Upload_FileInfo_DirectoryDoesNotExist() - { - foreach (var data in GetScpUploadFileInfoDirectoryDoesNotExistData()) - { - Scp_Upload_FileInfo_DirectoryDoesNotExist((IRemotePathTransformation)data[0], - (string)data[1], - (string)data[2]); - } - } -#endif public void Scp_Upload_FileInfo_DirectoryDoesNotExist(IRemotePathTransformation remotePathTransformation, string remotePath, string remoteFile) @@ -1480,20 +1276,8 @@ public void Scp_Upload_FileInfo_DirectoryDoesNotExist(IRemotePathTransformation /// /// https://github.com/sshnet/SSH.NET/issues/286 /// -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpUploadFileInfoExistingDirectoryData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Upload_FileInfo_ExistingDirectory() - { - foreach (var data in GetScpUploadFileInfoExistingDirectoryData()) - { - Scp_Upload_FileInfo_ExistingDirectory((IRemotePathTransformation)data[0], - (string)data[1]); - } - } -#endif public void Scp_Upload_FileInfo_ExistingDirectory(IRemotePathTransformation remotePathTransformation, string remoteFile) { @@ -1554,20 +1338,8 @@ public void Scp_Upload_FileInfo_ExistingDirectory(IRemotePathTransformation remo } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpUploadFileInfoExistingFileData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Upload_FileInfo_ExistingFile() - { - foreach (var data in GetScpUploadFileInfoExistingFileData()) - { - Scp_Upload_FileInfo_ExistingFile((IRemotePathTransformation)data[0], - (string)data[1]); - } - } -#endif public void Scp_Upload_FileInfo_ExistingFile(IRemotePathTransformation remotePathTransformation, string remoteFile) { @@ -1644,22 +1416,8 @@ public void Scp_Upload_FileInfo_ExistingFile(IRemotePathTransformation remotePat } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpUploadFileInfoFileDoesNotExistData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Upload_FileInfo_FileDoesNotExist() - { - foreach (var data in GetScpUploadFileInfoFileDoesNotExistData()) - { - Scp_Upload_FileInfo_FileDoesNotExist((IRemotePathTransformation)data[0], - (string)data[1], - (string)data[2], - (int)data[3]); - } - } -#endif public void Scp_Upload_FileInfo_FileDoesNotExist(IRemotePathTransformation remotePathTransformation, string remotePath, string remoteFile, @@ -1763,20 +1521,8 @@ public void Scp_Upload_FileInfo_FileDoesNotExist(IRemotePathTransformation remot } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpUploadDirectoryInfoDirectoryDoesNotExistData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Upload_DirectoryInfo_DirectoryDoesNotExist() - { - foreach (var data in GetScpUploadDirectoryInfoDirectoryDoesNotExistData()) - { - Scp_Upload_DirectoryInfo_DirectoryDoesNotExist((IRemotePathTransformation)data[0], - (string)data[1]); - } - } -#endif public void Scp_Upload_DirectoryInfo_DirectoryDoesNotExist(IRemotePathTransformation remotePathTransformation, string remoteDirectory) { @@ -1840,20 +1586,8 @@ public void Scp_Upload_DirectoryInfo_DirectoryDoesNotExist(IRemotePathTransforma } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpUploadDirectoryInfoExistingDirectoryData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Upload_DirectoryInfo_ExistingDirectory() - { - foreach (var data in GetScpUploadDirectoryInfoExistingDirectoryData()) - { - Scp_Upload_DirectoryInfo_ExistingDirectory((IRemotePathTransformation)data[0], - (string)data[1]); - } - } -#endif public void Scp_Upload_DirectoryInfo_ExistingDirectory(IRemotePathTransformation remotePathTransformation, string remoteDirectory) { @@ -2056,20 +1790,8 @@ public void Scp_Upload_DirectoryInfo_ExistingDirectory(IRemotePathTransformation } } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetScpUploadDirectoryInfoExistingFileData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Scp_Upload_DirectoryInfo_ExistingFile() - { - foreach (var data in GetScpUploadDirectoryInfoExistingFileData()) - { - Scp_Upload_DirectoryInfo_ExistingFile((IRemotePathTransformation)data[0], - (string)data[1]); - } - } -#endif public void Scp_Upload_DirectoryInfo_ExistingFile(IRemotePathTransformation remotePathTransformation, string remoteDirectory) { diff --git a/test/Renci.SshNet.IntegrationTests/SftpTests.cs b/test/Renci.SshNet.IntegrationTests/SftpTests.cs index 8c1f91660..e6f40c05e 100644 --- a/test/Renci.SshNet.IntegrationTests/SftpTests.cs +++ b/test/Renci.SshNet.IntegrationTests/SftpTests.cs @@ -25,19 +25,8 @@ public void SetUp() _remotePathTransformation = RemotePathTransformation.ShellQuote; } -#if FEATURE_MSTEST_DATATEST [DataTestMethod] [DynamicData(nameof(GetSftpUploadFileFileStreamData), DynamicDataSourceType.Method)] -#else - [TestMethod] - public void Sftp_Upload_DirectoryInfo_ExistingFile() - { - foreach (var data in GetSftpUploadFileFileStreamData()) - { - Sftp_UploadFile_FileStream((int) data[0]); - } - } -#endif public void Sftp_UploadFile_FileStream(int size) { var file = CreateTempFile(size); From 823bc1b67bcbce3d1e1a5a91236c77f7970055ae Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Mon, 13 Nov 2023 05:07:26 +0000 Subject: [PATCH 66/96] Use CollectionAssert in ListDirectory tests (#1166) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use CollectionAssert in ListDirectory tests * Indent the braces --------- Co-authored-by: Wojciech Nag贸rski --- .../SftpClientTests.cs | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/test/Renci.SshNet.IntegrationTests/SftpClientTests.cs b/test/Renci.SshNet.IntegrationTests/SftpClientTests.cs index ee0258cdc..535b07bce 100644 --- a/test/Renci.SshNet.IntegrationTests/SftpClientTests.cs +++ b/test/Renci.SshNet.IntegrationTests/SftpClientTests.cs @@ -34,21 +34,21 @@ public void Create_directory_with_contents_and_list_it() Assert.IsTrue(_sftpClient.Exists(testFilePath)); // Check if ListDirectory works - var files = _sftpClient.ListDirectory(testDirectory); + var expectedFiles = new List<(string FullName, bool IsRegularFile, bool IsDirectory)>() + { + ("/home/sshnet/sshnet-test/.", IsRegularFile: false, IsDirectory: true), + ("/home/sshnet/sshnet-test/..", IsRegularFile: false, IsDirectory: true), + ("/home/sshnet/sshnet-test/test-file.txt", IsRegularFile: true, IsDirectory: false), + }; + + var actualFiles = _sftpClient.ListDirectory(testDirectory) + .Select(f => (f.FullName, f.IsRegularFile, f.IsDirectory)) + .ToList(); _sftpClient.DeleteFile(testFilePath); _sftpClient.DeleteDirectory(testDirectory); - var builder = new StringBuilder(); - foreach (var file in files) - { - builder.AppendLine($"{file.FullName} {file.IsRegularFile} {file.IsDirectory}"); - } - - Assert.AreEqual(@"/home/sshnet/sshnet-test/. False True -/home/sshnet/sshnet-test/.. False True -/home/sshnet/sshnet-test/test-file.txt True False -", builder.ToString()); + CollectionAssert.AreEquivalent(expectedFiles, actualFiles); } [TestMethod] @@ -69,21 +69,24 @@ public async Task Create_directory_with_contents_and_list_it_async() Assert.IsTrue(_sftpClient.Exists(testFilePath)); // Check if ListDirectory works - var files = _sftpClient.ListDirectoryAsync(testDirectory, CancellationToken.None); + var expectedFiles = new List<(string FullName, bool IsRegularFile, bool IsDirectory)>() + { + ("/home/sshnet/sshnet-test/.", IsRegularFile: false, IsDirectory: true), + ("/home/sshnet/sshnet-test/..", IsRegularFile: false, IsDirectory: true), + ("/home/sshnet/sshnet-test/test-file.txt", IsRegularFile: true, IsDirectory: false), + }; + + var actualFiles = new List<(string FullName, bool IsRegularFile, bool IsDirectory)>(); - var builder = new StringBuilder(); - await foreach (var file in files) + await foreach (var file in _sftpClient.ListDirectoryAsync(testDirectory, CancellationToken.None)) { - builder.AppendLine($"{file.FullName} {file.IsRegularFile} {file.IsDirectory}"); + actualFiles.Add((file.FullName, file.IsRegularFile, file.IsDirectory)); } _sftpClient.DeleteFile(testFilePath); _sftpClient.DeleteDirectory(testDirectory); - Assert.AreEqual(@"/home/sshnet/sshnet-test/. False True -/home/sshnet/sshnet-test/.. False True -/home/sshnet/sshnet-test/test-file.txt True False -", builder.ToString()); + CollectionAssert.AreEquivalent(expectedFiles, actualFiles); } [TestMethod] From 2eec748b184e6ef3dfec93649c1ca1bdc27a627a Mon Sep 17 00:00:00 2001 From: Pedro Fonseca Date: Mon, 13 Nov 2023 06:08:57 +0100 Subject: [PATCH 67/96] Improve SFTP performance on medium/high latency connections (#866) * Improve SFTP performance on medium-high latency connections - Increases maxPendingReads from 10 to 100 - Increases socket send/receive buffer to 10 SSH packets (320K) * Fix merge * Adjust SFTP FileReader testcases to accept new MaxPendingReads values * Fix CreateSftpFileReader testcase, make it dependant on MaxPendingReads constant --------- Co-authored-by: Pedro Fonseca --- src/Renci.SshNet/Connection/ConnectorBase.cs | 2 +- src/Renci.SshNet/ServiceFactory.cs | 4 ++-- ...est_CreateSftpFileReader_EndLStatThrowsSshException.cs | 2 +- ...er_FileSizeIsMoreThanMaxPendingReadsTimesChunkSize.cs} | 8 +++++--- 4 files changed, 9 insertions(+), 7 deletions(-) rename test/Renci.SshNet.Tests/Classes/{ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs => ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanMaxPendingReadsTimesChunkSize.cs} (92%) diff --git a/src/Renci.SshNet/Connection/ConnectorBase.cs b/src/Renci.SshNet/Connection/ConnectorBase.cs index bdea64a6f..58b45960a 100644 --- a/src/Renci.SshNet/Connection/ConnectorBase.cs +++ b/src/Renci.SshNet/Connection/ConnectorBase.cs @@ -49,7 +49,7 @@ protected Socket SocketConnect(string host, int port, TimeSpan timeout) { SocketAbstraction.Connect(socket, ep, timeout); - const int socketBufferSize = 2 * Session.MaximumSshPacketSize; + const int socketBufferSize = 10 * Session.MaximumSshPacketSize; socket.SendBufferSize = socketBufferSize; socket.ReceiveBufferSize = socketBufferSize; return socket; diff --git a/src/Renci.SshNet/ServiceFactory.cs b/src/Renci.SshNet/ServiceFactory.cs index c41c3679e..af30f11c8 100644 --- a/src/Renci.SshNet/ServiceFactory.cs +++ b/src/Renci.SshNet/ServiceFactory.cs @@ -143,7 +143,7 @@ public INetConfSession CreateNetConfSession(ISession session, int operationTimeo /// public ISftpFileReader CreateSftpFileReader(string fileName, ISftpSession sftpSession, uint bufferSize) { - const int defaultMaxPendingReads = 3; + const int defaultMaxPendingReads = 10; // Issue #292: Avoid overlapping SSH_FXP_OPEN and SSH_FXP_LSTAT requests for the same file as this // causes a performance degradation on Sun SSH @@ -163,7 +163,7 @@ public ISftpFileReader CreateSftpFileReader(string fileName, ISftpSession sftpSe { var fileAttributes = sftpSession.EndLStat(statAsyncResult); fileSize = fileAttributes.Size; - maxPendingReads = Math.Min(10, (int) Math.Ceiling((double) fileAttributes.Size / chunkSize) + 1); + maxPendingReads = Math.Min(100, (int)Math.Ceiling((double)fileAttributes.Size / chunkSize) + 1); } catch (SshException ex) { diff --git a/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs index ee3db7cba..6184a05d1 100644 --- a/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs +++ b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_EndLStatThrowsSshException.cs @@ -59,7 +59,7 @@ private void SetupMocks() .Setup(p => p.EndLStat(_statAsyncResult)) .Throws(new SshException()); _sftpSessionMock.InSequence(seq) - .Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 3, null)) + .Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 10, null)) .Returns(_sftpFileReaderMock.Object); } diff --git a/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanMaxPendingReadsTimesChunkSize.cs similarity index 92% rename from test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs rename to test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanMaxPendingReadsTimesChunkSize.cs index dad634472..8fe220c80 100644 --- a/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize.cs +++ b/test/Renci.SshNet.Tests/Classes/ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanMaxPendingReadsTimesChunkSize.cs @@ -8,7 +8,7 @@ namespace Renci.SshNet.Tests.Classes { [TestClass] - public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesGreaterThanChunkSize + public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanMaxPendingReadsTimesChunkSize { private ServiceFactory _serviceFactory; private Mock _sftpSessionMock; @@ -22,18 +22,20 @@ public class ServiceFactoryTest_CreateSftpFileReader_FileSizeIsMoreThanTenTimesG private SftpFileAttributes _fileAttributes; private long _fileSize; private ISftpFileReader _actual; + private int _maxPendingReads; private void SetupData() { var random = new Random(); + _maxPendingReads = 100; _bufferSize = (uint)random.Next(1, int.MaxValue); _openAsyncResult = new SftpOpenAsyncResult(null, null); _handle = CryptoAbstraction.GenerateRandom(random.Next(1, 10)); _statAsyncResult = new SFtpStatAsyncResult(null, null); _fileName = random.Next().ToString(); _chunkSize = (uint) random.Next(1000, 5000); - _fileSize = _chunkSize * random.Next(11, 50); + _fileSize = _chunkSize * random.Next(_maxPendingReads + 1, _maxPendingReads * 2); _fileAttributes = new SftpFileAttributesBuilder().WithSize(_fileSize).Build(); } @@ -63,7 +65,7 @@ private void SetupMocks() .Setup(p => p.EndLStat(_statAsyncResult)) .Returns(_fileAttributes); _sftpSessionMock.InSequence(seq) - .Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, 10, _fileSize)) + .Setup(p => p.CreateFileReader(_handle, _sftpSessionMock.Object, _chunkSize, _maxPendingReads, _fileSize)) .Returns(_sftpFileReaderMock.Object); } From 58284d6019460a9881b37f653661e0fcb0e74af1 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Thu, 16 Nov 2023 05:05:37 +0000 Subject: [PATCH 68/96] Update global.json (#1240) --- .editorconfig | 7 +++++++ global.json | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 944a6bf07..30ee78be8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -557,6 +557,13 @@ dotnet_diagnostic.CA2208.severity = none #### Roslyn IDE analyser rules #### +# IDE0028: Simplify collection initialization; and +# IDE0305: Simplify collection initialization +# +# Temporarily suppressing collection expression recommendations coming from .NET 8 SDK +dotnet_diagnostic.IDE0028.severity = none +dotnet_diagnostic.IDE0305.severity = none + # IDE0032: Use auto-implemented property # # For performance reasons, we do not always want to enforce the use of diff --git a/global.json b/global.json index 0da2d5ff3..9d9cefcc5 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { "version": "7.0.403", - "rollForward": "disable" + "rollForward": "latestMajor" } } From b4c829105abb5d1a5ee24ee2a143119fcbd9a276 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Thu, 16 Nov 2023 05:39:42 +0000 Subject: [PATCH 69/96] Tweak diagnostics (#1241) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make it work (it needs the TRACE symbol defined - lots of head scratching without it) * Expose publicly, but still in DEBUG (to allow programmatic configuration necessary in Core) * Document how to use it * Tweak usage (add some logs, remove key/iv information, override ToString on some Message types) Co-authored-by: Wojciech Nag贸rski --- .../Abstractions/DiagnosticAbstraction.cs | 68 +++++++++++++++---- .../Messages/Authentication/FailureMessage.cs | 8 +++ .../Authentication/PublicKeyMessage.cs | 6 ++ .../Messages/Authentication/RequestMessage.cs | 6 ++ .../Authentication/RequestMessagePublicKey.cs | 6 ++ src/Renci.SshNet/Renci.SshNet.csproj | 4 +- src/Renci.SshNet/Security/KeyExchange.cs | 26 +++++-- src/Renci.SshNet/Session.cs | 6 +- 8 files changed, 107 insertions(+), 23 deletions(-) diff --git a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs index 014d70689..9de9bbea4 100644 --- a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs @@ -1,27 +1,65 @@ -锘縰sing System.Diagnostics; +锘縰sing System.ComponentModel; +using System.Diagnostics; namespace Renci.SshNet.Abstractions { - internal static class DiagnosticAbstraction + /// + /// Provides access to the internals of SSH.NET. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static class DiagnosticAbstraction { - private static readonly SourceSwitch SourceSwitch = new SourceSwitch("SshNetSwitch"); - - public static bool IsEnabled(TraceEventType traceEventType) - { - return SourceSwitch.ShouldTrace(traceEventType); - } - - private static readonly TraceSource Loggging = #if DEBUG - new TraceSource("SshNet.Logging", SourceLevels.All); -#else - new TraceSource("SshNet.Logging"); -#endif // DEBUG + /// + /// The instance used by SSH.NET. + /// + /// + /// + /// Configuration on .NET Core must be done programmatically, e.g. + /// + /// DiagnosticAbstraction.Source.Switch = new SourceSwitch("sourceSwitch", "Verbose"); + /// DiagnosticAbstraction.Source.Listeners.Remove("Default"); + /// DiagnosticAbstraction.Source.Listeners.Add(new ConsoleTraceListener()); + /// DiagnosticAbstraction.Source.Listeners.Add(new TextWriterTraceListener("trace.log")); + /// + /// + /// + /// On .NET Framework, it is possible to configure via App.config, e.g. + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// ]]> + /// + /// + /// + public static readonly TraceSource Source = new TraceSource("SshNet.Logging"); +#endif + /// + /// Logs a message to at the + /// level. + /// + /// The message to log. [Conditional("DEBUG")] public static void Log(string text) { - Loggging.TraceEvent(TraceEventType.Verbose, + Source.TraceEvent(TraceEventType.Verbose, System.Environment.CurrentManagedThreadId, text); } diff --git a/src/Renci.SshNet/Messages/Authentication/FailureMessage.cs b/src/Renci.SshNet/Messages/Authentication/FailureMessage.cs index 61379600f..f02705ecb 100644 --- a/src/Renci.SshNet/Messages/Authentication/FailureMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/FailureMessage.cs @@ -60,5 +60,13 @@ internal override void Process(Session session) { session.OnUserAuthenticationFailureReceived(this); } + + /// + public override string ToString() + { +#pragma warning disable MA0089 // Optimize string method usage + return $"SSH_MSG_USERAUTH_FAILURE {string.Join(",", AllowedAuthentications)} ({nameof(PartialSuccess)}:{PartialSuccess})"; +#pragma warning restore MA0089 // Optimize string method usage + } } } diff --git a/src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs b/src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs index b5582b788..b917ab99a 100644 --- a/src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs @@ -60,5 +60,11 @@ protected override void SaveData() WriteBinaryString(PublicKeyAlgorithmName); WriteBinaryString(PublicKeyData); } + + /// + public override string ToString() + { + return $"SSH_MSG_USERAUTH_PK_OK ({Ascii.GetString(PublicKeyAlgorithmName)})"; + } } } diff --git a/src/Renci.SshNet/Messages/Authentication/RequestMessage.cs b/src/Renci.SshNet/Messages/Authentication/RequestMessage.cs index 5393df3f7..57f60849f 100644 --- a/src/Renci.SshNet/Messages/Authentication/RequestMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/RequestMessage.cs @@ -106,5 +106,11 @@ internal override void Process(Session session) { throw new NotImplementedException(); } + + /// + public override string ToString() + { + return $"SSH_MSG_USERAUTH_REQUEST ({MethodName})"; + } } } diff --git a/src/Renci.SshNet/Messages/Authentication/RequestMessagePublicKey.cs b/src/Renci.SshNet/Messages/Authentication/RequestMessagePublicKey.cs index 391e60e76..a759ef20c 100644 --- a/src/Renci.SshNet/Messages/Authentication/RequestMessagePublicKey.cs +++ b/src/Renci.SshNet/Messages/Authentication/RequestMessagePublicKey.cs @@ -96,5 +96,11 @@ protected override void SaveData() WriteBinaryString(Signature); } } + + /// + public override string ToString() + { + return $"{base.ToString()} {Ascii.GetString(PublicKeyAlgorithmName)} {(Signature != null ? "with" : "without")} signature."; + } } } diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index 4ccf6c72e..89e82349d 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -6,7 +6,7 @@ - FEATURE_BINARY_SERIALIZATION;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_DNS_SYNC;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160 + $(DefineConstants);FEATURE_BINARY_SERIALIZATION;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_DNS_SYNC;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160 @@ -18,6 +18,6 @@ - FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP + $(DefineConstants);FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP diff --git a/src/Renci.SshNet/Security/KeyExchange.cs b/src/Renci.SshNet/Security/KeyExchange.cs index 5024941bf..44684a92e 100644 --- a/src/Renci.SshNet/Security/KeyExchange.cs +++ b/src/Renci.SshNet/Security/KeyExchange.cs @@ -183,11 +183,9 @@ public Cipher CreateServerCipher() serverKey = GenerateSessionKey(SharedKey, ExchangeHash, serverKey, _serverCipherInfo.KeySize / 8); - DiagnosticAbstraction.Log(string.Format("[{0}] Creating server cipher (Name:{1},Key:{2},IV:{3})", + DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} server cipher.", Session.ToHex(Session.SessionId), - Session.ConnectionInfo.CurrentServerEncryption, - Session.ToHex(serverKey), - Session.ToHex(serverVector))); + Session.ConnectionInfo.CurrentServerEncryption)); // Create server cipher return _serverCipherInfo.Cipher(serverKey, serverVector); @@ -210,6 +208,10 @@ public Cipher CreateClientCipher() clientKey = GenerateSessionKey(SharedKey, ExchangeHash, clientKey, _clientCipherInfo.KeySize / 8); + DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} client cipher.", + Session.ToHex(Session.SessionId), + Session.ConnectionInfo.CurrentClientEncryption)); + // Create client cipher return _clientCipherInfo.Cipher(clientKey, clientVector); } @@ -230,6 +232,10 @@ public HashAlgorithm CreateServerHash() Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'F', sessionId)), _serverHashInfo.KeySize / 8); + DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} server hmac algorithm.", + Session.ToHex(Session.SessionId), + Session.ConnectionInfo.CurrentServerHmacAlgorithm)); + return _serverHashInfo.HashAlgorithm(serverKey); } @@ -249,6 +255,10 @@ public HashAlgorithm CreateClientHash() Hash(GenerateSessionKey(SharedKey, ExchangeHash, 'E', sessionId)), _clientHashInfo.KeySize / 8); + DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} client hmac algorithm.", + Session.ToHex(Session.SessionId), + Session.ConnectionInfo.CurrentClientHmacAlgorithm)); + return _clientHashInfo.HashAlgorithm(clientKey); } @@ -265,6 +275,10 @@ public Compressor CreateCompressor() return null; } + DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} client compressor.", + Session.ToHex(Session.SessionId), + Session.ConnectionInfo.CurrentClientCompressionAlgorithm)); + var compressor = _compressionType.CreateInstance(); compressor.Init(Session); @@ -285,6 +299,10 @@ public Compressor CreateDecompressor() return null; } + DiagnosticAbstraction.Log(string.Format("[{0}] Creating {1} server decompressor.", + Session.ToHex(Session.SessionId), + Session.ConnectionInfo.CurrentServerCompressionAlgorithm)); + var decompressor = _decompressionType.CreateInstance(); decompressor.Init(Session); diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index 2d913d072..f05c0e0a0 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -616,7 +616,7 @@ public void Connect() ServerVersion = ConnectionInfo.ServerVersion = serverIdentification.ToString(); ConnectionInfo.ClientVersion = ClientVersion; - DiagnosticAbstraction.Log(string.Format("Server version '{0}' on '{1}'.", serverIdentification.ProtocolVersion, serverIdentification.SoftwareVersion)); + DiagnosticAbstraction.Log(string.Format("Server version '{0}'.", serverIdentification)); if (!(serverIdentification.ProtocolVersion.Equals("2.0") || serverIdentification.ProtocolVersion.Equals("1.99"))) { @@ -728,7 +728,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken) ServerVersion = ConnectionInfo.ServerVersion = serverIdentification.ToString(); ConnectionInfo.ClientVersion = ClientVersion; - DiagnosticAbstraction.Log(string.Format("Server version '{0}' on '{1}'.", serverIdentification.ProtocolVersion, serverIdentification.SoftwareVersion)); + DiagnosticAbstraction.Log(string.Format("Server version '{0}'.", serverIdentification)); if (!(serverIdentification.ProtocolVersion.Equals("2.0") || serverIdentification.ProtocolVersion.Equals("1.99"))) { @@ -1397,6 +1397,8 @@ internal void OnKeyExchangeInitReceived(KeyExchangeInitMessage message) ConnectionInfo.CurrentKeyExchangeAlgorithm = _keyExchange.Name; + DiagnosticAbstraction.Log(string.Format("[{0}] Performing {1} key exchange.", ToHex(SessionId), ConnectionInfo.CurrentKeyExchangeAlgorithm)); + _keyExchange.HostKeyReceived += KeyExchange_HostKeyReceived; // Start the algorithm implementation From 5021f6d4bb05113ca9bfef279d93687b09c66fcb Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Thu, 16 Nov 2023 06:05:22 +0000 Subject: [PATCH 70/96] Use System.Security.Cryptography in AesCipher (#1235) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use System.Security.Cryptography in AesCipher * don't set the IV - it is unused by ECB * Dispose ciphers in Session if applicable --------- Co-authored-by: Wojciech Nag贸rski --- src/Renci.SshNet/PrivateKeyFile.cs | 9 +- .../Cryptography/Ciphers/AesCipher.cs | 808 +----------------- src/Renci.SshNet/Session.cs | 20 + .../Renci.SshNet.IntegrationTests/SshTests.cs | 2 +- 4 files changed, 56 insertions(+), 783 deletions(-) diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index eb7b3767b..21c34cfe0 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -531,7 +531,14 @@ private static Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) throw new SshException("Cipher '" + cipherName + "' is not supported for an OpenSSH key."); } - privateKeyBytes = cipher.Decrypt(privateKeyBytes); + try + { + privateKeyBytes = cipher.Decrypt(privateKeyBytes); + } + finally + { + cipher.Dispose(); + } } // validate private key length diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs index 517f2b463..235040446 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs @@ -1,559 +1,16 @@ 锘縰sing System; -using System.Globalization; - -using Renci.SshNet.Common; +using System.Security.Cryptography; namespace Renci.SshNet.Security.Cryptography.Ciphers { /// /// AES cipher implementation. /// - public sealed class AesCipher : BlockCipher + public sealed class AesCipher : BlockCipher, IDisposable { - private const uint M1 = 0x80808080; - private const uint M2 = 0x7f7f7f7f; - private const uint M3 = 0x0000001b; - - private int _rounds; - private uint[] _encryptionKey; - private uint[] _decryptionKey; - private uint _c0; - private uint _c1; - private uint _c2; - private uint _c3; - - #region Static Definition Tables - - private static readonly byte[] S = - { - 99, 124, 119, 123, 242, 107, 111, 197, - 48, 1, 103, 43, 254, 215, 171, 118, - 202, 130, 201, 125, 250, 89, 71, 240, - 173, 212, 162, 175, 156, 164, 114, 192, - 183, 253, 147, 38, 54, 63, 247, 204, - 52, 165, 229, 241, 113, 216, 49, 21, - 4, 199, 35, 195, 24, 150, 5, 154, - 7, 18, 128, 226, 235, 39, 178, 117, - 9, 131, 44, 26, 27, 110, 90, 160, - 82, 59, 214, 179, 41, 227, 47, 132, - 83, 209, 0, 237, 32, 252, 177, 91, - 106, 203, 190, 57, 74, 76, 88, 207, - 208, 239, 170, 251, 67, 77, 51, 133, - 69, 249, 2, 127, 80, 60, 159, 168, - 81, 163, 64, 143, 146, 157, 56, 245, - 188, 182, 218, 33, 16, 255, 243, 210, - 205, 12, 19, 236, 95, 151, 68, 23, - 196, 167, 126, 61, 100, 93, 25, 115, - 96, 129, 79, 220, 34, 42, 144, 136, - 70, 238, 184, 20, 222, 94, 11, 219, - 224, 50, 58, 10, 73, 6, 36, 92, - 194, 211, 172, 98, 145, 149, 228, 121, - 231, 200, 55, 109, 141, 213, 78, 169, - 108, 86, 244, 234, 101, 122, 174, 8, - 186, 120, 37, 46, 28, 166, 180, 198, - 232, 221, 116, 31, 75, 189, 139, 138, - 112, 62, 181, 102, 72, 3, 246, 14, - 97, 53, 87, 185, 134, 193, 29, 158, - 225, 248, 152, 17, 105, 217, 142, 148, - 155, 30, 135, 233, 206, 85, 40, 223, - 140, 161, 137, 13, 191, 230, 66, 104, - 65, 153, 45, 15, 176, 84, 187, 22 - }; - - // The inverse S-box - private static readonly byte[] Si = - { - 82, 9, 106, 213, 48, 54, 165, 56, - 191, 64, 163, 158, 129, 243, 215, 251, - 124, 227, 57, 130, 155, 47, 255, 135, - 52, 142, 67, 68, 196, 222, 233, 203, - 84, 123, 148, 50, 166, 194, 35, 61, - 238, 76, 149, 11, 66, 250, 195, 78, - 8, 46, 161, 102, 40, 217, 36, 178, - 118, 91, 162, 73, 109, 139, 209, 37, - 114, 248, 246, 100, 134, 104, 152, 22, - 212, 164, 92, 204, 93, 101, 182, 146, - 108, 112, 72, 80, 253, 237, 185, 218, - 94, 21, 70, 87, 167, 141, 157, 132, - 144, 216, 171, 0, 140, 188, 211, 10, - 247, 228, 88, 5, 184, 179, 69, 6, - 208, 44, 30, 143, 202, 63, 15, 2, - 193, 175, 189, 3, 1, 19, 138, 107, - 58, 145, 17, 65, 79, 103, 220, 234, - 151, 242, 207, 206, 240, 180, 230, 115, - 150, 172, 116, 34, 231, 173, 53, 133, - 226, 249, 55, 232, 28, 117, 223, 110, - 71, 241, 26, 113, 29, 41, 197, 137, - 111, 183, 98, 14, 170, 24, 190, 27, - 252, 86, 62, 75, 198, 210, 121, 32, - 154, 219, 192, 254, 120, 205, 90, 244, - 31, 221, 168, 51, 136, 7, 199, 49, - 177, 18, 16, 89, 39, 128, 236, 95, - 96, 81, 127, 169, 25, 181, 74, 13, - 45, 229, 122, 159, 147, 201, 156, 239, - 160, 224, 59, 77, 174, 42, 245, 176, - 200, 235, 187, 60, 131, 83, 153, 97, - 23, 43, 4, 126, 186, 119, 214, 38, - 225, 105, 20, 99, 85, 33, 12, 125 - }; - - // vector used in calculating key schedule (powers of x in GF(256)) - private static readonly byte[] Rcon = - { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, - 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 - }; - - // precomputation tables of calculations for rounds - private static readonly uint[] T0 = - { - 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, - 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, - 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, - 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, - 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41, - 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, - 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, - 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, - 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, - 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, - 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, - 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, - 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, - 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, - 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, - 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, - 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, - 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, - 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, - 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, - 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, - 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, - 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, - 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, - 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, - 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, - 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, - 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, - 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, - 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, - 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, - 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, - 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, - 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, - 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, - 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, - 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, - 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, - 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, - 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, - 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, - 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, - 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, - 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, - 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, - 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, - 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, - 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, - 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, - 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, - 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, - 0x3a16162c - }; - - private static readonly uint[] T1 = - { - 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, 0xf2f2ff0d, - 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, 0x30306050, 0x01010203, - 0x6767cea9, 0x2b2b567d, 0xfefee719, 0xd7d7b562, 0xabab4de6, - 0x7676ec9a, 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, - 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, 0xadad41ec, - 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, 0x9c9c23bf, 0xa4a453f7, - 0x7272e496, 0xc0c09b5b, 0xb7b775c2, 0xfdfde11c, 0x93933dae, - 0x26264c6a, 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, - 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, 0x7171e293, - 0xd8d8ab73, 0x31316253, 0x15152a3f, 0x0404080c, 0xc7c79552, - 0x23234665, 0xc3c39d5e, 0x18183028, 0x969637a1, 0x05050a0f, - 0x9a9a2fb5, 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, - 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, 0x0909121b, - 0x83831d9e, 0x2c2c5874, 0x1a1a342e, 0x1b1b362d, 0x6e6edcb2, - 0x5a5ab4ee, 0xa0a05bfb, 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, - 0xb3b37dce, 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, - 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, 0x20204060, - 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, 0x6a6ad4be, 0xcbcb8d46, - 0xbebe67d9, 0x3939724b, 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, - 0xcfcf854a, 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, - 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, 0x45458acf, - 0xf9f9e910, 0x02020406, 0x7f7ffe81, 0x5050a0f0, 0x3c3c7844, - 0x9f9f25ba, 0xa8a84be3, 0x5151a2f3, 0xa3a35dfe, 0x404080c0, - 0x8f8f058a, 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, - 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, 0x10102030, - 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, 0xcdcd814c, 0x0c0c1814, - 0x13132635, 0xececc32f, 0x5f5fbee1, 0x979735a2, 0x444488cc, - 0x17172e39, 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, - 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, 0x6060c0a0, - 0x81811998, 0x4f4f9ed1, 0xdcdca37f, 0x22224466, 0x2a2a547e, - 0x90903bab, 0x88880b83, 0x46468cca, 0xeeeec729, 0xb8b86bd3, - 0x1414283c, 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, - 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, 0x494992db, - 0x06060c0a, 0x2424486c, 0x5c5cb8e4, 0xc2c29f5d, 0xd3d3bd6e, - 0xacac43ef, 0x6262c4a6, 0x919139a8, 0x959531a4, 0xe4e4d337, - 0x7979f28b, 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, - 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, 0x6c6cd8b4, - 0x5656acfa, 0xf4f4f307, 0xeaeacf25, 0x6565caaf, 0x7a7af48e, - 0xaeae47e9, 0x08081018, 0xbaba6fd5, 0x7878f088, 0x25254a6f, - 0x2e2e5c72, 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, - 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, 0x4b4b96dd, - 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, 0x7070e090, 0x3e3e7c42, - 0xb5b571c4, 0x6666ccaa, 0x484890d8, 0x03030605, 0xf6f6f701, - 0x0e0e1c12, 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, - 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, 0xe1e1d938, - 0xf8f8eb13, 0x98982bb3, 0x11112233, 0x6969d2bb, 0xd9d9a970, - 0x8e8e0789, 0x949433a7, 0x9b9b2db6, 0x1e1e3c22, 0x87871592, - 0xe9e9c920, 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, - 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, 0xbfbf65da, - 0xe6e6d731, 0x424284c6, 0x6868d0b8, 0x414182c3, 0x999929b0, - 0x2d2d5a77, 0x0f0f1e11, 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, - 0x16162c3a - }; - - private static readonly uint[] T2 = - { - 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, 0xf2ff0df2, - 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, 0x30605030, 0x01020301, - 0x67cea967, 0x2b567d2b, 0xfee719fe, 0xd7b562d7, 0xab4de6ab, - 0x76ec9a76, 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, - 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, 0xad41ecad, - 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, 0x9c23bf9c, 0xa453f7a4, - 0x72e49672, 0xc09b5bc0, 0xb775c2b7, 0xfde11cfd, 0x933dae93, - 0x264c6a26, 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, - 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, 0x71e29371, - 0xd8ab73d8, 0x31625331, 0x152a3f15, 0x04080c04, 0xc79552c7, - 0x23466523, 0xc39d5ec3, 0x18302818, 0x9637a196, 0x050a0f05, - 0x9a2fb59a, 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, - 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, 0x09121b09, - 0x831d9e83, 0x2c58742c, 0x1a342e1a, 0x1b362d1b, 0x6edcb26e, - 0x5ab4ee5a, 0xa05bfba0, 0x52a4f652, 0x3b764d3b, 0xd6b761d6, - 0xb37dceb3, 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, - 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, 0x20406020, - 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, 0x6ad4be6a, 0xcb8d46cb, - 0xbe67d9be, 0x39724b39, 0x4a94de4a, 0x4c98d44c, 0x58b0e858, - 0xcf854acf, 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, - 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, 0x458acf45, - 0xf9e910f9, 0x02040602, 0x7ffe817f, 0x50a0f050, 0x3c78443c, - 0x9f25ba9f, 0xa84be3a8, 0x51a2f351, 0xa35dfea3, 0x4080c040, - 0x8f058a8f, 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, - 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, 0x10203010, - 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, 0xcd814ccd, 0x0c18140c, - 0x13263513, 0xecc32fec, 0x5fbee15f, 0x9735a297, 0x4488cc44, - 0x172e3917, 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, - 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, 0x60c0a060, - 0x81199881, 0x4f9ed14f, 0xdca37fdc, 0x22446622, 0x2a547e2a, - 0x903bab90, 0x880b8388, 0x468cca46, 0xeec729ee, 0xb86bd3b8, - 0x14283c14, 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, - 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, 0x4992db49, - 0x060c0a06, 0x24486c24, 0x5cb8e45c, 0xc29f5dc2, 0xd3bd6ed3, - 0xac43efac, 0x62c4a662, 0x9139a891, 0x9531a495, 0xe4d337e4, - 0x79f28b79, 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, - 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, 0x6cd8b46c, - 0x56acfa56, 0xf4f307f4, 0xeacf25ea, 0x65caaf65, 0x7af48e7a, - 0xae47e9ae, 0x08101808, 0xba6fd5ba, 0x78f08878, 0x254a6f25, - 0x2e5c722e, 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, - 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, 0x4b96dd4b, - 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, 0x70e09070, 0x3e7c423e, - 0xb571c4b5, 0x66ccaa66, 0x4890d848, 0x03060503, 0xf6f701f6, - 0x0e1c120e, 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, - 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, 0xe1d938e1, - 0xf8eb13f8, 0x982bb398, 0x11223311, 0x69d2bb69, 0xd9a970d9, - 0x8e07898e, 0x9433a794, 0x9b2db69b, 0x1e3c221e, 0x87159287, - 0xe9c920e9, 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, - 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, 0xbf65dabf, - 0xe6d731e6, 0x4284c642, 0x68d0b868, 0x4182c341, 0x9929b099, - 0x2d5a772d, 0x0f1e110f, 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, - 0x162c3a16 - }; - - private static readonly uint[] T3 = - { - 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, 0xff0df2f2, - 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, 0x60503030, 0x02030101, - 0xcea96767, 0x567d2b2b, 0xe719fefe, 0xb562d7d7, 0x4de6abab, - 0xec9a7676, 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, - 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, 0x41ecadad, - 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, 0x23bf9c9c, 0x53f7a4a4, - 0xe4967272, 0x9b5bc0c0, 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, - 0x4c6a2626, 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, - 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, 0xe2937171, - 0xab73d8d8, 0x62533131, 0x2a3f1515, 0x080c0404, 0x9552c7c7, - 0x46652323, 0x9d5ec3c3, 0x30281818, 0x37a19696, 0x0a0f0505, - 0x2fb59a9a, 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, - 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, 0x121b0909, - 0x1d9e8383, 0x58742c2c, 0x342e1a1a, 0x362d1b1b, 0xdcb26e6e, - 0xb4ee5a5a, 0x5bfba0a0, 0xa4f65252, 0x764d3b3b, 0xb761d6d6, - 0x7dceb3b3, 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, - 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, 0x40602020, - 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, 0xd4be6a6a, 0x8d46cbcb, - 0x67d9bebe, 0x724b3939, 0x94de4a4a, 0x98d44c4c, 0xb0e85858, - 0x854acfcf, 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, - 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, 0x8acf4545, - 0xe910f9f9, 0x04060202, 0xfe817f7f, 0xa0f05050, 0x78443c3c, - 0x25ba9f9f, 0x4be3a8a8, 0xa2f35151, 0x5dfea3a3, 0x80c04040, - 0x058a8f8f, 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, - 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, 0x20301010, - 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, 0x814ccdcd, 0x18140c0c, - 0x26351313, 0xc32fecec, 0xbee15f5f, 0x35a29797, 0x88cc4444, - 0x2e391717, 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, - 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, 0xc0a06060, - 0x19988181, 0x9ed14f4f, 0xa37fdcdc, 0x44662222, 0x547e2a2a, - 0x3bab9090, 0x0b838888, 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, - 0x283c1414, 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, - 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, 0x92db4949, - 0x0c0a0606, 0x486c2424, 0xb8e45c5c, 0x9f5dc2c2, 0xbd6ed3d3, - 0x43efacac, 0xc4a66262, 0x39a89191, 0x31a49595, 0xd337e4e4, - 0xf28b7979, 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, - 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, 0xd8b46c6c, - 0xacfa5656, 0xf307f4f4, 0xcf25eaea, 0xcaaf6565, 0xf48e7a7a, - 0x47e9aeae, 0x10180808, 0x6fd5baba, 0xf0887878, 0x4a6f2525, - 0x5c722e2e, 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, - 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, 0x96dd4b4b, - 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, 0xe0907070, 0x7c423e3e, - 0x71c4b5b5, 0xccaa6666, 0x90d84848, 0x06050303, 0xf701f6f6, - 0x1c120e0e, 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, - 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, 0xd938e1e1, - 0xeb13f8f8, 0x2bb39898, 0x22331111, 0xd2bb6969, 0xa970d9d9, - 0x07898e8e, 0x33a79494, 0x2db69b9b, 0x3c221e1e, 0x15928787, - 0xc920e9e9, 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, - 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, 0x65dabfbf, - 0xd731e6e6, 0x84c64242, 0xd0b86868, 0x82c34141, 0x29b09999, - 0x5a772d2d, 0x1e110f0f, 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, - 0x2c3a1616 - }; - - private static readonly uint[] Tinv0 = - { - 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, - 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, - 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, - 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, - 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, - 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, - 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, - 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, - 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, - 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, - 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, - 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, - 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, - 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, - 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, - 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, - 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, - 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, - 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, - 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, - 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, - 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, - 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4, - 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, - 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, - 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, - 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, - 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, - 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, - 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, - 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, - 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, - 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, - 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850, - 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, - 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, - 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, - 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, - 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, - 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, - 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, - 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, - 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, - 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, - 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, - 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, - 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, - 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, - 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, - 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, - 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, - 0x4257b8d0 - }; - - private static readonly uint[] Tinv1 = - { - 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, 0x6bab3bcb, - 0x459d1ff1, 0x58faacab, 0x03e34b93, 0xfa302055, 0x6d76adf6, - 0x76cc8891, 0x4c02f525, 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, - 0xa362b58f, 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1, - 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, 0x5f8f03e7, - 0x9c921595, 0x7a6dbfeb, 0x595295da, 0x83bed42d, 0x217458d3, - 0x69e04929, 0xc8c98e44, 0x89c2756a, 0x798ef478, 0x3e58996b, - 0x71b927dd, 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, - 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, 0x7764b1e0, - 0xae6bbb84, 0xa081fe1c, 0x2b08f994, 0x68487058, 0xfd458f19, - 0x6cde9487, 0xf87b52b7, 0xd373ab23, 0x024b72e2, 0x8f1fe357, - 0xab55662a, 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5, - 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, 0x1ccf8a2b, - 0xb479a792, 0xf207f3f0, 0xe2694ea1, 0xf4da65cd, 0xbe0506d5, - 0x6234d11f, 0xfea6c48a, 0x532e349d, 0x55f3a2a0, 0xe18a0532, - 0xebf6a475, 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, - 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, 0x8d5491b5, - 0x5dc47105, 0xd406046f, 0x155060ff, 0xfb981924, 0xe9bdd697, - 0x434089cc, 0x9ed96777, 0x42e8b0bd, 0x8b890788, 0x5b19e738, - 0xeec879db, 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, - 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, 0xff0efdfb, - 0x38850f56, 0xd5ae3d1e, 0x392d3627, 0xd90f0a64, 0xa65c6821, - 0x545b9bd1, 0x2e36243a, 0x670a0cb1, 0xe757930f, 0x96eeb4d2, - 0x919b1b9e, 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, - 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, 0x0d090e0b, - 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, 0x19f15785, 0x0775af4c, - 0xdd99eebb, 0x607fa3fd, 0x2601f79f, 0xf5725cbc, 0x3b6644c5, - 0x7efb5b34, 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, - 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, 0x244a857d, - 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, 0x2f9e1d4b, 0x30b2dcf3, - 0x52860dec, 0xe3c177d0, 0x16b32b6c, 0xb970a999, 0x489411fa, - 0x64e94722, 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, - 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, 0x81f5a6cf, - 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, 0x9d3a2ce4, 0x9278500d, - 0xcc5f6a9b, 0x467e5462, 0x138df6c2, 0xb8d890e8, 0xf7392e5e, - 0xafc382f5, 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, - 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, 0x7826cd09, - 0x18596ef4, 0xb79aec01, 0x9a4f83a8, 0x6e95e665, 0xe6ffaa7e, - 0xcfbc2108, 0xe815efe6, 0x9be7bad9, 0x366f4ace, 0x099fead4, - 0x7cb029d6, 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, - 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, 0x9804f14a, - 0xdaec41f7, 0x50cd7f0e, 0xf691172f, 0xd64d768d, 0xb0ef434d, - 0x4daacc54, 0x0496e4df, 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, - 0x5165467f, 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, - 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, 0x61d79a8c, - 0x0ca1377a, 0x14f8598e, 0x3c13eb89, 0x27a9ceee, 0xc961b735, - 0xe51ce1ed, 0xb1477a3c, 0xdfd29c59, 0x73f2553f, 0xce141879, - 0x37c773bf, 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, - 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, 0xc31d1672, - 0x25e2bc0c, 0x493c288b, 0x950dff41, 0x01a83971, 0xb30c08de, - 0xe4b4d89c, 0xc1566490, 0x84cb7b61, 0xb632d570, 0x5c6c4874, - 0x57b8d042 - }; - - private static readonly uint[] Tinv2 = - { - 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, 0xab3bcb6b, - 0x9d1ff145, 0xfaacab58, 0xe34b9303, 0x302055fa, 0x76adf66d, - 0xcc889176, 0x02f5254c, 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, - 0x62b58fa3, 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, - 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, 0x8f03e75f, - 0x9215959c, 0x6dbfeb7a, 0x5295da59, 0xbed42d83, 0x7458d321, - 0xe0492969, 0xc98e44c8, 0xc2756a89, 0x8ef47879, 0x58996b3e, - 0xb927dd71, 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, - 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, 0x64b1e077, - 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, 0x48705868, 0x458f19fd, - 0xde94876c, 0x7b52b7f8, 0x73ab23d3, 0x4b72e202, 0x1fe3578f, - 0x55662aab, 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, - 0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, 0xcf8a2b1c, - 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, 0xda65cdf4, 0x0506d5be, - 0x34d11f62, 0xa6c48afe, 0x2e349d53, 0xf3a2a055, 0x8a0532e1, - 0xf6a475eb, 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, - 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, 0x5491b58d, - 0xc471055d, 0x06046fd4, 0x5060ff15, 0x981924fb, 0xbdd697e9, - 0x4089cc43, 0xd967779e, 0xe8b0bd42, 0x8907888b, 0x19e7385b, - 0xc879dbee, 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, - 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, 0x0efdfbff, - 0x850f5638, 0xae3d1ed5, 0x2d362739, 0x0f0a64d9, 0x5c6821a6, - 0x5b9bd154, 0x36243a2e, 0x0a0cb167, 0x57930fe7, 0xeeb4d296, - 0x9b1b9e91, 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, - 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, 0x090e0b0d, - 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, 0xf1578519, 0x75af4c07, - 0x99eebbdd, 0x7fa3fd60, 0x01f79f26, 0x725cbcf5, 0x6644c53b, - 0xfb5b347e, 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, - 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, 0x4a857d24, - 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, 0x9e1d4b2f, 0xb2dcf330, - 0x860dec52, 0xc177d0e3, 0xb32b6c16, 0x70a999b9, 0x9411fa48, - 0xe9472264, 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, - 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, 0xf5a6cf81, - 0x7aa528de, 0xb7da268e, 0xad3fa4bf, 0x3a2ce49d, 0x78500d92, - 0x5f6a9bcc, 0x7e546246, 0x8df6c213, 0xd890e8b8, 0x392e5ef7, - 0xc382f5af, 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, - 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, 0x26cd0978, - 0x596ef418, 0x9aec01b7, 0x4f83a89a, 0x95e6656e, 0xffaa7ee6, - 0xbc2108cf, 0x15efe6e8, 0xe7bad99b, 0x6f4ace36, 0x9fead409, - 0xb029d67c, 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, - 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, 0x04f14a98, - 0xec41f7da, 0xcd7f0e50, 0x91172ff6, 0x4d768dd6, 0xef434db0, - 0xaacc544d, 0x96e4df04, 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, - 0x65467f51, 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, - 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, 0xd79a8c61, - 0xa1377a0c, 0xf8598e14, 0x13eb893c, 0xa9ceee27, 0x61b735c9, - 0x1ce1ede5, 0x477a3cb1, 0xd29c59df, 0xf2553f73, 0x141879ce, - 0xc773bf37, 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, - 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, 0x1d1672c3, - 0xe2bc0c25, 0x3c288b49, 0x0dff4195, 0xa8397101, 0x0c08deb3, - 0xb4d89ce4, 0x566490c1, 0xcb7b6184, 0x32d570b6, 0x6c48745c, - 0xb8d04257 - }; - - private static readonly uint[] Tinv3 = - { - 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, 0x3bcb6bab, - 0x1ff1459d, 0xacab58fa, 0x4b9303e3, 0x2055fa30, 0xadf66d76, - 0x889176cc, 0xf5254c02, 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, - 0xb58fa362, 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, - 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, 0x03e75f8f, - 0x15959c92, 0xbfeb7a6d, 0x95da5952, 0xd42d83be, 0x58d32174, - 0x492969e0, 0x8e44c8c9, 0x756a89c2, 0xf478798e, 0x996b3e58, - 0x27dd71b9, 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, - 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, 0xb1e07764, - 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, 0x70586848, 0x8f19fd45, - 0x94876cde, 0x52b7f87b, 0xab23d373, 0x72e2024b, 0xe3578f1f, - 0x662aab55, 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, - 0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, 0x8a2b1ccf, - 0xa792b479, 0xf3f0f207, 0x4ea1e269, 0x65cdf4da, 0x06d5be05, - 0xd11f6234, 0xc48afea6, 0x349d532e, 0xa2a055f3, 0x0532e18a, - 0xa475ebf6, 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, - 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, 0x91b58d54, - 0x71055dc4, 0x046fd406, 0x60ff1550, 0x1924fb98, 0xd697e9bd, - 0x89cc4340, 0x67779ed9, 0xb0bd42e8, 0x07888b89, 0xe7385b19, - 0x79dbeec8, 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, - 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, 0xfdfbff0e, - 0x0f563885, 0x3d1ed5ae, 0x3627392d, 0x0a64d90f, 0x6821a65c, - 0x9bd1545b, 0x243a2e36, 0x0cb1670a, 0x930fe757, 0xb4d296ee, - 0x1b9e919b, 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, - 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, 0x0e0b0d09, - 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, 0x578519f1, 0xaf4c0775, - 0xeebbdd99, 0xa3fd607f, 0xf79f2601, 0x5cbcf572, 0x44c53b66, - 0x5b347efb, 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, - 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, 0x857d244a, - 0xd2f83dbb, 0xae1132f9, 0xc76da129, 0x1d4b2f9e, 0xdcf330b2, - 0x0dec5286, 0x77d0e3c1, 0x2b6c16b3, 0xa999b970, 0x11fa4894, - 0x472264e9, 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, - 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, 0xa6cf81f5, - 0xa528de7a, 0xda268eb7, 0x3fa4bfad, 0x2ce49d3a, 0x500d9278, - 0x6a9bcc5f, 0x5462467e, 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, - 0x82f5afc3, 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, - 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, 0xcd097826, - 0x6ef41859, 0xec01b79a, 0x83a89a4f, 0xe6656e95, 0xaa7ee6ff, - 0x2108cfbc, 0xefe6e815, 0xbad99be7, 0x4ace366f, 0xead4099f, - 0x29d67cb0, 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, - 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, 0xf14a9804, - 0x41f7daec, 0x7f0e50cd, 0x172ff691, 0x768dd64d, 0x434db0ef, - 0xcc544daa, 0xe4df0496, 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, - 0x467f5165, 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, - 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, 0x9a8c61d7, - 0x377a0ca1, 0x598e14f8, 0xeb893c13, 0xceee27a9, 0xb735c961, - 0xe1ede51c, 0x7a3cb147, 0x9c59dfd2, 0x553f73f2, 0x1879ce14, - 0x73bf37c7, 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, - 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, 0x1672c31d, - 0xbc0c25e2, 0x288b493c, 0xff41950d, 0x397101a8, 0x08deb30c, - 0xd89ce4b4, 0x6490c156, 0x7b6184cb, 0xd570b632, 0x48745c6c, - 0xd04257b8 - }; - - #endregion + private readonly Aes _aes; + private ICryptoTransform _encryptor; + private ICryptoTransform _decryptor; /// /// Initializes a new instance of the class. @@ -566,12 +23,13 @@ public sealed class AesCipher : BlockCipher public AesCipher(byte[] key, CipherMode mode, CipherPadding padding) : base(key, 16, mode, padding) { - var keySize = key.Length * 8; - - if (keySize is not (256 or 192 or 128)) - { - throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "KeySize '{0}' is not valid for this algorithm.", keySize)); - } + var aes = Aes.Create(); + aes.Key = key; +#pragma warning disable CA5358 // Do not use unsafe cipher modes; this is the basis for other modes. + aes.Mode = System.Security.Cryptography.CipherMode.ECB; +#pragma warning restore CA5358 // Do not use unsafe cipher modes + aes.Padding = PaddingMode.None; + _aes = aes; } /// @@ -589,35 +47,9 @@ public AesCipher(byte[] key, CipherMode mode, CipherPadding padding) /// or is too short. public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - if (inputBuffer is null) - { - throw new ArgumentNullException(nameof(inputBuffer)); - } - - if (outputBuffer is null) - { - throw new ArgumentNullException(nameof(outputBuffer)); - } - - if ((inputOffset + (32 / 2)) > inputBuffer.Length) - { - throw new ArgumentException("input buffer too short"); - } - - if ((outputOffset + (32 / 2)) > outputBuffer.Length) - { - throw new ArgumentException("output buffer too short"); - } - - _encryptionKey ??= GenerateWorkingKey(isEncryption: true, Key); - - UnPackBlock(inputBuffer, inputOffset); + _encryptor ??= _aes.CreateEncryptor(); - EncryptBlock(_encryptionKey); - - PackBlock(outputBuffer, outputOffset); - - return BlockSize; + return _encryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); } /// @@ -635,215 +67,29 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC /// or is too short. public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - if (inputBuffer is null) - { - throw new ArgumentNullException(nameof(inputBuffer)); - } - - if (outputBuffer is null) - { - throw new ArgumentNullException(nameof(outputBuffer)); - } - - if ((inputOffset + (32 / 2)) > inputBuffer.Length) - { - throw new ArgumentException("input buffer too short"); - } - - if ((outputOffset + (32 / 2)) > outputBuffer.Length) - { - throw new ArgumentException("output buffer too short"); - } + _decryptor ??= _aes.CreateDecryptor(); - _decryptionKey ??= GenerateWorkingKey(isEncryption: false, Key); - - UnPackBlock(inputBuffer, inputOffset); - - DecryptBlock(_decryptionKey); - - PackBlock(outputBuffer, outputOffset); - - return BlockSize; + return _decryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); } - private uint[] GenerateWorkingKey(bool isEncryption, byte[] key) + private void Dispose(bool disposing) { - var KC = key.Length / 4; // key length in words - - if (((KC != 4) && (KC != 6) && (KC != 8)) || ((KC * 4) != key.Length)) - { - throw new ArgumentException("Key length not 128/192/256 bits."); - } - - _rounds = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes - var W = new uint[(_rounds + 1) * 4]; // 4 words in a block - - /* - * Copy the key into the round key array. - */ - - var t = 0; - - for (var i = 0; i < key.Length; t++) - { - W[((t >> 2) * 4) + (t & 3)] = Pack.LittleEndianToUInt32(key, i); - i += 4; - } - - /* - * Calculate new values while not enough round key material is calculated. - */ - - var k = (_rounds + 1) << 2; - for (var i = KC; i < k; i++) + if (disposing) { - var temp = W[(((i - 1) >> 2) * 4) + ((i - 1) & 3)]; - if ((i % KC) == 0) - { - temp = SubWord(Shift(temp, 8)) ^ Rcon[(i / KC) - 1]; - } - else if ((KC > 6) && ((i % KC) == 4)) - { - temp = SubWord(temp); - } - - W[((i >> 2) * 4) + (i & 3)] = W[(((i - KC) >> 2) * 4) + ((i - KC) & 3)] ^ temp; - } + _encryptor?.Dispose(); + _encryptor = null; - if (!isEncryption) - { - for (var j = 1; j < _rounds; j++) - { - for (var i = 0; i < 4; i++) - { - W[(j * 4) + i] = InvMcol(W[(j * 4) + i]); - } - } + _decryptor?.Dispose(); + _decryptor = null; } - - return W; - } - - private static uint Shift(uint r, int shift) - { - return (r >> shift) | (r << (32 - shift)); - } - - private static uint FFmulX(uint x) - { - return ((x & M2) << 1) ^ (((x & M1) >> 7) * M3); } - private static uint InvMcol(uint x) + /// + public void Dispose() { - var f2 = FFmulX(x); - var f4 = FFmulX(f2); - var f8 = FFmulX(f4); - var f9 = x ^ f8; - - return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24); - } - - private static uint SubWord(uint x) - { - return (uint)S[x & 255] - | (((uint)S[(x >> 8) & 255]) << 8) - | (((uint)S[(x >> 16) & 255]) << 16) - | (((uint)S[(x >> 24) & 255]) << 24); - } - - private void UnPackBlock(byte[] bytes, int off) - { - _c0 = Pack.LittleEndianToUInt32(bytes, off); - _c1 = Pack.LittleEndianToUInt32(bytes, off + 4); - _c2 = Pack.LittleEndianToUInt32(bytes, off + 8); - _c3 = Pack.LittleEndianToUInt32(bytes, off + 12); - } - - private void PackBlock(byte[] bytes, int off) - { - Pack.UInt32ToLittleEndian(_c0, bytes, off); - Pack.UInt32ToLittleEndian(_c1, bytes, off + 4); - Pack.UInt32ToLittleEndian(_c2, bytes, off + 8); - Pack.UInt32ToLittleEndian(_c3, bytes, off + 12); - } - -#pragma warning disable SA1313 // Parameter names should begin with lower-case letter - private void EncryptBlock(uint[] KW) -#pragma warning restore SA1313 // Parameter names should begin with lower-case letter - { - int r; - uint r0, r1, r2, r3; - - _c0 ^= KW[(0 * 4) + 0]; - _c1 ^= KW[(0 * 4) + 1]; - _c2 ^= KW[(0 * 4) + 2]; - _c3 ^= KW[(0 * 4) + 3]; - - for (r = 1; r < _rounds - 1;) - { - r0 = T0[_c0 & 255] ^ T1[(_c1 >> 8) & 255] ^ T2[(_c2 >> 16) & 255] ^ T3[_c3 >> 24] ^ KW[(r * 4) + 0]; - r1 = T0[_c1 & 255] ^ T1[(_c2 >> 8) & 255] ^ T2[(_c3 >> 16) & 255] ^ T3[_c0 >> 24] ^ KW[(r * 4) + 1]; - r2 = T0[_c2 & 255] ^ T1[(_c3 >> 8) & 255] ^ T2[(_c0 >> 16) & 255] ^ T3[_c1 >> 24] ^ KW[(r * 4) + 2]; - r3 = T0[_c3 & 255] ^ T1[(_c0 >> 8) & 255] ^ T2[(_c1 >> 16) & 255] ^ T3[_c2 >> 24] ^ KW[(r++ * 4) + 3]; - _c0 = T0[r0 & 255] ^ T1[(r1 >> 8) & 255] ^ T2[(r2 >> 16) & 255] ^ T3[r3 >> 24] ^ KW[(r * 4) + 0]; - _c1 = T0[r1 & 255] ^ T1[(r2 >> 8) & 255] ^ T2[(r3 >> 16) & 255] ^ T3[r0 >> 24] ^ KW[(r * 4) + 1]; - _c2 = T0[r2 & 255] ^ T1[(r3 >> 8) & 255] ^ T2[(r0 >> 16) & 255] ^ T3[r1 >> 24] ^ KW[(r * 4) + 2]; - _c3 = T0[r3 & 255] ^ T1[(r0 >> 8) & 255] ^ T2[(r1 >> 16) & 255] ^ T3[r2 >> 24] ^ KW[(r++ * 4) + 3]; - } - - r0 = T0[_c0 & 255] ^ T1[(_c1 >> 8) & 255] ^ T2[(_c2 >> 16) & 255] ^ T3[_c3 >> 24] ^ KW[(r * 4) + 0]; - r1 = T0[_c1 & 255] ^ T1[(_c2 >> 8) & 255] ^ T2[(_c3 >> 16) & 255] ^ T3[_c0 >> 24] ^ KW[(r * 4) + 1]; - r2 = T0[_c2 & 255] ^ T1[(_c3 >> 8) & 255] ^ T2[(_c0 >> 16) & 255] ^ T3[_c1 >> 24] ^ KW[(r * 4) + 2]; - r3 = T0[_c3 & 255] ^ T1[(_c0 >> 8) & 255] ^ T2[(_c1 >> 16) & 255] ^ T3[_c2 >> 24] ^ KW[(r++ * 4) + 3]; - - /* - * The final round's table is a simple function of S so we don't use a whole other four tables for it. - */ - - _c0 = (uint)S[r0 & 255] ^ (((uint)S[(r1 >> 8) & 255]) << 8) ^ (((uint)S[(r2 >> 16) & 255]) << 16) ^ (((uint)S[r3 >> 24]) << 24) ^ KW[(r * 4) + 0]; - _c1 = (uint)S[r1 & 255] ^ (((uint)S[(r2 >> 8) & 255]) << 8) ^ (((uint)S[(r3 >> 16) & 255]) << 16) ^ (((uint)S[r0 >> 24]) << 24) ^ KW[(r * 4) + 1]; - _c2 = (uint)S[r2 & 255] ^ (((uint)S[(r3 >> 8) & 255]) << 8) ^ (((uint)S[(r0 >> 16) & 255]) << 16) ^ (((uint)S[r1 >> 24]) << 24) ^ KW[(r * 4) + 2]; - _c3 = (uint)S[r3 & 255] ^ (((uint)S[(r0 >> 8) & 255]) << 8) ^ (((uint)S[(r1 >> 16) & 255]) << 16) ^ (((uint)S[r2 >> 24]) << 24) ^ KW[(r * 4) + 3]; - } - -#pragma warning disable SA1313 // Parameter names should begin with lower-case letter - private void DecryptBlock(uint[] KW) -#pragma warning restore SA1313 // Parameter names should begin with lower-case letter - { - int r; - uint r0, r1, r2, r3; - - _c0 ^= KW[(_rounds * 4) + 0]; - _c1 ^= KW[(_rounds * 4) + 1]; - _c2 ^= KW[(_rounds * 4) + 2]; - _c3 ^= KW[(_rounds * 4) + 3]; - - for (r = _rounds - 1; r > 1;) - { - r0 = Tinv0[_c0 & 255] ^ Tinv1[(_c3 >> 8) & 255] ^ Tinv2[(_c2 >> 16) & 255] ^ Tinv3[_c1 >> 24] ^ KW[(r * 4) + 0]; - r1 = Tinv0[_c1 & 255] ^ Tinv1[(_c0 >> 8) & 255] ^ Tinv2[(_c3 >> 16) & 255] ^ Tinv3[_c2 >> 24] ^ KW[(r * 4) + 1]; - r2 = Tinv0[_c2 & 255] ^ Tinv1[(_c1 >> 8) & 255] ^ Tinv2[(_c0 >> 16) & 255] ^ Tinv3[_c3 >> 24] ^ KW[(r * 4) + 2]; - r3 = Tinv0[_c3 & 255] ^ Tinv1[(_c2 >> 8) & 255] ^ Tinv2[(_c1 >> 16) & 255] ^ Tinv3[_c0 >> 24] ^ KW[(r-- * 4) + 3]; - _c0 = Tinv0[r0 & 255] ^ Tinv1[(r3 >> 8) & 255] ^ Tinv2[(r2 >> 16) & 255] ^ Tinv3[r1 >> 24] ^ KW[(r * 4) + 0]; - _c1 = Tinv0[r1 & 255] ^ Tinv1[(r0 >> 8) & 255] ^ Tinv2[(r3 >> 16) & 255] ^ Tinv3[r2 >> 24] ^ KW[(r * 4) + 1]; - _c2 = Tinv0[r2 & 255] ^ Tinv1[(r1 >> 8) & 255] ^ Tinv2[(r0 >> 16) & 255] ^ Tinv3[r3 >> 24] ^ KW[(r * 4) + 2]; - _c3 = Tinv0[r3 & 255] ^ Tinv1[(r2 >> 8) & 255] ^ Tinv2[(r1 >> 16) & 255] ^ Tinv3[r0 >> 24] ^ KW[(r-- * 4) + 3]; - } - - r0 = Tinv0[_c0 & 255] ^ Tinv1[(_c3 >> 8) & 255] ^ Tinv2[(_c2 >> 16) & 255] ^ Tinv3[_c1 >> 24] ^ KW[(r * 4) + 0]; - r1 = Tinv0[_c1 & 255] ^ Tinv1[(_c0 >> 8) & 255] ^ Tinv2[(_c3 >> 16) & 255] ^ Tinv3[_c2 >> 24] ^ KW[(r * 4) + 1]; - r2 = Tinv0[_c2 & 255] ^ Tinv1[(_c1 >> 8) & 255] ^ Tinv2[(_c0 >> 16) & 255] ^ Tinv3[_c3 >> 24] ^ KW[(r * 4) + 2]; - r3 = Tinv0[_c3 & 255] ^ Tinv1[(_c2 >> 8) & 255] ^ Tinv2[(_c1 >> 16) & 255] ^ Tinv3[_c0 >> 24] ^ KW[(r * 4) + 3]; - - /* - * The final round's table is a simple function of Si so we don't use a whole other four tables for it. - */ - - _c0 = (uint)Si[r0 & 255] ^ (((uint)Si[(r3 >> 8) & 255]) << 8) ^ (((uint)Si[(r2 >> 16) & 255]) << 16) ^ (((uint)Si[r1 >> 24]) << 24) ^ KW[(0 * 4) + 0]; - _c1 = (uint)Si[r1 & 255] ^ (((uint)Si[(r0 >> 8) & 255]) << 8) ^ (((uint)Si[(r3 >> 16) & 255]) << 16) ^ (((uint)Si[r2 >> 24]) << 24) ^ KW[(0 * 4) + 1]; - _c2 = (uint)Si[r2 & 255] ^ (((uint)Si[(r1 >> 8) & 255]) << 8) ^ (((uint)Si[(r0 >> 16) & 255]) << 16) ^ (((uint)Si[r3 >> 24]) << 24) ^ KW[(0 * 4) + 2]; - _c3 = (uint)Si[r3 & 255] ^ (((uint)Si[(r2 >> 8) & 255]) << 8) ^ (((uint)Si[(r1 >> 16) & 255]) << 16) ^ (((uint)Si[r0 >> 24]) << 24) ^ KW[(0 * 4) + 3]; + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); } } } diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index f05c0e0a0..326e9b139 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -1427,6 +1427,16 @@ internal void OnNewKeysReceived(NewKeysMessage message) SessionId ??= _keyExchange.ExchangeHash; // Dispose of old ciphers and hash algorithms + if (_serverCipher is IDisposable disposableServerCipher) + { + disposableServerCipher.Dispose(); + } + + if (_clientCipher is IDisposable disposableClientCipher) + { + disposableClientCipher.Dispose(); + } + if (_serverMac != null) { _serverMac.Dispose(); @@ -2014,6 +2024,16 @@ protected virtual void Dispose(bool disposing) _keyExchangeCompletedWaitHandle = null; } + if (_serverCipher is IDisposable disposableServerCipher) + { + disposableServerCipher.Dispose(); + } + + if (_clientCipher is IDisposable disposableClientCipher) + { + disposableClientCipher.Dispose(); + } + var serverMac = _serverMac; if (serverMac != null) { diff --git a/test/Renci.SshNet.IntegrationTests/SshTests.cs b/test/Renci.SshNet.IntegrationTests/SshTests.cs index 5f3e58984..3bc09f4f2 100644 --- a/test/Renci.SshNet.IntegrationTests/SshTests.cs +++ b/test/Renci.SshNet.IntegrationTests/SshTests.cs @@ -63,7 +63,7 @@ public void Ssh_ShellStream_Exit() catch (ObjectDisposedException ex) { Assert.IsNull(ex.InnerException); - Assert.AreEqual("ShellStream", ex.ObjectName); + Assert.AreEqual("Renci.SshNet.ShellStream", ex.ObjectName); Assert.AreEqual($"Cannot access a disposed object.{Environment.NewLine}Object name: '{ex.ObjectName}'.", ex.Message); } From 54d01621aa54ce16a1523172b12be3bc9add898a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Thu, 16 Nov 2023 08:58:22 +0100 Subject: [PATCH 71/96] Enable trace logging for Integration tests (#1242) --- .../TestsFixtures/InfrastructureFixture.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/test/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs b/test/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs index 97e8c3776..f01df813d 100644 --- a/test/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs +++ b/test/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs @@ -1,7 +1,11 @@ -锘縰sing DotNet.Testcontainers.Builders; +锘縰sing System.Diagnostics; + +using DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Containers; using DotNet.Testcontainers.Images; +using Renci.SshNet.Abstractions; + namespace Renci.SshNet.IntegrationTests.TestsFixtures { public sealed class InfrastructureFixture : IDisposable @@ -34,6 +38,10 @@ public static InfrastructureFixture Instance public async Task InitializeAsync() { + DiagnosticAbstraction.Source.Switch = new SourceSwitch("sourceSwitch", "Verbose"); + DiagnosticAbstraction.Source.Listeners.Remove("Default"); + DiagnosticAbstraction.Source.Listeners.Add(new ConsoleTraceListener()); + _sshServerImage = new ImageFromDockerfileBuilder() .WithName("renci-ssh-tests-server-image") .WithDockerfileDirectory(CommonDirectoryPath.GetSolutionDirectory(), Path.Combine("test", "Renci.SshNet.IntegrationTests")) From f9f2b0e5f40eb6982ba98b696e1850eb81fe06a3 Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Thu, 16 Nov 2023 21:35:59 +0800 Subject: [PATCH 72/96] Expose SshIdentificationReceived event (#1195) * Fix https://github.com/sshnet/SSH.NET/issues/1191 * Expose `SshIdentificationReceived` event so that lib consumer can adjust based on server identification * revert unrelated code style change * revert OpenSSH 6.6 related tests * revert ConnectionBase * Add unit tests * Rename to `ServerIdentificationReceived` * rename --- src/Renci.SshNet/BaseClient.cs | 13 ++++ .../Common/SshIdentificationEventArgs.cs | 26 ++++++++ .../Connection/SshIdentification.cs | 2 +- src/Renci.SshNet/ISession.cs | 5 ++ src/Renci.SshNet/Session.cs | 9 +++ .../Classes/SessionTest_ConnectedBase.cs | 12 +++- ..._Connected_ServerIdentificationReceived.cs | 65 +++++++++++++++++++ 7 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 src/Renci.SshNet/Common/SshIdentificationEventArgs.cs create mode 100644 test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerIdentificationReceived.cs diff --git a/src/Renci.SshNet/BaseClient.cs b/src/Renci.SshNet/BaseClient.cs index ddd434c2e..bdfd5cb5f 100644 --- a/src/Renci.SshNet/BaseClient.cs +++ b/src/Renci.SshNet/BaseClient.cs @@ -153,6 +153,11 @@ public TimeSpan KeepAliveInterval /// public event EventHandler HostKeyReceived; + /// + /// Occurs when server identification received. + /// + public event EventHandler ServerIdentificationReceived; + /// /// Initializes a new instance of the class. /// @@ -390,6 +395,11 @@ private void Session_HostKeyReceived(object sender, HostKeyEventArgs e) HostKeyReceived?.Invoke(this, e); } + private void Session_ServerIdentificationReceived(object sender, SshIdentificationEventArgs e) + { + ServerIdentificationReceived?.Invoke(this, e); + } + /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// @@ -532,6 +542,7 @@ private Timer CreateKeepAliveTimer(TimeSpan dueTime, TimeSpan period) private ISession CreateAndConnectSession() { var session = _serviceFactory.CreateSession(ConnectionInfo, _serviceFactory.CreateSocketFactory()); + session.ServerIdentificationReceived += Session_ServerIdentificationReceived; session.HostKeyReceived += Session_HostKeyReceived; session.ErrorOccured += Session_ErrorOccured; @@ -550,6 +561,7 @@ private ISession CreateAndConnectSession() private async Task CreateAndConnectSessionAsync(CancellationToken cancellationToken) { var session = _serviceFactory.CreateSession(ConnectionInfo, _serviceFactory.CreateSocketFactory()); + session.ServerIdentificationReceived += Session_ServerIdentificationReceived; session.HostKeyReceived += Session_HostKeyReceived; session.ErrorOccured += Session_ErrorOccured; @@ -569,6 +581,7 @@ private void DisposeSession(ISession session) { session.ErrorOccured -= Session_ErrorOccured; session.HostKeyReceived -= Session_HostKeyReceived; + session.ServerIdentificationReceived -= Session_ServerIdentificationReceived; session.Dispose(); } diff --git a/src/Renci.SshNet/Common/SshIdentificationEventArgs.cs b/src/Renci.SshNet/Common/SshIdentificationEventArgs.cs new file mode 100644 index 000000000..f618112bd --- /dev/null +++ b/src/Renci.SshNet/Common/SshIdentificationEventArgs.cs @@ -0,0 +1,26 @@ +锘縰sing System; + +using Renci.SshNet.Connection; + +namespace Renci.SshNet.Common +{ + /// + /// Provides data for the ServerIdentificationReceived events. + /// + public class SshIdentificationEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The SSH identification. + public SshIdentificationEventArgs(SshIdentification sshIdentification) + { + SshIdentification = sshIdentification; + } + + /// + /// Gets the SSH identification. + /// + public SshIdentification SshIdentification { get; private set; } + } +} diff --git a/src/Renci.SshNet/Connection/SshIdentification.cs b/src/Renci.SshNet/Connection/SshIdentification.cs index 931656296..727cc4d94 100644 --- a/src/Renci.SshNet/Connection/SshIdentification.cs +++ b/src/Renci.SshNet/Connection/SshIdentification.cs @@ -5,7 +5,7 @@ namespace Renci.SshNet.Connection /// /// Represents an SSH identification. /// - internal sealed class SshIdentification + public sealed class SshIdentification { /// /// Initializes a new instance of the class with the specified protocol version diff --git a/src/Renci.SshNet/ISession.cs b/src/Renci.SshNet/ISession.cs index 5a035b104..e78ff75f8 100644 --- a/src/Renci.SshNet/ISession.cs +++ b/src/Renci.SshNet/ISession.cs @@ -260,6 +260,11 @@ internal interface ISession : IDisposable /// event EventHandler ErrorOccured; + /// + /// Occurs when server identification received. + /// + event EventHandler ServerIdentificationReceived; + /// /// Occurs when host key received. /// diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index 326e9b139..c984d3109 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -366,6 +366,11 @@ public Message ClientInitMessage /// public event EventHandler Disconnected; + /// + /// Occurs when server identification received. + /// + public event EventHandler ServerIdentificationReceived; + /// /// Occurs when host key received. /// @@ -624,6 +629,8 @@ public void Connect() DisconnectReason.ProtocolVersionNotSupported); } + ServerIdentificationReceived?.Invoke(this, new SshIdentificationEventArgs(serverIdentification)); + // Register Transport response messages RegisterMessage("SSH_MSG_DISCONNECT"); RegisterMessage("SSH_MSG_IGNORE"); @@ -736,6 +743,8 @@ public async Task ConnectAsync(CancellationToken cancellationToken) DisconnectReason.ProtocolVersionNotSupported); } + ServerIdentificationReceived?.Invoke(this, new SshIdentificationEventArgs(serverIdentification)); + // Register Transport response messages RegisterMessage("SSH_MSG_DISCONNECT"); RegisterMessage("SSH_MSG_IGNORE"); diff --git a/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs index 8f4bed7c0..3c1c2fdcf 100644 --- a/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs +++ b/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs @@ -46,7 +46,8 @@ public abstract class SessionTest_ConnectedBase protected Session Session { get; private set; } protected Socket ClientSocket { get; private set; } protected Socket ServerSocket { get; private set; } - internal SshIdentification ServerIdentification { get; private set; } + internal SshIdentification ServerIdentification { get; set; } + protected bool CallSessionConnectWhenArrange { get; set; } [TestInitialize] public void Setup() @@ -159,6 +160,8 @@ protected virtual void SetupData() ServerListener.Start(); ClientSocket = new DirectConnector(_socketFactory).Connect(ConnectionInfo); + + CallSessionConnectWhenArrange = true; } private void CreateMocks() @@ -180,7 +183,7 @@ private void SetupMocks() _ = ServiceFactoryMock.Setup(p => p.CreateProtocolVersionExchange()) .Returns(_protocolVersionExchangeMock.Object); _ = _protocolVersionExchangeMock.Setup(p => p.Start(Session.ClientVersion, ClientSocket, ConnectionInfo.Timeout)) - .Returns(ServerIdentification); + .Returns(() => ServerIdentification); _ = ServiceFactoryMock.Setup(p => p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, new[] { _keyExchangeAlgorithm })).Returns(_keyExchangeMock.Object); _ = _keyExchangeMock.Setup(p => p.Name) .Returns(_keyExchangeAlgorithm); @@ -212,7 +215,10 @@ protected void Arrange() SetupData(); SetupMocks(); - Session.Connect(); + if (CallSessionConnectWhenArrange) + { + Session.Connect(); + } } protected virtual void ClientAuthentication_Callback() diff --git a/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerIdentificationReceived.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerIdentificationReceived.cs new file mode 100644 index 000000000..7b5ff1d86 --- /dev/null +++ b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerIdentificationReceived.cs @@ -0,0 +1,65 @@ +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +using Renci.SshNet.Connection; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class SessionTest_Connected_ServerIdentificationReceived : SessionTest_ConnectedBase + { + protected override void SetupData() + { + base.SetupData(); + + CallSessionConnectWhenArrange = false; + + Session.ServerIdentificationReceived += (s, e) => + { + if ((e.SshIdentification.SoftwareVersion.StartsWith("OpenSSH_6.5", System.StringComparison.Ordinal) || e.SshIdentification.SoftwareVersion.StartsWith("OpenSSH_6.6", System.StringComparison.Ordinal)) + && !e.SshIdentification.SoftwareVersion.StartsWith("OpenSSH_6.6.1", System.StringComparison.Ordinal)) + { + _ = ConnectionInfo.KeyExchangeAlgorithms.Remove("curve25519-sha256"); + _ = ConnectionInfo.KeyExchangeAlgorithms.Remove("curve25519-sha256@libssh.org"); + } + }; + } + + protected override void Act() + { + } + + [TestMethod] + [DataRow("OpenSSH_6.5")] + [DataRow("OpenSSH_6.5p1")] + [DataRow("OpenSSH_6.5 PKIX")] + [DataRow("OpenSSH_6.6")] + [DataRow("OpenSSH_6.6p1")] + [DataRow("OpenSSH_6.6 PKIX")] + public void ShouldExcludeCurve25519KexWhenServerIs(string softwareVersion) + { + ServerIdentification = new SshIdentification("2.0", softwareVersion); + + Session.Connect(); + + Assert.IsFalse(ConnectionInfo.KeyExchangeAlgorithms.ContainsKey("curve25519-sha256")); + Assert.IsFalse(ConnectionInfo.KeyExchangeAlgorithms.ContainsKey("curve25519-sha256@libssh.org")); + } + + [TestMethod] + [DataRow("OpenSSH_6.6.1")] + [DataRow("OpenSSH_6.6.1p1")] + [DataRow("OpenSSH_6.6.1 PKIX")] + [DataRow("OpenSSH_6.7")] + [DataRow("OpenSSH_6.7p1")] + [DataRow("OpenSSH_6.7 PKIX")] + public void ShouldIncludeCurve25519KexWhenServerIs(string softwareVersion) + { + ServerIdentification = new SshIdentification("2.0", softwareVersion); + + Session.Connect(); + + Assert.IsTrue(ConnectionInfo.KeyExchangeAlgorithms.ContainsKey("curve25519-sha256")); + Assert.IsTrue(ConnectionInfo.KeyExchangeAlgorithms.ContainsKey("curve25519-sha256@libssh.org")); + } + } +} From daa1accaf677a6382973cb7ac891f31ed7808af6 Mon Sep 17 00:00:00 2001 From: se006 <84139931+se006@users.noreply.github.com> Date: Sun, 19 Nov 2023 01:32:08 -0500 Subject: [PATCH 73/96] Fix avoidable exception when data length is too long (#823) * Data lengths longer than stream position when data lengths are greater than int.maxvalue are ignored and do not throw an exception * Removed unreachable test * Do not try to load the data (just ignore it) --------- Co-authored-by: Steve Evans Co-authored-by: Rob Hague --- .../Messages/Transport/IgnoreMessage.cs | 21 ++------- .../Messages/Transport/IgnoreMessageTest.cs | 45 +------------------ 2 files changed, 5 insertions(+), 61 deletions(-) diff --git a/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs b/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs index 5d07f1d00..d657d2d46 100644 --- a/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs @@ -1,6 +1,4 @@ 锘縰sing System; -using System.Globalization; -using Renci.SshNet.Abstractions; namespace Renci.SshNet.Messages.Transport { @@ -13,7 +11,8 @@ public class IgnoreMessage : Message internal const byte MessageNumber = 2; /// - /// Gets ignore message data if any. + /// Gets ignore message data if this message has been initialised + /// with data to be sent. Otherwise, returns an empty array. /// public byte[] Data { get; private set; } @@ -61,21 +60,7 @@ protected override int BufferCapacity /// protected override void LoadData() { - var dataLength = ReadUInt32(); - if (dataLength > int.MaxValue) - { - throw new NotSupportedException(string.Format(CultureInfo.CurrentCulture, "Data longer than {0} is not supported.", int.MaxValue)); - } - - if (dataLength > (DataStream.Length - DataStream.Position)) - { - DiagnosticAbstraction.Log("SSH_MSG_IGNORE: Length exceeds data bytes, data ignored."); - Data = Array.Empty(); - } - else - { - Data = ReadBytes((int) dataLength); - } + // Do nothing - this data is supposed to be ignored. } /// diff --git a/test/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs index 1c82d3a6d..ecdbf3310 100644 --- a/test/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs @@ -1,5 +1,4 @@ 锘縰sing System; -using System.Globalization; using System.Linq; using Renci.SshNet.Common; using Renci.SshNet.Messages.Transport; @@ -80,7 +79,7 @@ public void GetBytes() } [TestMethod] - public void Load() + public void Load_IgnoresData() { var ignoreMessage = new IgnoreMessage(_data); var bytes = ignoreMessage.GetBytes(); @@ -89,47 +88,7 @@ public void Load() target.Load(bytes, 1, bytes.Length - 1); Assert.IsNotNull(target.Data); - Assert.AreEqual(_data.Length, target.Data.Length); - Assert.IsTrue(target.Data.SequenceEqual(_data)); - } - - [TestMethod] - public void Load_ShouldIgnoreDataWhenItsLengthIsGreatherThanItsActualBytes() - { - var ssh = new SshDataStream(1); - ssh.WriteByte(2); // Type - ssh.Write(5u); // Data length - ssh.Write(new byte[3]); // Data - - var ignoreMessageBytes = ssh.ToArray(); - - var ignoreMessage = new IgnoreMessage(); - ignoreMessage.Load(ignoreMessageBytes, 1, ignoreMessageBytes.Length - 1); - Assert.IsNotNull(ignoreMessage.Data); - Assert.AreEqual(0, ignoreMessage.Data.Length); - } - - [TestMethod] - public void Load_ShouldThrowNotSupportedExceptionWhenDataLengthIsGreaterThanInt32MaxValue() - { - var ssh = new SshDataStream(1); - ssh.WriteByte(2); // Type - ssh.Write(uint.MaxValue); // Data length - ssh.Write(new byte[3]); - - var ignoreMessageBytes = ssh.ToArray(); - var ignoreMessage = new IgnoreMessage(); - - try - { - ignoreMessage.Load(ignoreMessageBytes, 1, ignoreMessageBytes.Length - 1); - Assert.Fail(); - } - catch (NotSupportedException ex) - { - Assert.IsNull(ex.InnerException); - Assert.AreEqual(string.Format(CultureInfo.CurrentCulture, "Data longer than {0} is not supported.", int.MaxValue), ex.Message); - } + Assert.AreEqual(0, target.Data.Length); } } } From 18cf71bc07dbfd25aa55e0d60424cf691fa3f857 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Mon, 20 Nov 2023 19:20:20 +0000 Subject: [PATCH 74/96] Fix build break in Release (#1248) --- src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs index 9de9bbea4..3d69bb4c2 100644 --- a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs @@ -9,12 +9,14 @@ namespace Renci.SshNet.Abstractions [EditorBrowsable(EditorBrowsableState.Never)] public static class DiagnosticAbstraction { -#if DEBUG /// /// The instance used by SSH.NET. /// /// /// + /// Currently, the library only traces events when compiled in Debug mode. + /// + /// /// Configuration on .NET Core must be done programmatically, e.g. /// /// DiagnosticAbstraction.Source.Switch = new SourceSwitch("sourceSwitch", "Verbose"); @@ -49,7 +51,6 @@ public static class DiagnosticAbstraction /// /// public static readonly TraceSource Source = new TraceSource("SshNet.Logging"); -#endif /// /// Logs a message to at the From 4ce18d305ef9b77db70c8b6db8d27ed091453756 Mon Sep 17 00:00:00 2001 From: Pedro Fonseca Date: Tue, 28 Nov 2023 12:59:06 +0100 Subject: [PATCH 75/96] Use hardware-accelerated AES CryptoServiceProvider (#865) * Add FEATURE_AES_CSP to use hardware-accelerated AesCryptoServiceProvider Reduces CPU usage dramatically, allowing more performance on slower machines * Restructure, move most of the feature code to AesCipher.cs Fix padding for non-AES blockciphers Fix IV exception for non-AES blockciphers * Fix the AES Padding It looks like the legacy code doesn't correctly remove padding, so this code needs to do the same. * fix rebase issues restructure AES CSP code into its own class * Minor fixes * Rework based on suggestions * Move all changes to AesCypher.cs, as per Rob-Hague suggestion Remove FEATURE_AES_CSP conditional Fix OFB CipherMode * update AesCipherTest.cs generator * Fix continuous session encrypt/decrypt (preserve IV between calls when Padding is None) * Reduce CTR memory usage in Net 6+ Small performance increase in CTR buffer mode Cosmetic changes * Factor out the implementations and re-add the existing constructor * remove ctor; revert tests; remove unused _iv member * Reorder Encryption cipher preference list * Remove redundant AES tests Add tests for stream cipher state preservation * Refactor ArrayXOR() * Add test for IV overflow * Performance bump for AES CTR (thanks @robhague) * fix merge conflict * Move AesCipherMode enum to its own file --------- Co-authored-by: Pedro Fonseca Co-authored-by: Rob Hague --- .editorconfig | 15 + src/Renci.SshNet/ConnectionInfo.cs | 12 +- src/Renci.SshNet/PrivateKeyFile.cs | 10 +- .../Cryptography/Ciphers/AesCipher.BclImpl.cs | 108 ++++++ .../Ciphers/AesCipher.BlockImpl.cs | 54 +++ .../Cryptography/Ciphers/AesCipher.CtrImpl.cs | 219 +++++++++++++ .../Cryptography/Ciphers/AesCipher.cs | 110 ++++--- .../Cryptography/Ciphers/AesCipherMode.cs | 26 ++ .../Ciphers/Modes/OfbCipherMode.cs | 2 +- .../Ciphers/AesCipherBenchmarks.cs | 43 ++- .../Ciphers/AesCipherTest.Gen.cs.txt | 14 +- .../Cryptography/Ciphers/AesCipherTest.cs | 307 ++++++++++++------ 12 files changed, 740 insertions(+), 180 deletions(-) create mode 100644 src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BclImpl.cs create mode 100644 src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BlockImpl.cs create mode 100644 src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.CtrImpl.cs create mode 100644 src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipherMode.cs diff --git a/.editorconfig b/.editorconfig index 30ee78be8..86ba08e01 100644 --- a/.editorconfig +++ b/.editorconfig @@ -291,6 +291,9 @@ dotnet_diagnostic.SA1520.severity = none # We do not use file headers. dotnet_diagnostic.SA1633.severity = none +# SA1601: Partial elements should be documented +dotnet_diagnostic.SA1601.severity = none + # SA1648: must be used with inheriting class # # This rule is disabled by default, hence we need to explicitly enable it. @@ -555,6 +558,18 @@ dotnet_code_quality.CA1859.api_surface = all # This is similar to, but less powerful than, MA0015. dotnet_diagnostic.CA2208.severity = none +# CA5358: Do Not Use Unsafe Cipher Modes / Review cipher mode usage with cryptography experts +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca5358 +# +# We use ECB mode as the basis for other modes (e.g. CTR) +dotnet_diagnostic.CA5358.severity = none + +# CA5401: Do not use CreateEncryptor with non-default IV +# https://learn.microsoft.com/en-gb/dotnet/fundamentals/code-analysis/quality-rules/ca5401 +# +# We need to specify the IV. +dotnet_diagnostic.CA5401.severity = none + #### Roslyn IDE analyser rules #### # IDE0028: Simplify collection initialization; and diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index 02e817b24..6ffbf5979 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -360,11 +360,13 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy Encryptions = new Dictionary { - { "aes256-ctr", new CipherInfo(256, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), padding: null)) }, + { "aes128-ctr", new CipherInfo(128, (key, iv) => new AesCipher(key, iv, AesCipherMode.CTR, pkcs7Padding: false)) }, + { "aes192-ctr", new CipherInfo(192, (key, iv) => new AesCipher(key, iv, AesCipherMode.CTR, pkcs7Padding: false)) }, + { "aes256-ctr", new CipherInfo(256, (key, iv) => new AesCipher(key, iv, AesCipherMode.CTR, pkcs7Padding: false)) }, + { "aes128-cbc", new CipherInfo(128, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: false)) }, + { "aes192-cbc", new CipherInfo(192, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: false)) }, + { "aes256-cbc", new CipherInfo(256, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: false)) }, { "3des-cbc", new CipherInfo(192, (key, iv) => new TripleDesCipher(key, new CbcCipherMode(iv), padding: null)) }, - { "aes128-cbc", new CipherInfo(128, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), padding: null)) }, - { "aes192-cbc", new CipherInfo(192, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), padding: null)) }, - { "aes256-cbc", new CipherInfo(256, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), padding: null)) }, { "blowfish-cbc", new CipherInfo(128, (key, iv) => new BlowfishCipher(key, new CbcCipherMode(iv), padding: null)) }, { "twofish-cbc", new CipherInfo(256, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), padding: null)) }, { "twofish192-cbc", new CipherInfo(192, (key, iv) => new TwofishCipher(key, new CbcCipherMode(iv), padding: null)) }, @@ -374,8 +376,6 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy { "arcfour128", new CipherInfo(128, (key, iv) => new Arc4Cipher(key, dischargeFirstBytes: true)) }, { "arcfour256", new CipherInfo(256, (key, iv) => new Arc4Cipher(key, dischargeFirstBytes: true)) }, { "cast128-cbc", new CipherInfo(128, (key, iv) => new CastCipher(key, new CbcCipherMode(iv), padding: null)) }, - { "aes128-ctr", new CipherInfo(128, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), padding: null)) }, - { "aes192-ctr", new CipherInfo(192, (key, iv) => new AesCipher(key, new CtrCipherMode(iv), padding: null)) }, }; HmacAlgorithms = new Dictionary diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 21c34cfe0..1373630cd 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -226,13 +226,13 @@ private void Open(Stream privateKey, string passPhrase) cipher = new CipherInfo(64, (key, iv) => new DesCipher(key, new CbcCipherMode(iv), new PKCS7Padding())); break; case "AES-128-CBC": - cipher = new CipherInfo(128, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding())); + cipher = new CipherInfo(128, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: true)); break; case "AES-192-CBC": - cipher = new CipherInfo(192, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding())); + cipher = new CipherInfo(192, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: true)); break; case "AES-256-CBC": - cipher = new CipherInfo(256, (key, iv) => new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding())); + cipher = new CipherInfo(256, (key, iv) => new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: true)); break; default: throw new SshException(string.Format(CultureInfo.InvariantCulture, "Private key cipher \"{0}\" is not supported.", cipherName)); @@ -522,10 +522,10 @@ private static Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) switch (cipherName) { case "aes256-cbc": - cipher = new AesCipher(key, new CbcCipherMode(iv), new PKCS7Padding()); + cipher = new AesCipher(key, iv, AesCipherMode.CBC, pkcs7Padding: false); break; case "aes256-ctr": - cipher = new AesCipher(key, new CtrCipherMode(iv), new PKCS7Padding()); + cipher = new AesCipher(key, iv, AesCipherMode.CTR, pkcs7Padding: false); break; default: throw new SshException("Cipher '" + cipherName + "' is not supported for an OpenSSH key."); diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BclImpl.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BclImpl.cs new file mode 100644 index 000000000..0941489f5 --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BclImpl.cs @@ -0,0 +1,108 @@ +锘縰sing System; +using System.Security.Cryptography; + +using Renci.SshNet.Common; + +namespace Renci.SshNet.Security.Cryptography.Ciphers +{ + public partial class AesCipher + { + private sealed class BclImpl : BlockCipher, IDisposable + { + private readonly Aes _aes; + private readonly ICryptoTransform _encryptor; + private readonly ICryptoTransform _decryptor; + + public BclImpl( + byte[] key, + byte[] iv, + System.Security.Cryptography.CipherMode cipherMode, + PaddingMode paddingMode) + : base(key, 16, mode: null, padding: null) + { + var aes = Aes.Create(); + aes.Key = key; + + if (cipherMode != System.Security.Cryptography.CipherMode.ECB) + { + if (iv is null) + { + throw new ArgumentNullException(nameof(iv)); + } + + aes.IV = iv.Take(16); + } + + aes.Mode = cipherMode; + aes.Padding = paddingMode; + aes.FeedbackSize = 128; // We use CFB128 + _aes = aes; + _encryptor = aes.CreateEncryptor(); + _decryptor = aes.CreateDecryptor(); + } + + public override byte[] Encrypt(byte[] input, int offset, int length) + { + if (_aes.Padding != PaddingMode.None) + { + // If padding has been specified, call TransformFinalBlock to apply + // the padding and reset the state. + return _encryptor.TransformFinalBlock(input, offset, length); + } + + // Otherwise, (the most important case) assume this instance is + // used for one direction of an SSH connection, whereby the + // encrypted data in all packets are considered a single data + // stream i.e. we do not want to reset the state between calls to Encrypt. + var output = new byte[length]; + _ = _encryptor.TransformBlock(input, offset, length, output, 0); + return output; + } + + public override byte[] Decrypt(byte[] input, int offset, int length) + { + if (_aes.Padding != PaddingMode.None) + { + // If padding has been specified, call TransformFinalBlock to apply + // the padding and reset the state. + return _decryptor.TransformFinalBlock(input, offset, length); + } + + // Otherwise, (the most important case) assume this instance is + // used for one direction of an SSH connection, whereby the + // encrypted data in all packets are considered a single data + // stream i.e. we do not want to reset the state between calls to Decrypt. + var output = new byte[length]; + _ = _decryptor.TransformBlock(input, offset, length, output, 0); + return output; + } + + public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + throw new NotImplementedException($"Invalid usage of {nameof(EncryptBlock)}."); + } + + public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + throw new NotImplementedException($"Invalid usage of {nameof(DecryptBlock)}."); + } + + private void Dispose(bool disposing) + { + if (disposing) + { + _aes.Dispose(); + _encryptor.Dispose(); + _decryptor.Dispose(); + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } + } +} diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BlockImpl.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BlockImpl.cs new file mode 100644 index 000000000..ff261d767 --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.BlockImpl.cs @@ -0,0 +1,54 @@ +锘縰sing System; +using System.Security.Cryptography; + +namespace Renci.SshNet.Security.Cryptography.Ciphers +{ + public partial class AesCipher + { + private sealed class BlockImpl : BlockCipher, IDisposable + { + private readonly Aes _aes; + private readonly ICryptoTransform _encryptor; + private readonly ICryptoTransform _decryptor; + + public BlockImpl(byte[] key, CipherMode mode, CipherPadding padding) + : base(key, 16, mode, padding) + { + var aes = Aes.Create(); + aes.Key = key; + aes.Mode = System.Security.Cryptography.CipherMode.ECB; + aes.Padding = PaddingMode.None; + _aes = aes; + _encryptor = aes.CreateEncryptor(); + _decryptor = aes.CreateDecryptor(); + } + + public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + return _encryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); + } + + public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + return _decryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); + } + + private void Dispose(bool disposing) + { + if (disposing) + { + _aes.Dispose(); + _encryptor.Dispose(); + _decryptor.Dispose(); + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } + } +} diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.CtrImpl.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.CtrImpl.cs new file mode 100644 index 000000000..dacaf4a79 --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.CtrImpl.cs @@ -0,0 +1,219 @@ +锘縰sing System; +#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER +using System.Buffers.Binary; +using System.Numerics; +#endif +using System.Security.Cryptography; + +namespace Renci.SshNet.Security.Cryptography.Ciphers +{ + public partial class AesCipher + { + private sealed class CtrImpl : BlockCipher, IDisposable + { + private readonly Aes _aes; + + private readonly ICryptoTransform _encryptor; + +#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER + private ulong _ivUpper; // The upper 64 bits of the IV + private ulong _ivLower; // The lower 64 bits of the IV +#else + // The same on netfx + private readonly uint[] _packedIV; +#endif + + public CtrImpl( + byte[] key, + byte[] iv) + : base(key, 16, mode: null, padding: null) + { + var aes = Aes.Create(); + aes.Key = key; + aes.Mode = System.Security.Cryptography.CipherMode.ECB; + aes.Padding = PaddingMode.None; + _aes = aes; + _encryptor = aes.CreateEncryptor(); + +#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER + _ivLower = BinaryPrimitives.ReadUInt64BigEndian(iv.AsSpan(8)); + _ivUpper = BinaryPrimitives.ReadUInt64BigEndian(iv); +#else + _packedIV = GetPackedIV(iv); +#endif + } + + public override byte[] Encrypt(byte[] input, int offset, int length) + { + return CTREncryptDecrypt(input, offset, length); + } + + public override byte[] Decrypt(byte[] input, int offset, int length) + { + return CTREncryptDecrypt(input, offset, length); + } + + public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + throw new NotImplementedException($"Invalid usage of {nameof(DecryptBlock)}."); + } + + public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) + { + throw new NotImplementedException($"Invalid usage of {nameof(EncryptBlock)}."); + } + + private byte[] CTREncryptDecrypt(byte[] data, int offset, int length) + { + var count = length / BlockSize; + if (length % BlockSize != 0) + { + count++; + } + + var buffer = new byte[count * BlockSize]; + CTRCreateCounterArray(buffer); + _ = _encryptor.TransformBlock(buffer, 0, buffer.Length, buffer, 0); + ArrayXOR(buffer, data, offset, length); + + // adjust output for non-blocksized lengths + if (buffer.Length > length) + { + Array.Resize(ref buffer, length); + } + + return buffer; + } + +#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER + + // creates the Counter array filled with incrementing copies of IV + private void CTRCreateCounterArray(byte[] buffer) + { + for (var i = 0; i < buffer.Length; i += 16) + { + BinaryPrimitives.WriteUInt64BigEndian(buffer.AsSpan(i + 8), _ivLower); + BinaryPrimitives.WriteUInt64BigEndian(buffer.AsSpan(i), _ivUpper); + + _ivLower += 1; + _ivUpper += (_ivLower == 0) ? 1UL : 0UL; + } + } + + // XOR 2 arrays using Vector + private static void ArrayXOR(byte[] buffer, byte[] data, int offset, int length) + { + var i = 0; + + var oneVectorFromEnd = length - Vector.Count; + for (; i <= oneVectorFromEnd; i += Vector.Count) + { + var v = new Vector(buffer, i) ^ new Vector(data, offset + i); + v.CopyTo(buffer, i); + } + + for (; i < length; i++) + { + buffer[i] ^= data[offset + i]; + } + } + +#else + // creates the Counter array filled with incrementing copies of IV + private void CTRCreateCounterArray(byte[] buffer) + { + // fill array with IV, increment by 1 for each copy + var words = buffer.Length / 4; + var counter = new uint[words]; + for (var i = 0; i < words; i += 4) + { + // write IV to buffer (big endian) + counter[i] = _packedIV[0]; + counter[i + 1] = _packedIV[1]; + counter[i + 2] = _packedIV[2]; + counter[i + 3] = _packedIV[3]; + + // increment IV (little endian) + if (_packedIV[3] < 0xFF000000u) + { + _packedIV[3] += 0x01000000u; + } + else + { + var j = 3; + do + { + _packedIV[j] = SwapEndianness(SwapEndianness(_packedIV[j]) + 1); + } + while (_packedIV[j] == 0 && --j >= 0); + } + } + + // copy uint[] to byte[] + Buffer.BlockCopy(counter, 0, buffer, 0, buffer.Length); + } + + // XOR 2 arrays using Uint[] and blockcopy + private static void ArrayXOR(byte[] buffer, byte[] data, int offset, int length) + { + var words = length / 4; + if (length % 4 != 0) + { + words++; + } + + // convert original data to words + var datawords = new uint[words]; + Buffer.BlockCopy(data, offset, datawords, 0, length); + + // convert encrypted IV counter to words + var bufferwords = new uint[words]; + Buffer.BlockCopy(buffer, 0, bufferwords, 0, length); + + // XOR encrypted Counter with input data + for (var i = 0; i < words; i++) + { + bufferwords[i] = bufferwords[i] ^ datawords[i]; + } + + // copy uint[] to byte[] + Buffer.BlockCopy(bufferwords, 0, buffer, 0, length); + } + + // pack the IV into an array of uint[4] + private static uint[] GetPackedIV(byte[] iv) + { + var packedIV = new uint[4]; + packedIV[0] = BitConverter.ToUInt32(iv, 0); + packedIV[1] = BitConverter.ToUInt32(iv, 4); + packedIV[2] = BitConverter.ToUInt32(iv, 8); + packedIV[3] = BitConverter.ToUInt32(iv, 12); + + return packedIV; + } + + private static uint SwapEndianness(uint x) + { + x = (x >> 16) | (x << 16); + return ((x & 0xFF00FF00) >> 8) | ((x & 0x00FF00FF) << 8); + } +#endif + + private void Dispose(bool disposing) + { + if (disposing) + { + _aes.Dispose(); + _encryptor.Dispose(); + } + } + + public void Dispose() + { + // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method + Dispose(disposing: true); + GC.SuppressFinalize(this); + } + } + } +} diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs index 235040446..447e1aee3 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipher.cs @@ -1,86 +1,90 @@ -锘縰sing System; +using System; using System.Security.Cryptography; +using Renci.SshNet.Security.Cryptography.Ciphers.Modes; +using Renci.SshNet.Security.Cryptography.Ciphers.Paddings; + namespace Renci.SshNet.Security.Cryptography.Ciphers { /// /// AES cipher implementation. /// - public sealed class AesCipher : BlockCipher, IDisposable + public sealed partial class AesCipher : BlockCipher, IDisposable { - private readonly Aes _aes; - private ICryptoTransform _encryptor; - private ICryptoTransform _decryptor; + private readonly BlockCipher _impl; /// /// Initializes a new instance of the class. /// /// The key. /// The mode. - /// The padding. + /// The IV. + /// Enable PKCS7 padding. /// is . /// Keysize is not valid for this algorithm. - public AesCipher(byte[] key, CipherMode mode, CipherPadding padding) - : base(key, 16, mode, padding) + public AesCipher(byte[] key, byte[] iv, AesCipherMode mode, bool pkcs7Padding = false) + : base(key, 16, mode: null, padding: null) { - var aes = Aes.Create(); - aes.Key = key; -#pragma warning disable CA5358 // Do not use unsafe cipher modes; this is the basis for other modes. - aes.Mode = System.Security.Cryptography.CipherMode.ECB; -#pragma warning restore CA5358 // Do not use unsafe cipher modes - aes.Padding = PaddingMode.None; - _aes = aes; + if (mode == AesCipherMode.OFB) + { + // OFB is not supported on modern .NET + _impl = new BlockImpl(key, new OfbCipherMode(iv), pkcs7Padding ? new PKCS7Padding() : null); + } +#if !NET6_0_OR_GREATER + else if (mode == AesCipherMode.CFB) + { + // CFB not supported on NetStandard 2.1 + _impl = new BlockImpl(key, new CfbCipherMode(iv), pkcs7Padding ? new PKCS7Padding() : null); + } +#endif + else if (mode == AesCipherMode.CTR) + { + // CTR not supported by the BCL, use an optimized implementation + _impl = new CtrImpl(key, iv); + } + else + { + _impl = new BclImpl( + key, + iv, + (System.Security.Cryptography.CipherMode) mode, + pkcs7Padding ? PaddingMode.PKCS7 : PaddingMode.None); + } } - /// - /// Encrypts the specified region of the input byte array and copies the encrypted data to the specified region of the output byte array. - /// - /// The input data to encrypt. - /// The offset into the input byte array from which to begin using data. - /// The number of bytes in the input byte array to use as data. - /// The output to which to write encrypted data. - /// The offset into the output byte array from which to begin writing data. - /// - /// The number of bytes encrypted. - /// - /// or is . - /// or is too short. + /// public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - _encryptor ??= _aes.CreateEncryptor(); - - return _encryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); + return _impl.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); } - /// - /// Decrypts the specified region of the input byte array and copies the decrypted data to the specified region of the output byte array. - /// - /// The input data to decrypt. - /// The offset into the input byte array from which to begin using data. - /// The number of bytes in the input byte array to use as data. - /// The output to which to write decrypted data. - /// The offset into the output byte array from which to begin writing data. - /// - /// The number of bytes decrypted. - /// - /// or is . - /// or is too short. + /// public override int DecryptBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { - _decryptor ??= _aes.CreateDecryptor(); + return _impl.EncryptBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); + } - return _decryptor.TransformBlock(inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset); + /// + public override byte[] Encrypt(byte[] input, int offset, int length) + { + return _impl.Encrypt(input, offset, length); } - private void Dispose(bool disposing) + /// + public override byte[] Decrypt(byte[] input, int offset, int length) { - if (disposing) - { - _encryptor?.Dispose(); - _encryptor = null; + return _impl.Decrypt(input, offset, length); + } - _decryptor?.Dispose(); - _decryptor = null; + /// + /// Dispose the instance. + /// + /// Set to True to dispose of resouces. + public void Dispose(bool disposing) + { + if (disposing && _impl is IDisposable disposableImpl) + { + disposableImpl.Dispose(); } } diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipherMode.cs new file mode 100644 index 000000000..51ebfdd14 --- /dev/null +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/AesCipherMode.cs @@ -0,0 +1,26 @@ +锘縩amespace Renci.SshNet.Security.Cryptography.Ciphers +{ + /// + /// Custom AES Cipher Mode, follows System.Security.Cryptography.CipherMode. + /// + public enum AesCipherMode + { + /// CBC Mode. + CBC = 1, + + /// ECB Mode. + ECB = 2, + + /// OFB Mode. + OFB = 3, + + /// CFB Mode. + CFB = 4, + + /// CTS Mode. + CTS = 5, + + /// CTR Mode. + CTR = 6 + } +} diff --git a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs index df2ce60be..70b6473d3 100644 --- a/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs +++ b/src/Renci.SshNet/Security/Cryptography/Ciphers/Modes/OfbCipherMode.cs @@ -54,7 +54,7 @@ public override int EncryptBlock(byte[] inputBuffer, int inputOffset, int inputC for (var i = 0; i < _blockSize; i++) { - outputBuffer[outputOffset + i] = (byte)(_ivOutput[i] ^ inputBuffer[inputOffset + i]); + outputBuffer[outputOffset + i] = (byte) (_ivOutput[i] ^ inputBuffer[inputOffset + i]); } return _blockSize; diff --git a/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs index ff414cc4a..f24559c5b 100644 --- a/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs +++ b/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/AesCipherBenchmarks.cs @@ -1,6 +1,5 @@ 锘縰sing BenchmarkDotNet.Attributes; using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; namespace Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers { @@ -15,7 +14,7 @@ public AesCipherBenchmarks() { _key = new byte[32]; _iv = new byte[16]; - _data = new byte[256]; + _data = new byte[32 * 1024]; Random random = new(Seed: 12345); random.NextBytes(_key); @@ -26,13 +25,49 @@ public AesCipherBenchmarks() [Benchmark] public byte[] Encrypt_CBC() { - return new AesCipher(_key, new CbcCipherMode(_iv), null).Encrypt(_data); + return new AesCipher(_key, _iv, AesCipherMode.CBC, false).Encrypt(_data); } [Benchmark] public byte[] Decrypt_CBC() { - return new AesCipher(_key, new CbcCipherMode(_iv), null).Decrypt(_data); + return new AesCipher(_key, _iv, AesCipherMode.CBC, false).Decrypt(_data); + } + + [Benchmark] + public byte[] Encrypt_CFB() + { + return new AesCipher(_key, _iv, AesCipherMode.CFB, false).Encrypt(_data); + } + + [Benchmark] + public byte[] Decrypt_CFB() + { + return new AesCipher(_key, _iv, AesCipherMode.CFB, false).Decrypt(_data); + } + + [Benchmark] + public byte[] Encrypt_CTR() + { + return new AesCipher(_key, _iv, AesCipherMode.CTR, false).Encrypt(_data); + } + + [Benchmark] + public byte[] Decrypt_CTR() + { + return new AesCipher(_key, _iv, AesCipherMode.CTR, false).Decrypt(_data); + } + + [Benchmark] + public byte[] Encrypt_ECB() + { + return new AesCipher(_key, null, AesCipherMode.ECB, false).Encrypt(_data); + } + + [Benchmark] + public byte[] Decrypt_ECB() + { + return new AesCipher(_key, null, AesCipherMode.ECB, false).Decrypt(_data); } } } diff --git a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.Gen.cs.txt b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.Gen.cs.txt index c0bda499b..3b3bfa65d 100644 --- a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.Gen.cs.txt +++ b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.Gen.cs.txt @@ -6,11 +6,11 @@ Dictionary modes = new() { - ["ecb"] = ("mode: null", CipherMode.ECB), - ["cbc"] = ("new CbcCipherMode((byte[])iv.Clone())", CipherMode.CBC), - ["cfb"] = ("new CfbCipherMode((byte[])iv.Clone())", CipherMode.CFB), - ["ctr"] = ("new CtrCipherMode((byte[])iv.Clone())", null), - ["ofb"] = ("new OfbCipherMode((byte[])iv.Clone())", CipherMode.OFB), + ["ecb"] = ("iv: null, AesCipherMode.ECB", CipherMode.ECB), + ["cbc"] = ("(byte[])iv.Clone(), AesCipherMode.CBC", CipherMode.CBC), + ["cfb"] = ("(byte[])iv.Clone(), AesCipherMode.CFB", CipherMode.CFB), + ["ctr"] = ("(byte[])iv.Clone(), AesCipherMode.CTR", null), + ["ofb"] = ("(byte[])iv.Clone(), AesCipherMode.OFB", CipherMode.OFB), }; Random random = new(123); @@ -90,7 +90,7 @@ foreach ((string mode, (string modeCode, CipherMode? bclMode)) in modes) tw.WriteLine($"// {openSslCmd} | hd"); // pipe to hexdump WriteBytes(expected); tw.WriteLine(); - tw.WriteLine($"var actual = new AesCipher(key, {modeCode}, padding: null).Encrypt(input);"); + tw.WriteLine($"var actual = new AesCipher(key, {modeCode}, pkcs7Padding: false).Encrypt(input);"); tw.WriteLine(); tw.WriteLine($"CollectionAssert.AreEqual(expected, actual);"); @@ -117,7 +117,7 @@ foreach ((string mode, (string modeCode, CipherMode? bclMode)) in modes) } tw.WriteLine(); - tw.WriteLine($"var decrypted = new AesCipher(key, {modeCode}, padding: null).Decrypt(actual);"); + tw.WriteLine($"var decrypted = new AesCipher(key, {modeCode}, pkcs7Padding: false).Decrypt(actual);"); tw.WriteLine(); tw.WriteLine($"CollectionAssert.AreEqual(input, decrypted);"); diff --git a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs index 1587481ea..e1a0e9744 100644 --- a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/Ciphers/AesCipherTest.cs @@ -1,7 +1,8 @@ -锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; +锘縰sing System.Linq; + +using Microsoft.VisualStudio.TestTools.UnitTesting; using Renci.SshNet.Common; using Renci.SshNet.Security.Cryptography.Ciphers; -using Renci.SshNet.Security.Cryptography.Ciphers.Modes; using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers @@ -13,19 +14,116 @@ namespace Renci.SshNet.Tests.Classes.Security.Cryptography.Ciphers public class AesCipherTest : TestBase { [TestMethod] - public void Encrypt_Input_128_CBC() + public void AES_CTR_Encrypt_Should_Preserve_Cipher_Stream_State() { - var input = new byte[] { 0x00, 0x00, 0x00, 0x2c, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x0c, 0x73, 0x73, 0x68, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x61, 0x75, 0x74, 0x68, 0x30, 0x9e, 0xe0, 0x9c, 0x12, 0xee, 0x3a, 0x30, 0x03, 0x52, 0x1c, 0x1a, 0xe7, 0x3e, 0x0b, 0x9a, 0xcf, 0x9a, 0x57, 0x42, 0x0b, 0x4f, 0x4a, 0x15, 0xa0, 0xf5 }; - var key = new byte[] { 0xe4, 0x94, 0xf9, 0xb1, 0x00, 0x4f, 0x16, 0x2a, 0x80, 0x11, 0xea, 0x73, 0x0d, 0xb9, 0xbf, 0x64 }; - var iv = new byte[] { 0x74, 0x8b, 0x4f, 0xe6, 0xc1, 0x29, 0xb3, 0x54, 0xec, 0x77, 0x92, 0xf3, 0x15, 0xa0, 0x41, 0xa8 }; - var expected = new byte[] { 0x19, 0x7f, 0x80, 0xd8, 0xc9, 0x89, 0xc4, 0xa7, 0xc6, 0xc6, 0x3f, 0x9f, 0x1e, 0x00, 0x1f, 0x72, 0xa7, 0x5e, 0xde, 0x40, 0x88, 0xa2, 0x72, 0xf2, 0xed, 0x3f, 0x81, 0x45, 0xb6, 0xbd, 0x45, 0x87, 0x15, 0xa5, 0x10, 0x92, 0x4a, 0x37, 0x9e, 0xa9, 0x80, 0x1c, 0x14, 0x83, 0xa3, 0x39, 0x45, 0x28 }; - var testCipher = new AesCipher(key, new CbcCipherMode(iv), null); + var input = new byte[] + { + 0x9b, 0x6e, 0x1d, 0xf8, 0x07, 0xf9, 0x55, 0xd4, 0xd7, 0x1a, 0xce, 0xca, 0xa8, 0x31, 0x29, 0x0f, + 0x63, 0x4d, 0x52, 0x71, 0xa5, 0x0c, 0x96, 0x08, 0xd6, 0xc5, 0x14, 0xa0, 0xc8, 0x29, 0xb1, 0xd5, + 0x40, 0x2c, 0xe5, 0xa9, 0xb4, 0x31, 0xa9, 0xa8, 0x76, 0xa5, 0x1e, 0x7a, 0xc8, 0x09, 0x32, 0x39, + 0xbc, 0x89, 0x7a, 0x22, 0x42, 0x2c, 0xba, 0x8e, 0xd7, 0x15, 0x22, 0x41, 0xe4, 0xb5, 0x0b, 0xad, + }; + var key = new byte[] + { + 0x69, 0xf9, 0x8a, 0x7c, 0x4b, 0x80, 0x5b, 0x31, 0xa4, 0xaa, 0xfa, 0xff, 0xed, 0x1c, 0x3f, 0xcc, + }; + var iv = new byte[] + { + 0x92, 0xdb, 0xe4, 0x3e, 0xaf, 0x8f, 0x92, 0x13, 0x71, 0x56, 0xd1, 0x9f, 0x0f, 0x68, 0xc3, 0xc1, + }; - var actual = testCipher.Encrypt(input); + // echo -n -e '\x9b\x6e\x1d\xf8\x07\xf9\x55\xd4\xd7\x1a\xce\xca\xa8\x31\x29\x0f\x63\x4d\x52\x71\xa5\x0c\x96\x08\xd6\xc5\x14\xa0\xc8\x29\xb1\xd5\x40\x2c\xe5\xa9\xb4\x31\xa9\xa8\x76\xa5\x1e\x7a\xc8\x09\x32\x39\xbc\x89\x7a\x22\x42\x2c\xba\x8e\xd7\x15\x22\x41\xe4\xb5\x0b\xad' | openssl enc -e -aes-128-ctr -K 69F98A7C4B805B31A4AAFAFFED1C3FCC -iv 92DBE43EAF8F92137156D19F0F68C3C1 -nopad | hd + var expected = new byte[] + { + 0xc0, 0x69, 0x4b, 0xdb, 0xb2, 0x0c, 0x22, 0x82, 0xf0, 0x85, 0x77, 0x3e, 0xd9, 0x5a, 0xe7, 0x9e, + 0xb0, 0x34, 0xe8, 0x95, 0x8e, 0x93, 0x0a, 0xcf, 0xa4, 0x26, 0xd3, 0x80, 0x12, 0xcc, 0x06, 0x38, + 0x1d, 0x18, 0x55, 0xfc, 0x56, 0x59, 0xaf, 0x0b, 0x2b, 0x80, 0x87, 0x0c, 0x87, 0x45, 0xb0, 0xe2, + 0xec, 0x47, 0x81, 0x82, 0x89, 0x24, 0x76, 0xe2, 0x20, 0x6a, 0x99, 0xe2, 0xa7, 0x5a, 0xb0, 0x40, + }; - Assert.IsTrue(actual.IsEqualTo(expected)); + var cipher = new AesCipher(key, (byte[]) iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false); + var actual1 = cipher.Encrypt(input.Take(32)); + var actual2 = cipher.Encrypt(input.Take(32, 32)); + + CollectionAssert.AreEqual(expected.Take(32), actual1); + CollectionAssert.AreEqual(expected.Take(32, 32), actual2); + } + + [TestMethod] + public void AES_CTR_Decrypt_Should_Preserve_Cipher_Stream_State() + { + var input = new byte[] + { + 0xc0, 0x69, 0x4b, 0xdb, 0xb2, 0x0c, 0x22, 0x82, 0xf0, 0x85, 0x77, 0x3e, 0xd9, 0x5a, 0xe7, 0x9e, + 0xb0, 0x34, 0xe8, 0x95, 0x8e, 0x93, 0x0a, 0xcf, 0xa4, 0x26, 0xd3, 0x80, 0x12, 0xcc, 0x06, 0x38, + 0x1d, 0x18, 0x55, 0xfc, 0x56, 0x59, 0xaf, 0x0b, 0x2b, 0x80, 0x87, 0x0c, 0x87, 0x45, 0xb0, 0xe2, + 0xec, 0x47, 0x81, 0x82, 0x89, 0x24, 0x76, 0xe2, 0x20, 0x6a, 0x99, 0xe2, 0xa7, 0x5a, 0xb0, 0x40, + }; + var key = new byte[] + { + 0x69, 0xf9, 0x8a, 0x7c, 0x4b, 0x80, 0x5b, 0x31, 0xa4, 0xaa, 0xfa, 0xff, 0xed, 0x1c, 0x3f, 0xcc, + }; + var iv = new byte[] + { + 0x92, 0xdb, 0xe4, 0x3e, 0xaf, 0x8f, 0x92, 0x13, 0x71, 0x56, 0xd1, 0x9f, 0x0f, 0x68, 0xc3, 0xc1, + }; + + // echo -n -e '\x9b\x6e\x1d\xf8\x07\xf9\x55\xd4\xd7\x1a\xce\xca\xa8\x31\x29\x0f\x63\x4d\x52\x71\xa5\x0c\x96\x08\xd6\xc5\x14\xa0\xc8\x29\xb1\xd5\x40\x2c\xe5\xa9\xb4\x31\xa9\xa8\x76\xa5\x1e\x7a\xc8\x09\x32\x39\xbc\x89\x7a\x22\x42\x2c\xba\x8e\xd7\x15\x22\x41\xe4\xb5\x0b\xad' | openssl enc -e -aes-128-ctr -K 69F98A7C4B805B31A4AAFAFFED1C3FCC -iv 92DBE43EAF8F92137156D19F0F68C3C1 -nopad | hd + var expected = new byte[] + { + 0x9b, 0x6e, 0x1d, 0xf8, 0x07, 0xf9, 0x55, 0xd4, 0xd7, 0x1a, 0xce, 0xca, 0xa8, 0x31, 0x29, 0x0f, + 0x63, 0x4d, 0x52, 0x71, 0xa5, 0x0c, 0x96, 0x08, 0xd6, 0xc5, 0x14, 0xa0, 0xc8, 0x29, 0xb1, 0xd5, + 0x40, 0x2c, 0xe5, 0xa9, 0xb4, 0x31, 0xa9, 0xa8, 0x76, 0xa5, 0x1e, 0x7a, 0xc8, 0x09, 0x32, 0x39, + 0xbc, 0x89, 0x7a, 0x22, 0x42, 0x2c, 0xba, 0x8e, 0xd7, 0x15, 0x22, 0x41, 0xe4, 0xb5, 0x0b, 0xad, + }; + + var cipher = new AesCipher(key, (byte[]) iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false); + var actual1 = cipher.Decrypt(input.Take(32)); + var actual2 = cipher.Decrypt(input.Take(32, 32)); + + CollectionAssert.AreEqual(expected.Take(32), actual1); + CollectionAssert.AreEqual(expected.Take(32, 32), actual2); } + [TestMethod] + public void AES_CTR_IV_Overflow() + { + var input = new byte[] + { + 0x03, 0xe1, 0xe1, 0xaa, 0xa5, 0xbc, 0xa1, 0x9f, 0xba, 0x8c, 0x42, 0x05, 0x8b, 0x4a, 0xbf, 0x28, + 0x96, 0x39, 0xec, 0x0d, 0xfc, 0x2d, 0xb2, 0x7c, 0xe9, 0x74, 0x8e, 0x5f, 0xb9, 0xf3, 0x99, 0xce, + 0xe1, 0x1a, 0x5c, 0x51, 0xa3, 0x1d, 0xd7, 0x1b, 0x15, 0x8c, 0xad, 0xa6, 0xaf, 0x63, 0x0d, 0x8c, + 0x1a, 0xf1, 0x3a, 0x35, 0x8c, 0xca, 0x3f, 0xd6, 0x2f, 0x65, 0xc1, 0x31, 0x2d, 0x41, 0xe5, 0xc7, + }; + var key = new byte[] + { + 0xf3, 0x74, 0x23, 0x71, 0xed, 0x6d, 0x84, 0x79, 0x61, 0xd0, 0xf8, 0x6f, 0x7f, 0x0c, 0xcc, 0x86, + 0x67, 0x02, 0x45, 0xc8, 0xb8, 0x64, 0x42, 0x17, 0xda, 0x85, 0x21, 0x3e, 0x5c, 0xa6, 0xee, 0xd4, + }; + var iv = new byte[] + { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }; + + // echo -n -e '\x03\xe1\xe1\xaa\xa5\xbc\xa1\x9f\xba\x8c\x42\x05\x8b\x4a\xbf\x28\x96\x39\xec\x0d\xfc\x2d\xb2\x7c\xe9\x74\x8e\x5f\xb9\xf3\x99\xce\xe1\x1a\x5c\x51\xa3\x1d\xd7\x1b\x15\x8c\xad\xa6\xaf\x63\x0d\x8c\x1a\xf1\x3a\x35\x8c\xca\x3f\xd6\x2f\x65\xc1\x31\x2d\x41\xe5\xc7' | openssl enc -e -aes-256-ctr -K F3742371ED6D847961D0F86F7F0CCC86670245C8B8644217DA85213E5CA6EED4 -iv FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -nopad | hd + var expected = new byte[] + { + 0x4e, 0xfa, 0xa2, 0x01, 0x5c, 0x5f, 0x3a, 0x55, 0x33, 0x53, 0x51, 0xda, 0xdf, 0xa5, 0xab, 0x7e, + 0x57, 0x93, 0x2d, 0xe6, 0x99, 0x4a, 0x58, 0x56, 0xcb, 0x19, 0x9f, 0x88, 0xe1, 0xa8, 0x7b, 0xcd, + 0x3d, 0x8e, 0xdd, 0x10, 0xc8, 0xb3, 0x60, 0xb0, 0x2b, 0xaf, 0x92, 0xfe, 0x39, 0x47, 0x35, 0xcc, + 0xfd, 0x34, 0xc5, 0x81, 0xfa, 0xb9, 0xe3, 0xc4, 0x10, 0xed, 0x06, 0x6e, 0x91, 0x5e, 0xfc, 0x47, + }; + + var actual = new AesCipher(key, (byte[]) iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); + + CollectionAssert.AreEqual(expected, actual); + + var decrypted = new AesCipher(key, (byte[]) iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); + + CollectionAssert.AreEqual(input, decrypted); + } + + [TestMethod] public void Encrypt_InputAndOffsetAndLength_128_CBC() { @@ -34,7 +132,7 @@ public void Encrypt_InputAndOffsetAndLength_128_CBC() var key = new byte[] { 0xe4, 0x94, 0xf9, 0xb1, 0x00, 0x4f, 0x16, 0x2a, 0x80, 0x11, 0xea, 0x73, 0x0d, 0xb9, 0xbf, 0x64 }; var iv = new byte[] { 0x74, 0x8b, 0x4f, 0xe6, 0xc1, 0x29, 0xb3, 0x54, 0xec, 0x77, 0x92, 0xf3, 0x15, 0xa0, 0x41, 0xa8 }; var expected = new byte[] { 0x19, 0x7f, 0x80, 0xd8, 0xc9, 0x89, 0xc4, 0xa7, 0xc6, 0xc6, 0x3f, 0x9f, 0x1e, 0x00, 0x1f, 0x72, 0xa7, 0x5e, 0xde, 0x40, 0x88, 0xa2, 0x72, 0xf2, 0xed, 0x3f, 0x81, 0x45, 0xb6, 0xbd, 0x45, 0x87, 0x15, 0xa5, 0x10, 0x92, 0x4a, 0x37, 0x9e, 0xa9, 0x80, 0x1c, 0x14, 0x83, 0xa3, 0x39, 0x45, 0x28 }; - var testCipher = new AesCipher(key, new CbcCipherMode(iv), null); + var testCipher = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false); var actual = testCipher.Encrypt(input, 2, input.Length - 5); @@ -48,7 +146,7 @@ public void Encrypt_Input_128_CTR() var key = new byte[] { 0x17, 0x78, 0x56, 0xe1, 0x3e, 0xbd, 0x3e, 0x50, 0x1d, 0x79, 0x3f, 0x0f, 0x55, 0x37, 0x45, 0x54 }; var iv = new byte[] { 0xe6, 0x65, 0x36, 0x0d, 0xdd, 0xd7, 0x50, 0xc3, 0x48, 0xdb, 0x48, 0x07, 0xa1, 0x30, 0xd2, 0x38 }; var expected = new byte[] { 0xca, 0xfb, 0x1c, 0x49, 0xbf, 0x82, 0x2a, 0xbb, 0x1c, 0x52, 0xc7, 0x86, 0x22, 0x8a, 0xe5, 0xa4, 0xf3, 0xda, 0x4e, 0x1c, 0x3a, 0x87, 0x41, 0x1c, 0xd2, 0x6e, 0x76, 0xdc, 0xc2, 0xe9, 0xc2, 0x0e, 0xf5, 0xc7, 0xbd, 0x12, 0x85, 0xfa, 0x0e, 0xda, 0xee, 0x50, 0xd7, 0xfd, 0x81, 0x34, 0x25, 0x6d }; - var testCipher = new AesCipher(key, new CtrCipherMode(iv), null); + var testCipher = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false); var actual = testCipher.Encrypt(input); @@ -62,7 +160,7 @@ public void Decrypt_Input_128_CTR() var iv = new byte[] { 0xe6, 0x65, 0x36, 0x0d, 0xdd, 0xd7, 0x50, 0xc3, 0x48, 0xdb, 0x48, 0x07, 0xa1, 0x30, 0xd2, 0x38 }; var input = new byte[] { 0xca, 0xfb, 0x1c, 0x49, 0xbf, 0x82, 0x2a, 0xbb, 0x1c, 0x52, 0xc7, 0x86, 0x22, 0x8a, 0xe5, 0xa4, 0xf3, 0xda, 0x4e, 0x1c, 0x3a, 0x87, 0x41, 0x1c, 0xd2, 0x6e, 0x76, 0xdc, 0xc2, 0xe9, 0xc2, 0x0e, 0xf5, 0xc7, 0xbd, 0x12, 0x85, 0xfa, 0x0e, 0xda, 0xee, 0x50, 0xd7, 0xfd, 0x81, 0x34, 0x25, 0x6d }; var expected = new byte[] { 0x00, 0x00, 0x00, 0x2c, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x0c, 0x73, 0x73, 0x68, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x61, 0x75, 0x74, 0x68, 0xb0, 0x74, 0x21, 0x87, 0x16, 0xb9, 0x69, 0x48, 0x33, 0xce, 0xb3, 0xe7, 0xdc, 0x3f, 0x50, 0xdc, 0xcc, 0xd5, 0x27, 0xb7, 0xfe, 0x7a, 0x78, 0x22, 0xae, 0xc8 }; - var testCipher = new AesCipher(key, new CtrCipherMode(iv), null); + var testCipher = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false); var actual = testCipher.Decrypt(input); @@ -76,7 +174,7 @@ public void Decrypt_InputAndOffsetAndLength_128_CTR() var iv = new byte[] { 0xe6, 0x65, 0x36, 0x0d, 0xdd, 0xd7, 0x50, 0xc3, 0x48, 0xdb, 0x48, 0x07, 0xa1, 0x30, 0xd2, 0x38 }; var input = new byte[] { 0x0a, 0xca, 0xfb, 0x1c, 0x49, 0xbf, 0x82, 0x2a, 0xbb, 0x1c, 0x52, 0xc7, 0x86, 0x22, 0x8a, 0xe5, 0xa4, 0xf3, 0xda, 0x4e, 0x1c, 0x3a, 0x87, 0x41, 0x1c, 0xd2, 0x6e, 0x76, 0xdc, 0xc2, 0xe9, 0xc2, 0x0e, 0xf5, 0xc7, 0xbd, 0x12, 0x85, 0xfa, 0x0e, 0xda, 0xee, 0x50, 0xd7, 0xfd, 0x81, 0x34, 0x25, 0x6d, 0x0a, 0x05 }; var expected = new byte[] { 0x00, 0x00, 0x00, 0x2c, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x0c, 0x73, 0x73, 0x68, 0x2d, 0x75, 0x73, 0x65, 0x72, 0x61, 0x75, 0x74, 0x68, 0xb0, 0x74, 0x21, 0x87, 0x16, 0xb9, 0x69, 0x48, 0x33, 0xce, 0xb3, 0xe7, 0xdc, 0x3f, 0x50, 0xdc, 0xcc, 0xd5, 0x27, 0xb7, 0xfe, 0x7a, 0x78, 0x22, 0xae, 0xc8 }; - var testCipher = new AesCipher(key, new CtrCipherMode(iv), null); + var testCipher = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false); var actual = testCipher.Decrypt(input, 1, input.Length - 3); @@ -103,11 +201,11 @@ public void AES_ECB_128_Length16() 0x9d, 0x55, 0x05, 0x4e, 0xe9, 0x50, 0xb5, 0x93, 0x50, 0x93, 0x69, 0x96, 0xa6, 0xdd, 0x1e, 0x15, }; - var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -132,11 +230,11 @@ public void AES_ECB_128_Length32() 0xe3, 0x1c, 0x95, 0x44, 0x49, 0x9e, 0x4a, 0x17, 0x0e, 0x64, 0xd3, 0xe8, 0x5c, 0xe6, 0x9f, 0x83, }; - var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -165,11 +263,11 @@ public void AES_ECB_128_Length64() 0x10, 0xe3, 0xe0, 0x30, 0xd3, 0x0e, 0xe3, 0x94, 0xd8, 0xf5, 0xb1, 0x44, 0xf8, 0x36, 0xfd, 0x0b, }; - var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -193,11 +291,11 @@ public void AES_ECB_192_Length16() 0x1c, 0xd3, 0x91, 0xd8, 0xc3, 0xe0, 0x4d, 0x8e, 0x9e, 0x5c, 0xaf, 0xcc, 0x55, 0x65, 0x54, 0xb7, }; - var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -223,11 +321,11 @@ public void AES_ECB_192_Length32() 0x87, 0xe2, 0x91, 0x40, 0x31, 0x26, 0x67, 0xf6, 0xf7, 0x86, 0x73, 0x89, 0x0d, 0x35, 0x22, 0x6c, }; - var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -257,11 +355,11 @@ public void AES_ECB_192_Length64() 0xcd, 0x20, 0xab, 0xbc, 0x59, 0xb2, 0xa5, 0x80, 0xf5, 0x8e, 0x53, 0xda, 0xb1, 0x39, 0x8f, 0xbc, }; - var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -285,11 +383,11 @@ public void AES_ECB_256_Length16() 0x6a, 0xd2, 0x73, 0x2b, 0x05, 0x2e, 0xdd, 0x74, 0x0c, 0x37, 0xf2, 0xcf, 0x8a, 0xef, 0x57, 0x8a, }; - var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -315,11 +413,11 @@ public void AES_ECB_256_Length32() 0x59, 0x0b, 0x9c, 0x7a, 0xf2, 0xb6, 0x34, 0x0d, 0xc9, 0xdd, 0x15, 0x6e, 0x75, 0xe7, 0xc6, 0x82, }; - var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -349,11 +447,11 @@ public void AES_ECB_256_Length64() 0x63, 0xd2, 0x7d, 0x7a, 0xfc, 0xdb, 0x11, 0x08, 0x70, 0x73, 0x61, 0xe0, 0xfb, 0x93, 0xa6, 0xf9, }; - var actual = new AesCipher(key, mode: null, padding: null).Encrypt(input); + var actual = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, mode: null, padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, iv: null, AesCipherMode.ECB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -380,11 +478,11 @@ public void AES_CBC_128_Length16() 0x49, 0x0e, 0xa9, 0x6f, 0x55, 0xb3, 0x57, 0xdf, 0x7c, 0x18, 0x77, 0x0c, 0xca, 0x46, 0x0d, 0x83, }; - var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -413,11 +511,11 @@ public void AES_CBC_128_Length32() 0x2d, 0x87, 0x42, 0x20, 0xf1, 0x0b, 0x78, 0x96, 0xd5, 0x7c, 0xeb, 0xa2, 0x7f, 0x4b, 0x5a, 0xff, }; - var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -450,11 +548,11 @@ public void AES_CBC_128_Length64() 0x3d, 0x61, 0x9e, 0x0d, 0x54, 0x7f, 0xe1, 0xc4, 0x78, 0xf2, 0x04, 0x00, 0x68, 0xa9, 0x9b, 0x32, }; - var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -482,11 +580,11 @@ public void AES_CBC_192_Length16() 0xe1, 0x2f, 0x71, 0xad, 0x59, 0xae, 0xa7, 0xe3, 0xd3, 0x23, 0x43, 0x81, 0x31, 0xc2, 0xe5, 0xd9, }; - var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -516,11 +614,11 @@ public void AES_CBC_192_Length32() 0x07, 0xf2, 0x98, 0x41, 0xbb, 0x58, 0x3d, 0xe5, 0xcf, 0x56, 0xf5, 0x4b, 0x33, 0xf7, 0xa0, 0x9a, }; - var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -554,11 +652,11 @@ public void AES_CBC_192_Length64() 0xda, 0xba, 0xde, 0xb2, 0x7d, 0xbc, 0x71, 0xf8, 0x9b, 0xaa, 0x93, 0x52, 0xf4, 0x26, 0x3c, 0x6f, }; - var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -586,11 +684,11 @@ public void AES_CBC_256_Length16() 0xe7, 0xa5, 0x53, 0xd7, 0x28, 0x4c, 0x16, 0x4e, 0xfc, 0xa2, 0xa8, 0x86, 0xfc, 0xcb, 0x71, 0x61, }; - var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -620,11 +718,11 @@ public void AES_CBC_256_Length32() 0x6a, 0xfb, 0x4a, 0x8b, 0xc8, 0x25, 0x87, 0x5c, 0x9b, 0x47, 0xf5, 0x3f, 0x42, 0xf5, 0xc6, 0x08, }; - var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -658,11 +756,11 @@ public void AES_CBC_256_Length64() 0x08, 0x19, 0x66, 0x47, 0xe7, 0xd9, 0x1d, 0x1c, 0x42, 0xdc, 0x97, 0x9c, 0xf0, 0x9a, 0x14, 0x34, }; - var actual = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CbcCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CBC, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -689,11 +787,11 @@ public void AES_CFB_128_Length16() 0x76, 0xd2, 0x2b, 0x69, 0xa6, 0xdf, 0x3b, 0x4d, 0x4a, 0x52, 0x8a, 0x7a, 0x54, 0x9d, 0xbe, 0x55, }; - var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -722,11 +820,11 @@ public void AES_CFB_128_Length32() 0x18, 0xc5, 0xf7, 0x41, 0x78, 0x5f, 0x38, 0x6b, 0x4d, 0x04, 0x00, 0x3b, 0x61, 0x8c, 0xaf, 0xe7, }; - var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -759,11 +857,11 @@ public void AES_CFB_128_Length64() 0xf7, 0x49, 0xbc, 0xbf, 0xcb, 0x5c, 0xfa, 0x12, 0xcb, 0xcc, 0x38, 0x71, 0x68, 0xd6, 0xe9, 0x64, }; - var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -791,11 +889,11 @@ public void AES_CFB_192_Length16() 0x4f, 0x9b, 0xdf, 0x72, 0x2d, 0x10, 0x1b, 0xb9, 0xa1, 0xe1, 0x06, 0xba, 0xbc, 0xc5, 0xfe, 0x13, }; - var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -825,11 +923,11 @@ public void AES_CFB_192_Length32() 0x72, 0xcf, 0x57, 0x7f, 0xf9, 0x5d, 0xfe, 0xb1, 0x36, 0x9a, 0x1d, 0x02, 0x0d, 0x4b, 0x8f, 0x35, }; - var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -863,11 +961,11 @@ public void AES_CFB_192_Length64() 0x69, 0x90, 0x2a, 0xf9, 0xf4, 0xe8, 0xcc, 0xa5, 0x2b, 0xdd, 0x9c, 0xbc, 0x44, 0xcd, 0x1e, 0x5b, }; - var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -895,11 +993,11 @@ public void AES_CFB_256_Length16() 0xf0, 0xfa, 0x95, 0x5c, 0xfc, 0x3f, 0xbe, 0xe5, 0x4b, 0x55, 0x57, 0xad, 0x93, 0x63, 0x36, 0x07, }; - var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -929,11 +1027,11 @@ public void AES_CFB_256_Length32() 0xc2, 0xc1, 0x54, 0x9c, 0xfd, 0xf9, 0x43, 0xd0, 0xdc, 0xa7, 0x20, 0x68, 0x3e, 0xc3, 0x8f, 0x3c, }; - var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -967,11 +1065,11 @@ public void AES_CFB_256_Length64() 0xf6, 0xd4, 0x06, 0xef, 0x04, 0xf1, 0xe5, 0x53, 0x54, 0xd5, 0x80, 0xc2, 0x96, 0x6b, 0xc7, 0x07, }; - var actual = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -998,11 +1096,11 @@ public void AES_CTR_128_Length16() 0xe4, 0x03, 0x8f, 0x2a, 0xdd, 0x9d, 0xf6, 0x87, 0xf6, 0x29, 0xee, 0x27, 0x4c, 0xf3, 0xba, 0x82, }; - var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1031,11 +1129,11 @@ public void AES_CTR_128_Length32() 0x9c, 0xb2, 0x30, 0x94, 0xdc, 0x88, 0xfa, 0x39, 0x05, 0x0c, 0x26, 0x25, 0x28, 0x6a, 0x9b, 0x4e, }; - var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1068,11 +1166,11 @@ public void AES_CTR_128_Length64() 0xec, 0x47, 0x81, 0x82, 0x89, 0x24, 0x76, 0xe2, 0x20, 0x6a, 0x99, 0xe2, 0xa7, 0x5a, 0xb0, 0x40, }; - var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1100,11 +1198,11 @@ public void AES_CTR_192_Length16() 0xc4, 0x4e, 0x81, 0x32, 0xe6, 0x6d, 0x0a, 0x78, 0x49, 0xe5, 0x64, 0x6c, 0xe6, 0xc2, 0x91, 0xc9, }; - var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1134,11 +1232,11 @@ public void AES_CTR_192_Length32() 0x85, 0xcd, 0x88, 0xa8, 0x25, 0xc8, 0xbd, 0xf8, 0xc3, 0xa9, 0x74, 0x36, 0x82, 0x19, 0xfc, 0xb3, }; - var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1172,11 +1270,11 @@ public void AES_CTR_192_Length64() 0x2d, 0x26, 0x4a, 0x22, 0x97, 0x7a, 0x94, 0x5e, 0xb0, 0xb2, 0x3d, 0x42, 0x2b, 0x4a, 0x5e, 0x5d, }; - var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1204,11 +1302,11 @@ public void AES_CTR_256_Length16() 0xa6, 0x46, 0x19, 0x9d, 0x3e, 0xa5, 0x53, 0xc8, 0xd9, 0xb3, 0x46, 0xbc, 0x0b, 0x3e, 0x47, 0xf4, }; - var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1238,11 +1336,11 @@ public void AES_CTR_256_Length32() 0x1d, 0x7e, 0xe7, 0xe7, 0xa0, 0xae, 0x31, 0x9b, 0xb3, 0x21, 0xb8, 0x0c, 0x47, 0x3e, 0xaf, 0xdd, }; - var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1276,11 +1374,11 @@ public void AES_CTR_256_Length64() 0x92, 0xb0, 0x7b, 0x7a, 0x77, 0x65, 0xf0, 0xcc, 0xbd, 0xe4, 0x41, 0xea, 0x9e, 0xfd, 0xdf, 0x41, }; - var actual = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new CtrCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.CTR, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1307,11 +1405,11 @@ public void AES_OFB_128_Length16() 0xb0, 0x65, 0x77, 0x03, 0xb4, 0x54, 0x82, 0x92, 0x05, 0x82, 0x93, 0x1f, 0x8d, 0x7b, 0xb6, 0xf0, }; - var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1340,11 +1438,11 @@ public void AES_OFB_128_Length32() 0x11, 0xb9, 0xd6, 0x67, 0x6c, 0xe7, 0xaa, 0x09, 0x93, 0xe3, 0x5f, 0xed, 0x38, 0x46, 0x37, 0xd2, }; - var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1377,11 +1475,11 @@ public void AES_OFB_128_Length64() 0xda, 0xad, 0x1b, 0xa5, 0x20, 0x67, 0xd2, 0xa6, 0x18, 0x26, 0x30, 0x43, 0x2f, 0xa2, 0x66, 0x0b, }; - var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1409,11 +1507,11 @@ public void AES_OFB_192_Length16() 0x79, 0x41, 0x28, 0xc9, 0x3b, 0x89, 0x6f, 0x69, 0x92, 0xb0, 0x3e, 0x38, 0x11, 0x2c, 0xe5, 0xd8, }; - var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1443,11 +1541,11 @@ public void AES_OFB_192_Length32() 0xe8, 0xe8, 0x8e, 0x1a, 0xa6, 0x25, 0xa5, 0x65, 0x0d, 0x5a, 0xe2, 0x9c, 0xd2, 0x7e, 0x06, 0x14, }; - var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1481,11 +1579,11 @@ public void AES_OFB_192_Length64() 0xc7, 0xd0, 0x21, 0x0a, 0x40, 0x1d, 0x32, 0x32, 0x88, 0x86, 0x40, 0xa9, 0x4c, 0x59, 0x9c, 0xb4, }; - var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1513,11 +1611,11 @@ public void AES_OFB_256_Length16() 0x98, 0x85, 0x21, 0xeb, 0x42, 0x0c, 0x8b, 0xb3, 0xab, 0x64, 0x78, 0xe5, 0x67, 0xdd, 0xee, 0x36, }; - var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1547,11 +1645,11 @@ public void AES_OFB_256_Length32() 0x39, 0x54, 0x2e, 0x9f, 0x81, 0x49, 0xd3, 0x6b, 0x58, 0x20, 0x03, 0x21, 0x8d, 0x41, 0x9a, 0x42, }; - var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } @@ -1585,13 +1683,14 @@ public void AES_OFB_256_Length64() 0x7a, 0x3a, 0x43, 0xa6, 0x8f, 0x48, 0xfe, 0x6e, 0x64, 0xf6, 0x01, 0x0d, 0xdf, 0x9d, 0x34, 0xee, }; - var actual = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Encrypt(input); + var actual = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Encrypt(input); CollectionAssert.AreEqual(expected, actual); - var decrypted = new AesCipher(key, new OfbCipherMode((byte[])iv.Clone()), padding: null).Decrypt(actual); + var decrypted = new AesCipher(key, (byte[])iv.Clone(), AesCipherMode.OFB, pkcs7Padding: false).Decrypt(actual); CollectionAssert.AreEqual(input, decrypted); } + } } From 5921b6eca396ba04159d90507b25dd56e957f2b3 Mon Sep 17 00:00:00 2001 From: Gert Driesen Date: Thu, 30 Nov 2023 07:40:13 +0100 Subject: [PATCH 76/96] Disable a few duplicate analyzer rules. (#1254) --- .editorconfig | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/.editorconfig b/.editorconfig index 86ba08e01..3fbc77faf 100644 --- a/.editorconfig +++ b/.editorconfig @@ -65,6 +65,12 @@ dotnet_diagnostic.S1135.severity = none # We sometimes return null to avoid allocating an empty List. dotnet_diagnostic.S1168.severity = none +# S1144: Unused private types or members should be removed +# https://rules.sonarsource.com/csharp/RSPEC-1144 +# +# This is a duplicate of IDE0051. +dotnet_diagnostic.S1144.severity = none + # S1172: Unused method parameters should be removed # https://rules.sonarsource.com/csharp/RSPEC-1172 # @@ -89,6 +95,12 @@ dotnet_diagnostic.S1854.severity = none # The analysis is not precise enough, leading to false positives. dotnet_diagnostic.S2259.severity = none +# S2292: Trivial properties should be auto-implemented +# https://rules.sonarsource.com/csharp/RSPEC-2292 +# +# This is a duplicate of IDE0032. +dotnet_diagnostic.S2292.severity = none + # S2445: Blocks should be synchronized on read-only fields # https://rules.sonarsource.com/csharp/RSPEC-2445 # @@ -150,12 +162,30 @@ dotnet_diagnostic.S3267.severity = none # consider enabling S3376 in favor of MA0058. dotnet_diagnostic.S3376.severity = none +# S3442: "abstract" classes should not have "public" constructors +# https://rules.sonarsource.com/csharp/RSPEC-3442 +# +# This is a duplicate of MA0017. +dotnet_diagnostic.S3442.severity = none + +# S3450: Parameters with "[DefaultParameterValue]" attributes should also be marked "[Optional]" +# https://rules.sonarsource.com/csharp/RSPEC-3450 +# +# This is a duplicate of MA0087. +dotnet_diagnostic.S3450.severity = none + # S3871: Exception types should be "public" # https://rules.sonarsource.com/csharp/RSPEC-3871 # # This is a duplicate of CA1064. dotnet_diagnostic.S3871.severity = none +# S3903: Types should be defined in named namespaces +# https://rules.sonarsource.com/csharp/RSPEC-3903 +# +# This is a duplicate of MA0047. +dotnet_diagnostic.S3903.severity = none + # S3925: "ISerializable" should be implemented correctly # https://rules.sonarsource.com/csharp/RSPEC-3925 # From d3641a06769a3393b47ae79ff9aa6f73637ae77b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Thu, 30 Nov 2023 19:19:00 +0100 Subject: [PATCH 77/96] Test integration tests (#1250) * Test integration tests * Update appveyor.yml * Update appveyor.yml * Update Dockerfile * Update appveyor.yml * test? * Test * Enable docker * Update appveyor.yml * Update appveyor.yml * Fix & Show additional information * Try to fix connection problems * Fix build * remove artifacts * Enable logging * Log Information only * Update appveyor.yml Co-authored-by: Rob Hague * Update appveyor.yml * Update appveyor.yml Co-authored-by: Rob Hague * Update appveyor.yml Co-authored-by: Rob Hague * Update appveyor.yml * Update appveyor.yml * Update appveyor.yml * Update appveyor.yml * Update appveyor.yml * Update appveyor.yml * Update appveyor.yml * Update appveyor.yml * Update appveyor.yml * sleep after restarting * Update RemoteSshd.cs * Fix tests * Dispose ports * Small improvements * Fix build * Small fixes * Revert not related changes * Test linux and windows * fix * test_script * Use real commands * Fixes * fix? * Add Appveyor TestLogger * Fix linux tests * Fix tests * Try to fix tests * Revert * Give time before * fix * revert * Give some time to process all messages after connect * ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound * fix netsh * trace * Update appveyor.yml * Update appveyor.yml * etl2pcapng * Update appveyor.yml ??? * Update appveyor.yml * Update appveyor.yml * Update appveyor.yml * Update appveyor.yml * come on !! * Update appveyor.yml * Fixes tests for linux * Reverts * Fix build * Update TestMethodForPlatformAttribute.cs * Update TestMethodForPlatformAttribute.cs * Update appveyor.yml * Issue #1253 * Install .NET SDK * next try * fix? * try * Finishing * Fixes * apt-get install dotnet-sdk-7.0 * Finish? * Add environment APPVEYOR_BAKE_IMAGE * Update test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs Co-authored-by: Rob Hague * Fix review * Fix * Update appveyor.yml * Update appveyor.yml * Delete .runsettings --------- Co-authored-by: Rob Hague Co-authored-by: Robert Hague Co-authored-by: Scott Xu --- appveyor.yml | 68 +++++++++++++++---- global.json | 2 +- .../Abstractions/DiagnosticAbstraction.cs | 9 +-- .../Properties/CommonAssemblyInfo.cs | 6 +- .../{Dockerfile => Dockerfile.TestServer} | 0 .../ForwardedPortLocalTest.cs | 6 +- .../SftpClientTest.Upload.cs | 10 ++- .../RemoteSshd.cs | 8 +++ .../Renci.SshNet.IntegrationTests.csproj | 23 ++++--- .../Renci.SshNet.IntegrationTests/SshTests.cs | 8 +-- .../TestsFixtures/InfrastructureFixture.cs | 21 +++--- .../TestsFixtures/IntegrationTestBase.cs | 19 +++++- .../Classes/Common/SemaphoreLightTest.cs | 2 +- .../Connection/DirectConnectorTestBase.cs | 2 +- ...rTest_Connect_TimeoutConnectingToServer.cs | 25 +++++-- ...orTest_Connect_TimeoutConnectingToProxy.cs | 25 +++++-- ...rTest_Connect_TimeoutReadingHttpContent.cs | 2 +- ...orTest_Connect_TimeoutReadingStatusLine.cs | 2 +- .../Connection/Socks4ConnectorTestBase.cs | 2 +- ...nnectorTest_Connect_ConnectionSucceeded.cs | 4 +- ...orTest_Connect_TimeoutConnectingToProxy.cs | 26 +++++-- .../Connection/Socks5ConnectorTestBase.cs | 2 +- ...ct_NoAuthentication_ConnectionSucceeded.cs | 4 +- ...orTest_Connect_TimeoutConnectingToProxy.cs | 25 +++++-- ...swordAuthentication_ConnectionSucceeded.cs | 4 +- ...est_Dispose_PortStarted_ChannelNotBound.cs | 7 +- ...icTest_Stop_PortStarted_ChannelNotBound.cs | 5 +- .../Classes/SftpClientTest.ConnectAsync.cs | 6 +- .../Common/TestMethodForPlatformAttribute.cs | 35 ++++++++++ .../Renci.SshNet.Tests.csproj | 14 +++- 30 files changed, 284 insertions(+), 88 deletions(-) rename test/Renci.SshNet.IntegrationTests/{Dockerfile => Dockerfile.TestServer} (100%) create mode 100644 test/Renci.SshNet.Tests/Common/TestMethodForPlatformAttribute.cs diff --git a/appveyor.yml b/appveyor.yml index 2aeeb4891..7793c15dc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,17 +1,59 @@ -os: Visual Studio 2022 +image: + - Ubuntu2204 + - Visual Studio 2022 -before_build: - - nuget restore Renci.SshNet.sln +services: + - docker -install: - - cinst dotnet-sdk --version=7.0.403 --limit-output +for: +- + matrix: + only: + - image: Ubuntu2204 -build: - project: Renci.SshNet.sln - verbosity: minimal - -test_script: -- cmd: >- - vstest.console /logger:Appveyor test\Renci.SshNet.Tests\bin\Debug\net462\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration" --blame + install: + - sh: sudo apt-get update && sudo apt-get install -y dotnet-sdk-7.0=7.0.403-1 - vstest.console /logger:Appveyor test\Renci.SshNet.Tests\bin\Debug\net7.0\Renci.SshNet.Tests.dll /TestCaseFilter:"TestCategory!=integration" --blame + before_build: + - sh: mkdir artifacts -p + + build_script: + - echo build + - dotnet build Renci.SshNet.sln -c Debug -f net7.0 + + test_script: + - sh: echo "Run unit tests" + - sh: dotnet test -f net7.0 -c Debug --no-restore --no-build --results-directory artifacts --logger Appveyor --logger "console;verbosity=normal" --logger "liquid.md;LogFileName=linux_unit_test_net_7_report.md" -p:CollectCoverage=true -p:CoverletOutputFormat=cobertura -p:CoverletOutput=../../artifacts/linux_unit_test_net_7_coverage.xml test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj + - sh: echo "Run integration tests" + - sh: dotnet test -c Debug --no-restore --no-build --results-directory artifacts --logger Appveyor --logger "console;verbosity=normal" --logger "liquid.md;LogFileName=linux_integration_test_net_7_report.md" -p:CollectCoverage=true -p:CoverletOutputFormat=cobertura -p:CoverletOutput=../../artifacts/linux_integration_test_net_7_coverage.xml test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj + +# on_failure: +# - sh: appveyor PushArtifact artifacts/tcpdump.pcap + +- + matrix: + only: + - image: Visual Studio 2022 + + install: + - ps: choco install dotnet-7.0-sdk --version=7.0.403 + + before_build: + - ps: mkdir artifacts -f + + build_script: + - echo build + - dotnet build Renci.SshNet.sln -c Debug + + test_script: + - ps: echo "Run unit tests for .NET 7.0" + - ps: dotnet test -f net7.0 -c Debug --no-restore --no-build --results-directory artifacts --logger Appveyor --logger "console;verbosity=normal" --logger "liquid.md;LogFileName=windows_unit_test_net_7_report.md" -p:CollectCoverage=true -p:CoverletOutputFormat=cobertura -p:CoverletOutput=../../artifacts/windows_unit_test_net_7_coverage.xml test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj + - ps: echo "Run unit tests for .NET Framework 4.6.2" + - ps: dotnet test -f net462 -c Debug --no-restore --no-build --results-directory artifacts --logger Appveyor --logger "console;verbosity=normal" --logger "liquid.md;LogFileName=windows_unit_test_net_4_6_2_report.md" -p:CollectCoverage=true -p:CoverletOutputFormat=cobertura -p:CoverletOutput=../../artifacts/windows_unit_test_net_4_6_2_coverage.xml test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj + +# on_failure: +# - ps: Push-AppveyorArtifact artifacts/tcpdump.pcap + +artifacts: + - path: artifacts + name: artifacts diff --git a/global.json b/global.json index 9d9cefcc5..44da40565 100644 --- a/global.json +++ b/global.json @@ -3,4 +3,4 @@ "version": "7.0.403", "rollForward": "latestMajor" } -} +} \ No newline at end of file diff --git a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs index 3d69bb4c2..bc1248dc0 100644 --- a/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/DiagnosticAbstraction.cs @@ -57,12 +57,13 @@ public static class DiagnosticAbstraction /// level. /// /// The message to log. + /// The trace event type. [Conditional("DEBUG")] - public static void Log(string text) + public static void Log(string text, TraceEventType type = TraceEventType.Verbose) { - Source.TraceEvent(TraceEventType.Verbose, - System.Environment.CurrentManagedThreadId, - text); + Source.TraceEvent(type, + System.Environment.CurrentManagedThreadId, + text); } } } diff --git a/src/Renci.SshNet/Properties/CommonAssemblyInfo.cs b/src/Renci.SshNet/Properties/CommonAssemblyInfo.cs index 7af4c6381..31ae72dff 100644 --- a/src/Renci.SshNet/Properties/CommonAssemblyInfo.cs +++ b/src/Renci.SshNet/Properties/CommonAssemblyInfo.cs @@ -9,9 +9,9 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] -[assembly: AssemblyVersion("2023.0.0")] -[assembly: AssemblyFileVersion("2023.0.0")] -[assembly: AssemblyInformationalVersion("2023.0.0")] +[assembly: AssemblyVersion("2023.0.1")] +[assembly: AssemblyFileVersion("2023.0.1")] +[assembly: AssemblyInformationalVersion("2023.0.1")] [assembly: CLSCompliant(false)] // Setting ComVisible to false makes the types in this assembly not visible diff --git a/test/Renci.SshNet.IntegrationTests/Dockerfile b/test/Renci.SshNet.IntegrationTests/Dockerfile.TestServer similarity index 100% rename from test/Renci.SshNet.IntegrationTests/Dockerfile rename to test/Renci.SshNet.IntegrationTests/Dockerfile.TestServer diff --git a/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs index bf6292faa..ec28a738e 100644 --- a/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs +++ b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/ForwardedPortLocalTest.cs @@ -3,7 +3,7 @@ using Renci.SshNet.Common; namespace Renci.SshNet.IntegrationTests.OldIntegrationTests -{ +{ /// /// Provides functionality for local port forwarding /// @@ -21,7 +21,7 @@ public void Test_PortForwarding_Local_Stop_Hangs_On_Wait() { client.Connect(); - var port1 = new ForwardedPortLocal("localhost", 8084, "www.google.com", 80); + using var port1 = new ForwardedPortLocal("localhost", 8085, "www.google.com", 80); client.AddForwardedPort(port1); port1.Exception += delegate (object sender, ExceptionEventArgs e) { @@ -102,7 +102,7 @@ public void Test_PortForwarding_Local_Without_Connecting() { using (var client = new SshClient(SshServerHostName, SshServerPort, User.UserName, User.Password)) { - var port1 = new ForwardedPortLocal("localhost", 8084, "www.renci.org", 80); + using var port1 = new ForwardedPortLocal("localhost", 8084, "www.renci.org", 80); client.AddForwardedPort(port1); port1.Exception += delegate (object sender, ExceptionEventArgs e) { diff --git a/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs index 91c248bd3..b4b620e77 100644 --- a/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs +++ b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs @@ -230,7 +230,15 @@ public void Test_Sftp_Multiple_Async_Upload_And_Download_10Files_5MB_Each() sftp.Disconnect(); Assert.IsTrue(hashMatches, "Hash does not match"); - Assert.IsTrue(uploadDownloadSizeOk, "Uploaded and downloaded bytes does not match"); + if (!uploadDownloadSizeOk) + { + // TODO https://github.com/sshnet/SSH.NET/issues/1253 + Assert.Inconclusive("Uploaded and downloaded bytes should match, but test is not stable"); + } + else + { + Assert.IsTrue(uploadDownloadSizeOk, "Uploaded and downloaded bytes does not match"); + } } } diff --git a/test/Renci.SshNet.IntegrationTests/RemoteSshd.cs b/test/Renci.SshNet.IntegrationTests/RemoteSshd.cs index 14614b406..476671f1a 100644 --- a/test/Renci.SshNet.IntegrationTests/RemoteSshd.cs +++ b/test/Renci.SshNet.IntegrationTests/RemoteSshd.cs @@ -37,6 +37,14 @@ public RemoteSshd Restart() } } + // Socket fails on Linux, reporting inability early. This is the Linux behavior by design. + // https://github.com/dotnet/runtime/issues/47484#issuecomment-769239699 + // At this point we have to wait until the ssh server in the container is available after reconfiguration. + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + Thread.Sleep(300); + } + return this; } } diff --git a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj index 19e104b31..6abe36e6a 100644 --- a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj +++ b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj @@ -9,23 +9,30 @@ - + - + - + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + - runtime; build; native; contentfiles; analyzers; buildtransitive - all + build; native; contentfiles; analyzers; buildtransitive + all diff --git a/test/Renci.SshNet.IntegrationTests/SshTests.cs b/test/Renci.SshNet.IntegrationTests/SshTests.cs index 3bc09f4f2..6c1ddfb0f 100644 --- a/test/Renci.SshNet.IntegrationTests/SshTests.cs +++ b/test/Renci.SshNet.IntegrationTests/SshTests.cs @@ -616,8 +616,8 @@ public void Ssh_RemotePortForwarding() var hostAddresses = Dns.GetHostAddresses(Dns.GetHostName()); var ipv4HostAddress = hostAddresses.First(p => p.AddressFamily == AddressFamily.InterNetwork); - var endpoint1 = new IPEndPoint(ipv4HostAddress, 666); - var endpoint2 = new IPEndPoint(ipv4HostAddress, 667); + var endpoint1 = new IPEndPoint(ipv4HostAddress, 10000); + var endpoint2 = new IPEndPoint(ipv4HostAddress, 10001); var bytesReceivedOnListener1 = new List(); var bytesReceivedOnListener2 = new List(); @@ -635,7 +635,7 @@ public void Ssh_RemotePortForwarding() client.Connect(); var forwardedPort1 = new ForwardedPortRemote(IPAddress.Loopback, - 10000, + 10002, endpoint1.Address, (uint)endpoint1.Port); forwardedPort1.Exception += (sender, args) => Console.WriteLine(@"forwardedPort1 exception: " + args.Exception); @@ -643,7 +643,7 @@ public void Ssh_RemotePortForwarding() forwardedPort1.Start(); var forwardedPort2 = new ForwardedPortRemote(IPAddress.Loopback, - 10001, + 10003, endpoint2.Address, (uint)endpoint2.Port); forwardedPort2.Exception += (sender, args) => Console.WriteLine(@"forwardedPort2 exception: " + args.Exception); diff --git a/test/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs b/test/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs index f01df813d..3482f9692 100644 --- a/test/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs +++ b/test/Renci.SshNet.IntegrationTests/TestsFixtures/InfrastructureFixture.cs @@ -1,11 +1,7 @@ -锘縰sing System.Diagnostics; - -using DotNet.Testcontainers.Builders; +锘縰sing DotNet.Testcontainers.Builders; using DotNet.Testcontainers.Containers; using DotNet.Testcontainers.Images; -using Renci.SshNet.Abstractions; - namespace Renci.SshNet.IntegrationTests.TestsFixtures { public sealed class InfrastructureFixture : IDisposable @@ -38,16 +34,11 @@ public static InfrastructureFixture Instance public async Task InitializeAsync() { - DiagnosticAbstraction.Source.Switch = new SourceSwitch("sourceSwitch", "Verbose"); - DiagnosticAbstraction.Source.Listeners.Remove("Default"); - DiagnosticAbstraction.Source.Listeners.Add(new ConsoleTraceListener()); - _sshServerImage = new ImageFromDockerfileBuilder() .WithName("renci-ssh-tests-server-image") .WithDockerfileDirectory(CommonDirectoryPath.GetSolutionDirectory(), Path.Combine("test", "Renci.SshNet.IntegrationTests")) - .WithDockerfile("Dockerfile") + .WithDockerfile("Dockerfile.TestServer") .WithDeleteIfExists(true) - .Build(); await _sshServerImage.CreateAsync(); @@ -62,6 +53,14 @@ public async Task InitializeAsync() SshServerPort = _sshServer.GetMappedPublicPort(22); SshServerHostName = _sshServer.Hostname; + + // Socket fails on Linux, reporting inability early. This is the Linux behavior by design. + // https://github.com/dotnet/runtime/issues/47484#issuecomment-769239699 + // At this point we have to wait until the ssh server in the container is available + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + await Task.Delay(300); + } } public async Task DisposeAsync() diff --git a/test/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs b/test/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs index 1d6658fc2..d08578e4e 100644 --- a/test/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs +++ b/test/Renci.SshNet.IntegrationTests/TestsFixtures/IntegrationTestBase.cs @@ -1,4 +1,8 @@ -锘縩amespace Renci.SshNet.IntegrationTests.TestsFixtures +锘縰sing System.Diagnostics; + +using Renci.SshNet.Abstractions; + +namespace Renci.SshNet.IntegrationTests.TestsFixtures { /// /// The base class for integration tests @@ -81,5 +85,18 @@ protected void CreateTestFile(string fileName, int size) } } } + + protected void EnableTracing() + { + DiagnosticAbstraction.Source.Switch = new SourceSwitch("sourceSwitch", nameof(SourceLevels.Verbose)); + DiagnosticAbstraction.Source.Listeners.Remove("Default"); + DiagnosticAbstraction.Source.Listeners.Add(new ConsoleTraceListener() { Name = "TestConsoleLogger" }); + } + + protected void DisableTracing() + { + DiagnosticAbstraction.Source.Switch = new SourceSwitch("sourceSwitch", nameof(SourceLevels.Off)); + DiagnosticAbstraction.Source.Listeners.Remove("TestConsoleLogger"); + } } } diff --git a/test/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs index 17d5e72f2..5b4aa43b9 100644 --- a/test/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs @@ -78,7 +78,7 @@ public void WaitTest() watch.Stop(); - Assert.IsTrue(watch.ElapsedMilliseconds > 200); + Assert.IsTrue(watch.ElapsedMilliseconds >= 200); Assert.IsTrue(watch.ElapsedMilliseconds < 250); } diff --git a/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs b/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs index d1989c3de..7eb9040e9 100644 --- a/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs +++ b/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTestBase.cs @@ -36,7 +36,7 @@ protected sealed override void Arrange() protected ConnectionInfo CreateConnectionInfo(string hostName) { return new ConnectionInfo(hostName, - 777, + 1027, "user", new KeyboardInteractiveAuthenticationMethod("user")); } diff --git a/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs b/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs index 661b286ae..0aa4a9b8a 100644 --- a/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs +++ b/test/Renci.SshNet.Tests/Classes/Connection/DirectConnectorTest_Connect_TimeoutConnectingToServer.cs @@ -3,12 +3,14 @@ using System.Globalization; using System.Net; using System.Net.Sockets; +using System.Runtime.InteropServices; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Connection { @@ -16,7 +18,7 @@ namespace Renci.SshNet.Tests.Classes.Connection public class DirectConnectorTest_Connect_TimeoutConnectingToServer : DirectConnectorTestBase { private ConnectionInfo _connectionInfo; - private SshOperationTimeoutException _actualException; + private Exception _actualException; private Socket _clientSocket; private Stopwatch _stopWatch; @@ -60,21 +62,34 @@ protected override void Act() { _actualException = ex; } + catch (SocketException ex) + { + _actualException = ex; + } finally { _stopWatch.Stop(); } } - [TestMethod] - public void ConnectShouldHaveThrownSshOperationTimeoutException() + [TestMethodForPlatform(nameof(OSPlatform.Windows))] + public void ConnectShouldHaveThrownSshOperationTimeoutExceptionOnWindows() { Assert.IsNull(_actualException.InnerException); + Assert.IsInstanceOfType(_actualException); Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Connection failed to establish within {0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message); } - [TestMethod] - public void ConnectShouldHaveRespectedTimeout() + [TestMethodForPlatform(nameof(OSPlatform.Linux))] + public void ConnectShouldHaveThrownSocketExceptionOnLinux() + { + Assert.IsNull(_actualException.InnerException); + Assert.IsInstanceOfType(_actualException); + Assert.AreEqual("Connection refused", _actualException.Message); + } + + [TestMethodForPlatform(nameof(OSPlatform.Windows))] + public void ConnectShouldHaveRespectedTimeoutOnWindows() { var errorText = string.Format("Elapsed: {0}, Timeout: {1}", _stopWatch.ElapsedMilliseconds, diff --git a/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs index bb8041c89..de3332908 100644 --- a/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs +++ b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutConnectingToProxy.cs @@ -3,12 +3,14 @@ using System.Globalization; using System.Net; using System.Net.Sockets; +using System.Runtime.InteropServices; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Connection { @@ -16,7 +18,7 @@ namespace Renci.SshNet.Tests.Classes.Connection public class HttpConnectorTest_Connect_TimeoutConnectingToProxy : HttpConnectorTestBase { private ConnectionInfo _connectionInfo; - private SshOperationTimeoutException _actualException; + private Exception _actualException; private Socket _clientSocket; private Stopwatch _stopWatch; @@ -70,21 +72,34 @@ protected override void Act() { _actualException = ex; } + catch (SocketException ex) + { + _actualException = ex; + } finally { _stopWatch.Stop(); } } - [TestMethod] - public void ConnectShouldHaveThrownSshOperationTimeoutException() + [TestMethodForPlatform(nameof(OSPlatform.Windows))] + public void ConnectShouldHaveThrownSshOperationTimeoutExceptionOnWindows() { Assert.IsNull(_actualException.InnerException); + Assert.IsInstanceOfType(_actualException); Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Connection failed to establish within {0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message); } - [TestMethod] - public void ConnectShouldHaveRespectedTimeout() + [TestMethodForPlatform(nameof(OSPlatform.Linux))] + public void ConnectShouldHaveThrownSshOperationTimeoutExceptionOnLinux() + { + Assert.IsNull(_actualException.InnerException); + Assert.IsInstanceOfType(_actualException); + Assert.AreEqual("Connection refused", _actualException.Message); + } + + [TestMethodForPlatform(nameof(OSPlatform.Windows))] + public void ConnectShouldHaveRespectedTimeoutOnWindows() { var errorText = string.Format("Elapsed: {0}, Timeout: {1}", _stopWatch.ElapsedMilliseconds, diff --git a/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs index 98ffde6aa..6808bfb50 100644 --- a/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs +++ b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingHttpContent.cs @@ -36,7 +36,7 @@ protected override void SetupData() var random = new Random(); _connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(), - 777, + 1026, "user", ProxyTypes.Http, IPAddress.Loopback.ToString(), diff --git a/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs index bec205f1a..38f65634c 100644 --- a/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs +++ b/test/Renci.SshNet.Tests/Classes/Connection/HttpConnectorTest_Connect_TimeoutReadingStatusLine.cs @@ -32,7 +32,7 @@ protected override void SetupData() var random = new Random(); _connectionInfo = new ConnectionInfo(IPAddress.Loopback.ToString(), - 777, + 1028, "user", ProxyTypes.Http, IPAddress.Loopback.ToString(), diff --git a/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs index 0c3497f12..91891252b 100644 --- a/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs +++ b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTestBase.cs @@ -38,7 +38,7 @@ protected sealed override void Arrange() protected ConnectionInfo CreateConnectionInfo(string proxyUser, string proxyPassword) { return new ConnectionInfo(IPAddress.Loopback.ToString(), - 777, + 1030, "user", ProxyTypes.Socks4, IPAddress.Loopback.ToString(), diff --git a/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs index 5aabb8164..ced5855cb 100644 --- a/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs +++ b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_ConnectionSucceeded.cs @@ -103,8 +103,8 @@ public void ProxyShouldHaveReceivedExpectedSocksRequest() // CONNECT request 0x01, // Destination port - 0x03, - 0x09, + 0x04, + 0x06, // Destination address (IPv4) 0x7f, 0x00, diff --git a/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs index d7ad42157..f8793bd68 100644 --- a/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs +++ b/test/Renci.SshNet.Tests/Classes/Connection/Socks4ConnectorTest_Connect_TimeoutConnectingToProxy.cs @@ -5,6 +5,9 @@ using System.Diagnostics; using System.Globalization; using System.Net.Sockets; +using System.Runtime.InteropServices; + +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Connection { @@ -12,7 +15,7 @@ namespace Renci.SshNet.Tests.Classes.Connection public class Socks4ConnectorTest_Connect_TimeoutConnectingToProxy : Socks4ConnectorTestBase { private ConnectionInfo _connectionInfo; - private SshOperationTimeoutException _actualException; + private Exception _actualException; private Socket _clientSocket; private Stopwatch _stopWatch; @@ -55,21 +58,34 @@ protected override void Act() { _actualException = ex; } + catch (SocketException ex) + { + _actualException = ex; + } finally { _stopWatch.Stop(); } } - [TestMethod] - public void ConnectShouldHaveThrownSshOperationTimeoutException() + [TestMethodForPlatform(nameof(OSPlatform.Windows))] + public void ConnectShouldHaveThrownSshOperationTimeoutExceptionOnWindows() { Assert.IsNull(_actualException.InnerException); + Assert.IsInstanceOfType(_actualException); Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Connection failed to establish within {0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message); } - [TestMethod] - public void ConnectShouldHaveRespectedTimeout() + [TestMethodForPlatform(nameof(OSPlatform.Linux))] + public void ConnectShouldHaveThrownSshOperationTimeoutExceptionOnLinux() + { + Assert.IsNull(_actualException.InnerException); + Assert.IsInstanceOfType(_actualException); + Assert.AreEqual("Connection refused", _actualException.Message); + } + + [TestMethodForPlatform(nameof(OSPlatform.Windows))] + public void ConnectShouldHaveRespectedTimeoutOnWindows() { var errorText = string.Format("Elapsed: {0}, Timeout: {1}", _stopWatch.ElapsedMilliseconds, diff --git a/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs index fefe5728e..8ce9537cf 100644 --- a/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs +++ b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTestBase.cs @@ -40,7 +40,7 @@ protected sealed override void Arrange() protected ConnectionInfo CreateConnectionInfo(string proxyUser, string proxyPassword) { return new ConnectionInfo(IPAddress.Loopback.ToString(), - 777, + 1029, "user", ProxyTypes.Socks5, IPAddress.Loopback.ToString(), diff --git a/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs index e51548840..65ec1a20b 100644 --- a/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs +++ b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_NoAuthentication_ConnectionSucceeded.cs @@ -174,8 +174,8 @@ public void ProxyShouldHaveReceivedExpectedSocksRequest() 0x00, 0x01, // Destination port - 0x03, - 0x09 + 0x04, + 0x05 }; diff --git a/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs index 720c24ff9..964e36960 100644 --- a/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs +++ b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_TimeoutConnectingToProxy.cs @@ -2,12 +2,14 @@ using System.Diagnostics; using System.Globalization; using System.Net.Sockets; +using System.Runtime.InteropServices; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes.Connection { @@ -15,7 +17,7 @@ namespace Renci.SshNet.Tests.Classes.Connection public class Socks5ConnectorTest_Connect_TimeoutConnectingToProxy : Socks5ConnectorTestBase { private ConnectionInfo _connectionInfo; - private SshOperationTimeoutException _actualException; + private Exception _actualException; private Socket _clientSocket; private Stopwatch _stopWatch; @@ -59,21 +61,34 @@ protected override void Act() { _actualException = ex; } + catch (SocketException ex) + { + _actualException = ex; + } finally { _stopWatch.Stop(); } } - [TestMethod] - public void ConnectShouldHaveThrownSshOperationTimeoutException() + [TestMethodForPlatform(nameof(OSPlatform.Windows))] + public void ConnectShouldHaveThrownSshOperationTimeoutExceptionOnWindows() { Assert.IsNull(_actualException.InnerException); + Assert.IsInstanceOfType(_actualException); Assert.AreEqual(string.Format(CultureInfo.InvariantCulture, "Connection failed to establish within {0} milliseconds.", _connectionInfo.Timeout.TotalMilliseconds), _actualException.Message); } - [TestMethod] - public void ConnectShouldHaveRespectedTimeout() + [TestMethodForPlatform(nameof(OSPlatform.Linux))] + public void ConnectShouldHaveThrownSshOperationTimeoutExceptionOnLinux() + { + Assert.IsNull(_actualException.InnerException); + Assert.IsInstanceOfType(_actualException); + Assert.AreEqual("Connection refused", _actualException.Message); + } + + [TestMethodForPlatform(nameof(OSPlatform.Windows))] + public void ConnectShouldHaveRespectedTimeoutOnWindows() { var errorText = string.Format("Elapsed: {0}, Timeout: {1}", _stopWatch.ElapsedMilliseconds, diff --git a/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs index 0c13af50d..3c69ac5c4 100644 --- a/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs +++ b/test/Renci.SshNet.Tests/Classes/Connection/Socks5ConnectorTest_Connect_UserNamePasswordAuthentication_ConnectionSucceeded.cs @@ -193,8 +193,8 @@ public void ProxyShouldHaveReceivedExpectedSocksRequest() expectedSocksRequest.Add(0x00); expectedSocksRequest.Add(0x01); // Destination port - expectedSocksRequest.Add(0x03); - expectedSocksRequest.Add(0x09); + expectedSocksRequest.Add(0x04); + expectedSocksRequest.Add(0x05); var errorText = string.Format("Expected:{0}{1}{0}but was:{0}{2}", Environment.NewLine, diff --git a/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs index aa9957389..b3e325535 100644 --- a/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs +++ b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Dispose_PortStarted_ChannelNotBound.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Runtime.InteropServices; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -10,6 +11,7 @@ using Renci.SshNet.Channels; using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes { @@ -83,7 +85,7 @@ protected void Arrange() protected void Act() { - _forwardedPort.Stop(); + _forwardedPort.Dispose(); } [TestMethod] @@ -109,7 +111,8 @@ public void ForwardedPortShouldRefuseNewConnections() } } - [TestMethod] + // TODO We should investigate why this method doesn't work on Linux + [TestMethodForPlatform(nameof(OSPlatform.Windows))] public void ExistingConnectionShouldBeClosed() { try diff --git a/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs index 34db4f9dd..b0059f453 100644 --- a/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs +++ b/test/Renci.SshNet.Tests/Classes/ForwardedPortDynamicTest_Stop_PortStarted_ChannelNotBound.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Runtime.InteropServices; using System.Threading; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -10,6 +11,7 @@ using Renci.SshNet.Channels; using Renci.SshNet.Common; +using Renci.SshNet.Tests.Common; namespace Renci.SshNet.Tests.Classes { @@ -113,7 +115,8 @@ public void ForwardedPortShouldRefuseNewConnections() } } - [TestMethod] + // TODO We should investigate why this method doesn't work on Linux + [TestMethodForPlatform(nameof(OSPlatform.Windows))] public void ExistingConnectionShouldBeClosed() { try diff --git a/test/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs b/test/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs index df7a8f0b6..88ab436db 100644 --- a/test/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs +++ b/test/Renci.SshNet.Tests/Classes/SftpClientTest.ConnectAsync.cs @@ -21,7 +21,7 @@ public async Task ConnectAsync_HostNameInvalid_ShouldThrowSocketExceptionWithErr } catch (SocketException ex) { - Assert.AreEqual(SocketError.HostNotFound, ex.SocketErrorCode); + Assert.IsTrue(ex.SocketErrorCode is SocketError.HostNotFound or SocketError.TryAgain, $"Socket error is {ex.SocketErrorCode}"); } } @@ -39,8 +39,8 @@ public async Task ConnectAsync_ProxyHostNameInvalid_ShouldThrowSocketExceptionWi } catch (SocketException ex) { - Assert.AreEqual(SocketError.HostNotFound, ex.SocketErrorCode); + Assert.IsTrue(ex.SocketErrorCode is SocketError.HostNotFound or SocketError.TryAgain, $"Socket error is {ex.SocketErrorCode}"); } } } -} \ No newline at end of file +} diff --git a/test/Renci.SshNet.Tests/Common/TestMethodForPlatformAttribute.cs b/test/Renci.SshNet.Tests/Common/TestMethodForPlatformAttribute.cs new file mode 100644 index 000000000..fcfaf7375 --- /dev/null +++ b/test/Renci.SshNet.Tests/Common/TestMethodForPlatformAttribute.cs @@ -0,0 +1,35 @@ +锘縰sing System.Runtime.InteropServices; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Renci.SshNet.Tests.Common +{ + public sealed class TestMethodForPlatformAttribute : TestMethodAttribute + { + public TestMethodForPlatformAttribute(string platform) + { + Platform = platform; + } + + public string Platform { get; } + + public override TestResult[] Execute(ITestMethod testMethod) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Create(Platform))) + { + return base.Execute(testMethod); + } + + var message = $"Test not executed. The test is intended for the '{Platform}' platform only."; + return new[] + { + new TestResult + { + Outcome = UnitTestOutcome.Inconclusive, + TestFailureException = new AssertInconclusiveException(message) + } + }; + + } + } +} diff --git a/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index 085a17e75..19f08f14b 100644 --- a/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -8,10 +8,22 @@ - + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + build; native; contentfiles; analyzers; buildtransitive + all + + From 4c7bd35a71937087c1ef233d7a6d0952ad91d4ec Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Sat, 2 Dec 2023 05:56:48 +0800 Subject: [PATCH 78/96] Add support for .NET 8.0 (#1255) * Add support for .NET 8.0 * Fix CA1512: Use 'ArgumentOutOfRangeException.ThrowIfNegative' instead of explicitly throwing a new exception instance (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1512) * Use `ThrowIfGreaterThan` instead of `ThrowIfNegative`+calculation, to supply the correct parameter name. * .NET 8 is faster :-) * Use the explicit version, in case newer version SDK breaks our tests --- appveyor.yml | 14 +++++----- build/nuget/SSH.NET.nuspec | 5 +++- global.json | 4 +-- src/Renci.SshNet/Common/SshData.cs | 4 +++ src/Renci.SshNet/Renci.SshNet.csproj | 6 ++-- src/Renci.SshNet/Sftp/SftpFileStream.cs | 28 ++++++++++++++++--- .../Renci.SshNet.Benchmarks.csproj | 2 +- .../Renci.SshNet.IntegrationTests.csproj | 2 +- .../Renci.SshNet.TestTools.OpenSSH.csproj | 2 +- ...nected_KeepAliveInterval_NotNegativeOne.cs | 4 +-- .../Renci.SshNet.Tests.csproj | 2 +- 11 files changed, 50 insertions(+), 23 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 7793c15dc..56f84c117 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,20 +12,20 @@ for: - image: Ubuntu2204 install: - - sh: sudo apt-get update && sudo apt-get install -y dotnet-sdk-7.0=7.0.403-1 + - sh: sudo apt-get update && sudo apt-get install -y dotnet-sdk-8.0=8.0.100-1 before_build: - sh: mkdir artifacts -p build_script: - echo build - - dotnet build Renci.SshNet.sln -c Debug -f net7.0 + - dotnet build Renci.SshNet.sln -c Debug -f net8.0 test_script: - sh: echo "Run unit tests" - - sh: dotnet test -f net7.0 -c Debug --no-restore --no-build --results-directory artifacts --logger Appveyor --logger "console;verbosity=normal" --logger "liquid.md;LogFileName=linux_unit_test_net_7_report.md" -p:CollectCoverage=true -p:CoverletOutputFormat=cobertura -p:CoverletOutput=../../artifacts/linux_unit_test_net_7_coverage.xml test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj + - sh: dotnet test -f net8.0 -c Debug --no-restore --no-build --results-directory artifacts --logger Appveyor --logger "console;verbosity=normal" --logger "liquid.md;LogFileName=linux_unit_test_net_8_report.md" -p:CollectCoverage=true -p:CoverletOutputFormat=cobertura -p:CoverletOutput=../../artifacts/linux_unit_test_net_8_coverage.xml test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj - sh: echo "Run integration tests" - - sh: dotnet test -c Debug --no-restore --no-build --results-directory artifacts --logger Appveyor --logger "console;verbosity=normal" --logger "liquid.md;LogFileName=linux_integration_test_net_7_report.md" -p:CollectCoverage=true -p:CoverletOutputFormat=cobertura -p:CoverletOutput=../../artifacts/linux_integration_test_net_7_coverage.xml test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj + - sh: dotnet test -c Debug --no-restore --no-build --results-directory artifacts --logger Appveyor --logger "console;verbosity=normal" --logger "liquid.md;LogFileName=linux_integration_test_net_8_report.md" -p:CollectCoverage=true -p:CoverletOutputFormat=cobertura -p:CoverletOutput=../../artifacts/linux_integration_test_net_8_coverage.xml test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj # on_failure: # - sh: appveyor PushArtifact artifacts/tcpdump.pcap @@ -36,7 +36,7 @@ for: - image: Visual Studio 2022 install: - - ps: choco install dotnet-7.0-sdk --version=7.0.403 + - ps: choco install dotnet-8.0-sdk --version=8.0.100 before_build: - ps: mkdir artifacts -f @@ -46,8 +46,8 @@ for: - dotnet build Renci.SshNet.sln -c Debug test_script: - - ps: echo "Run unit tests for .NET 7.0" - - ps: dotnet test -f net7.0 -c Debug --no-restore --no-build --results-directory artifacts --logger Appveyor --logger "console;verbosity=normal" --logger "liquid.md;LogFileName=windows_unit_test_net_7_report.md" -p:CollectCoverage=true -p:CoverletOutputFormat=cobertura -p:CoverletOutput=../../artifacts/windows_unit_test_net_7_coverage.xml test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj + - ps: echo "Run unit tests for .NET 8.0" + - ps: dotnet test -f net8.0 -c Debug --no-restore --no-build --results-directory artifacts --logger Appveyor --logger "console;verbosity=normal" --logger "liquid.md;LogFileName=windows_unit_test_net_8_report.md" -p:CollectCoverage=true -p:CoverletOutputFormat=cobertura -p:CoverletOutput=../../artifacts/windows_unit_test_net_8_coverage.xml test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj - ps: echo "Run unit tests for .NET Framework 4.6.2" - ps: dotnet test -f net462 -c Debug --no-restore --no-build --results-directory artifacts --logger Appveyor --logger "console;verbosity=normal" --logger "liquid.md;LogFileName=windows_unit_test_net_4_6_2_report.md" -p:CollectCoverage=true -p:CoverletOutputFormat=cobertura -p:CoverletOutput=../../artifacts/windows_unit_test_net_4_6_2_coverage.xml test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj diff --git a/build/nuget/SSH.NET.nuspec b/build/nuget/SSH.NET.nuspec index 55ce42e28..fec2d2fcf 100644 --- a/build/nuget/SSH.NET.nuspec +++ b/build/nuget/SSH.NET.nuspec @@ -29,6 +29,9 @@ + + + - \ No newline at end of file + diff --git a/global.json b/global.json index 44da40565..d07970ac2 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.403", + "version": "8.0.100", "rollForward": "latestMajor" } -} \ No newline at end of file +} diff --git a/src/Renci.SshNet/Common/SshData.cs b/src/Renci.SshNet/Common/SshData.cs index 9cbf4fd95..4e7ff0438 100644 --- a/src/Renci.SshNet/Common/SshData.cs +++ b/src/Renci.SshNet/Common/SshData.cs @@ -158,10 +158,14 @@ protected byte[] ReadBytes(int length) var data = new byte[length]; var bytesRead = _stream.Read(data, 0, length); +#if NET8_0_OR_GREATER + ArgumentOutOfRangeException.ThrowIfGreaterThan(length, bytesRead); +#else if (bytesRead < length) { throw new ArgumentOutOfRangeException(nameof(length)); } +#endif return data; } diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index 89e82349d..824ff52a7 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -2,14 +2,14 @@ false Renci.SshNet - net462;netstandard2.0;netstandard2.1;net6.0;net7.0 + net462;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0 $(DefineConstants);FEATURE_BINARY_SERIALIZATION;FEATURE_SOCKET_EAP;FEATURE_SOCKET_APM;FEATURE_DNS_SYNC;FEATURE_HASH_RIPEMD160_CREATE;FEATURE_HMAC_RIPEMD160 - + @@ -17,7 +17,7 @@ - + $(DefineConstants);FEATURE_SOCKET_TAP;FEATURE_SOCKET_APM;FEATURE_SOCKET_EAP;FEATURE_DNS_SYNC;FEATURE_DNS_APM;FEATURE_DNS_TAP diff --git a/src/Renci.SshNet/Sftp/SftpFileStream.cs b/src/Renci.SshNet/Sftp/SftpFileStream.cs index 03b9e088f..7880ffbbd 100644 --- a/src/Renci.SshNet/Sftp/SftpFileStream.cs +++ b/src/Renci.SshNet/Sftp/SftpFileStream.cs @@ -519,6 +519,10 @@ public override int Read(byte[] buffer, int offset, int count) throw new ArgumentNullException(nameof(buffer)); } +#if NET8_0_OR_GREATER + ArgumentOutOfRangeException.ThrowIfNegative(offset); + ArgumentOutOfRangeException.ThrowIfNegative(count); +#else if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset)); @@ -528,7 +532,7 @@ public override int Read(byte[] buffer, int offset, int count) { throw new ArgumentOutOfRangeException(nameof(count)); } - +#endif if ((buffer.Length - offset) < count) { throw new ArgumentException("Invalid array range."); @@ -660,6 +664,10 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, throw new ArgumentNullException(nameof(buffer)); } +#if NET8_0_OR_GREATER + ArgumentOutOfRangeException.ThrowIfNegative(offset); + ArgumentOutOfRangeException.ThrowIfNegative(count); +#else if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset)); @@ -669,7 +677,7 @@ public override async Task ReadAsync(byte[] buffer, int offset, int count, { throw new ArgumentOutOfRangeException(nameof(count)); } - +#endif if ((buffer.Length - offset) < count) { throw new ArgumentException("Invalid array range."); @@ -951,10 +959,14 @@ public override long Seek(long offset, SeekOrigin origin) /// public override void SetLength(long value) { +#if NET8_0_OR_GREATER + ArgumentOutOfRangeException.ThrowIfNegative(value); +#else if (value < 0) { throw new ArgumentOutOfRangeException(nameof(value)); } +#endif // Lock down the file stream while we do this. lock (_lock) @@ -1005,6 +1017,10 @@ public override void Write(byte[] buffer, int offset, int count) throw new ArgumentNullException(nameof(buffer)); } +#if NET8_0_OR_GREATER + ArgumentOutOfRangeException.ThrowIfNegative(offset); + ArgumentOutOfRangeException.ThrowIfNegative(count); +#else if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset)); @@ -1014,7 +1030,7 @@ public override void Write(byte[] buffer, int offset, int count) { throw new ArgumentOutOfRangeException(nameof(count)); } - +#endif if ((buffer.Length - offset) < count) { throw new ArgumentException("Invalid array range."); @@ -1104,6 +1120,10 @@ public override async Task WriteAsync(byte[] buffer, int offset, int count, Canc throw new ArgumentNullException(nameof(buffer)); } +#if NET8_0_OR_GREATER + ArgumentOutOfRangeException.ThrowIfNegative(offset); + ArgumentOutOfRangeException.ThrowIfNegative(count); +#else if (offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset)); @@ -1113,7 +1133,7 @@ public override async Task WriteAsync(byte[] buffer, int offset, int count, Canc { throw new ArgumentOutOfRangeException(nameof(count)); } - +#endif if ((buffer.Length - offset) < count) { throw new ArgumentException("Invalid array range."); diff --git a/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj b/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj index 3f1186f39..eee47fcf7 100644 --- a/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj +++ b/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj @@ -1,7 +1,7 @@ Exe - net7.0 + net8.0 enable enable diff --git a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj index 6abe36e6a..40f0d3a08 100644 --- a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj +++ b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj @@ -1,7 +1,7 @@ 锘 - net7.0 + net8.0 enable false true diff --git a/test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj b/test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj index 26ab725ef..6efdde6c1 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj +++ b/test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj @@ -1,6 +1,6 @@ 锘 - net7.0 + net8.0 enable enable $(NoWarn);SYSLIB0021;SYSLIB1045 diff --git a/test/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs b/test/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs index 2afb84609..f3650976a 100644 --- a/test/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs +++ b/test/Renci.SshNet.Tests/Classes/BaseClientTest_Connected_KeepAliveInterval_NotNegativeOne.cs @@ -56,12 +56,12 @@ protected override void Act() { _client.KeepAliveInterval = _keepAliveInterval; - // allow keep-alive to be sent a few times. .NET 7 is faster and + // allow keep-alive to be sent a few times. .NET 8 is faster and // we need to wait less because we want exactly three messages in a session. #if NETFRAMEWORK Thread.Sleep(195); #else - Thread.Sleep(180); + Thread.Sleep(170); #endif } diff --git a/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index 19f08f14b..43db2f5ef 100644 --- a/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -1,6 +1,6 @@ 锘 - net462;net6.0;net7.0 + net462;net6.0;net7.0;net8.0 From a027c76d7adbf754200035262f682781e32a42a9 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Sat, 2 Dec 2023 14:16:22 +0100 Subject: [PATCH 79/96] Fail with a friendlier error message when response has not been set (#1245) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Wojciech Nag贸rski --- .../Common/AuthenticationPromptEventArgs.cs | 4 +- ...KeyboardInteractiveAuthenticationMethod.cs | 14 +++++- .../InformationRequestMessage.cs | 2 +- .../AuthenticationMethodFactory.cs | 2 +- .../AuthenticationTests.cs | 46 +++++++++++++++---- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/Renci.SshNet/Common/AuthenticationPromptEventArgs.cs b/src/Renci.SshNet/Common/AuthenticationPromptEventArgs.cs index 9c22c340c..3a2562ae1 100644 --- a/src/Renci.SshNet/Common/AuthenticationPromptEventArgs.cs +++ b/src/Renci.SshNet/Common/AuthenticationPromptEventArgs.cs @@ -14,7 +14,7 @@ public class AuthenticationPromptEventArgs : AuthenticationEventArgs /// The instruction. /// The language. /// The information request prompts. - public AuthenticationPromptEventArgs(string username, string instruction, string language, IEnumerable prompts) + public AuthenticationPromptEventArgs(string username, string instruction, string language, IReadOnlyList prompts) : base(username) { Instruction = instruction; @@ -35,6 +35,6 @@ public AuthenticationPromptEventArgs(string username, string instruction, string /// /// Gets server information request prompts. /// - public IEnumerable Prompts { get; } + public IReadOnlyList Prompts { get; } } } diff --git a/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs b/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs index 825809950..7169fabc0 100644 --- a/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs +++ b/src/Renci.SshNet/KeyboardInteractiveAuthenticationMethod.cs @@ -125,9 +125,19 @@ private void Session_UserAuthenticationInformationRequestReceived(object sender, var informationResponse = new InformationResponseMessage(); - foreach (var response in from r in eventArgs.Prompts orderby r.Id ascending select r.Response) + foreach (var prompt in eventArgs.Prompts.OrderBy(r => r.Id)) { - informationResponse.Responses.Add(response); + if (prompt.Response is null) + { + throw new SshAuthenticationException( + $"{nameof(AuthenticationPrompt)}.{nameof(prompt.Response)} is null for " + + $"prompt \"{prompt.Request}\". You can set this by subscribing to " + + $"{nameof(KeyboardInteractiveAuthenticationMethod)}.{nameof(AuthenticationPrompt)} " + + $"and inspecting the {nameof(AuthenticationPromptEventArgs.Prompts)} property " + + $"of the event args."); + } + + informationResponse.Responses.Add(prompt.Response); } // Send information response message diff --git a/src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs b/src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs index c887cc883..7110222ac 100644 --- a/src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs @@ -29,7 +29,7 @@ internal sealed class InformationRequestMessage : Message /// /// Gets information request prompts. /// - public IEnumerable Prompts { get; private set; } + public IReadOnlyList Prompts { get; private set; } /// /// Called when type specific data need to be loaded. diff --git a/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs b/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs index 17e4c75b6..edb3e74d1 100644 --- a/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs +++ b/test/Renci.SshNet.IntegrationTests/AuthenticationMethodFactory.cs @@ -69,7 +69,7 @@ public PrivateKeyAuthenticationMethod CreateRegularUserPrivateKeyAuthenticationM return new PrivateKeyAuthenticationMethod(Users.Regular.UserName, new PrivateKeyFile(memoryStream)); } - public PasswordAuthenticationMethod CreateRegulatUserPasswordAuthenticationMethod() + public PasswordAuthenticationMethod CreateRegularUserPasswordAuthenticationMethod() { return new PasswordAuthenticationMethod(Users.Regular.UserName, Users.Regular.Password); } diff --git a/test/Renci.SshNet.IntegrationTests/AuthenticationTests.cs b/test/Renci.SshNet.IntegrationTests/AuthenticationTests.cs index c3968e949..dd0a4f3d9 100644 --- a/test/Renci.SshNet.IntegrationTests/AuthenticationTests.cs +++ b/test/Renci.SshNet.IntegrationTests/AuthenticationTests.cs @@ -161,7 +161,7 @@ public void Multifactor_Password_ExceedsPartialSuccessLimit() .Update() .Restart(); - var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod()); + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod()); using (var client = new SftpClient(connectionInfo)) { try @@ -187,7 +187,7 @@ public void Multifactor_Password_MatchPartialSuccessLimit() .Update() .Restart(); - var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod()); + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod()); using (var client = new SftpClient(connectionInfo)) { client.Connect(); @@ -205,7 +205,7 @@ public void Multifactor_Password_Or_PublicKeyAndKeyboardInteractive() .Restart(); var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethod(), - _authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod()); + _authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod()); using (var client = new SftpClient(connectionInfo)) { client.Connect(); @@ -243,7 +243,7 @@ public void Multifactor_PasswordAndPublicKey_Or_PasswordAndPassword() .Update() .Restart(); - var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod(), + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod(), _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey()); using (var client = new SftpClient(connectionInfo)) { @@ -275,14 +275,14 @@ public void Multifactor_PasswordAndPassword_Or_PublicKey() .Update() .Restart(); - var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod(), + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod(), _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey()); using (var client = new SftpClient(connectionInfo)) { client.Connect(); } - connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod()); + connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod()); using (var client = new SftpClient(connectionInfo)) { client.Connect(); @@ -297,13 +297,13 @@ public void Multifactor_Password_Or_Password() .Update() .Restart(); - var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod()); + var connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod()); using (var client = new SftpClient(connectionInfo)) { client.Connect(); } - connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegulatUserPasswordAuthenticationMethod(), + connectionInfo = _connectionInfoFactory.Create(_authenticationMethodFactory.CreateRegularUserPasswordAuthenticationMethod(), _authenticationMethodFactory.CreateRegularUserPrivateKeyAuthenticationMethodWithBadKey()); using (var client = new SftpClient(connectionInfo)) { @@ -423,5 +423,35 @@ public void KeyboardInteractiveConnectionInfo() Assert.AreEqual(connectionInfo.Host, SshServerHostName); Assert.AreEqual(connectionInfo.Username, User.UserName); } + + [TestMethod] + public void KeyboardInteractive_NoResponseSet_ThrowsSshAuthenticationException() + { + // ...instead of a cryptic ArgumentNullException + // https://github.com/sshnet/SSH.NET/issues/382 + + _remoteSshdConfig.WithAuthenticationMethods(Users.Regular.UserName, "keyboard-interactive") + .WithChallengeResponseAuthentication(true) + .WithKeyboardInteractiveAuthentication(true) + .WithUsePAM(true) + .Update() + .Restart(); + + var connectionInfo = _connectionInfoFactory.Create(new KeyboardInteractiveAuthenticationMethod(Users.Regular.UserName)); + + using (var client = new SftpClient(connectionInfo)) + { + try + { + client.Connect(); + Assert.Fail(); + } + catch (SshAuthenticationException ex) + { + Assert.IsNull(ex.InnerException); + Assert.IsTrue(ex.Message.StartsWith("AuthenticationPrompt.Response is null for prompt \"Password: \""), $"Message was \"{ex.Message}\""); + } + } + } } } From 9b0262c5fb05da2f3e15c09677b3a8cadae262ca Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Sat, 2 Dec 2023 16:41:32 +0100 Subject: [PATCH 80/96] Disable some impactful analyzers (#1246) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Disable some impactful analyzers * fb --------- Co-authored-by: Wojciech Nag贸rski --- .editorconfig | 121 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 7 deletions(-) diff --git a/.editorconfig b/.editorconfig index 3fbc77faf..aa407a9c4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -89,6 +89,19 @@ dotnet_diagnostic.S1481.severity = none # This is a duplicate of IDE0059. dotnet_diagnostic.S1854.severity = none +# S1944: Invalid casts should be avoided +# https://rules.sonarsource.com/csharp/RSPEC-1944/ +# +# Disabled due to build performance impact. +dotnet_diagnostic.S1944.severity = none + +# S2053: Hashes should include an unpredictable salt +# https://rules.sonarsource.com/csharp/RSPEC-2053/ +# +# Disabled due to build performance impact / +# We need to specify the salt. +dotnet_diagnostic.S2053.severity = none + # S2259: Null pointers should not be dereferenced # https://rules.sonarsource.com/csharp/RSPEC-2259 # @@ -116,8 +129,9 @@ dotnet_diagnostic.S2551.severity = none # S2583: Conditionally executed code should be reachable # https://rules.sonarsource.com/csharp/RSPEC-2583 # +# Disabled due to build performance impact / # This rule produces false errors in, for example, for loops. -#dotnet_diagnostic.S2583.severity = none +dotnet_diagnostic.S2583.severity = none # S2699: Tests should include assertions # https://rules.sonarsource.com/csharp/RSPEC-2699 @@ -131,6 +145,12 @@ dotnet_diagnostic.S2551.severity = none # } dotnet_diagnostic.S2699.severity = none +# S2930: "IDisposables" should be disposed +# https://rules.sonarsource.com/csharp/RSPEC-2930/ +# +# Duplicate of CA2000. +dotnet_diagnostic.S2930.severity = none + # S2933: Fields that are only assigned in the constructor should be "readonly" # https://rules.sonarsource.com/csharp/RSPEC-2933 # @@ -155,6 +175,10 @@ dotnet_diagnostic.S3218.severity = none # LINQ is the root of all evil :p dotnet_diagnostic.S3267.severity = none +# S3329: Cipher Block Chaining IVs should be unpredictable +# https://rules.sonarsource.com/csharp/RSPEC-3329/ +dotnet_diagnostic.S3329.severity = none + # S3376: Attribute, EventArgs, and Exception type names should end with the type being extended # https://rules.sonarsource.com/csharp/RSPEC-3376 # @@ -174,12 +198,36 @@ dotnet_diagnostic.S3442.severity = none # This is a duplicate of MA0087. dotnet_diagnostic.S3450.severity = none +# S3459: Unassigned members should be removed +# https://rules.sonarsource.com/csharp/RSPEC-3459/ +# +# Duplicate of IDE0051/IDE0052 +dotnet_diagnostic.S3459.severity = none + +# S3626: Jump statements should not be redundant +# https://rules.sonarsource.com/csharp/RSPEC-3626/ +# +# Disabled due to build performance impact. +dotnet_diagnostic.S3626.severity = none + +# S3655: Empty nullable value should not be accessed +# https://rules.sonarsource.com/csharp/RSPEC-3655/ +# +# Disabled due to build performance impact. +dotnet_diagnostic.S3655.severity = none + # S3871: Exception types should be "public" # https://rules.sonarsource.com/csharp/RSPEC-3871 # # This is a duplicate of CA1064. dotnet_diagnostic.S3871.severity = none +# S3900: Arguments of public methods should be validated against null +# https://rules.sonarsource.com/csharp/RSPEC-3900/ +# +# This is a duplicate of CA1062. +dotnet_diagnostic.S3900.severity = none + # S3903: Types should be defined in named namespaces # https://rules.sonarsource.com/csharp/RSPEC-3903 # @@ -198,6 +246,12 @@ dotnet_diagnostic.S3925.severity = none # This is a duplicate of MA0015. dotnet_diagnostic.S3928.severity = none +# S3949: Calculations should not overflow +# https://rules.sonarsource.com/csharp/RSPEC-3949/ +# +# Disabled due to build performance impact. +dotnet_diagnostic.S3949.severity = none + # S3998: Threads should not lock on objects with weak identity # https://rules.sonarsource.com/csharp/RSPEC-3998 # @@ -210,6 +264,16 @@ dotnet_diagnostic.S3998.severity = none # This is a duplicate of MA0062. dotnet_diagnostic.S4070.severity = none +# S4158: Empty collections should not be accessed or iterated +# https://rules.sonarsource.com/csharp/RSPEC-4158/ +# +# Disabled due to build performance impact. +dotnet_diagnostic.S4158.severity = none + +# S4423: Weak SSL/TLS protocols should not be used +# https://rules.sonarsource.com/csharp/RSPEC-4423/ +dotnet_diagnostic.S4423.severity = none + # S4456: Parameter validation in yielding methods should be wrapped # https://rules.sonarsource.com/csharp/RSPEC-4456 # @@ -228,6 +292,26 @@ dotnet_diagnostic.S4487.severity = none # This is a partial duplicate of MA0067, and we do not want to report the use of 'default' for a Guid as error. dotnet_diagnostic.S4581.severity = none +# S4830: Server certificates should be verified during SSL/TLS connections +# https://rules.sonarsource.com/csharp/RSPEC-4830/ +dotnet_diagnostic.S4830.severity = none + +# S5542: Encryption algorithms should be used with secure mode and padding scheme +# https://rules.sonarsource.com/csharp/RSPEC-5542/ +dotnet_diagnostic.S5542.severity = none + +# S5547: Cipher algorithms should be robust +# https://rules.sonarsource.com/csharp/RSPEC-5547/ +dotnet_diagnostic.S5547.severity = none + +# S5659: JWT should be signed and verified with strong cipher algorithms +# https://rules.sonarsource.com/csharp/RSPEC-5659/ +dotnet_diagnostic.S5659.severity = none + +# S5773: Types allowed to be deserialized should be restricted +# https://rules.sonarsource.com/csharp/RSPEC-5773/ +dotnet_diagnostic.S4581.severity = none + #### StyleCop rules #### # SA1003: Symbols must be spaced correctly @@ -262,6 +346,12 @@ dotnet_diagnostic.SA1101.severity = none # callsForType.Count); dotnet_diagnostic.SA1116.severity = none +# SA1121: Use built-in type alias +# https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA1121.md +# +# Duplicate of IDE0049. +dotnet_diagnostic.SA1121.severity = none + # SA1200: Using directives must be placed correctly # # This is already verified by the .NET compiler platform analyzers (csharp_using_directive_placement option and IDE0065 rule). @@ -293,6 +383,11 @@ dotnet_diagnostic.SA1413.severity = none # This is a duplicate of IDE0011. dotnet_diagnostic.SA1503.severity = none +# SA1512: Single-line comments should not be followed by a blank line +# +# Blank lines can improve readability. +dotnet_diagnostic.SA1512.severity = none + # SA1516: Elements must be separated by blank line # # When enabled, a diagnostic is produced for properties with both a get and set accessor. @@ -551,9 +646,7 @@ dotnet_diagnostic.CA1510.severity = none # # This is a duplicate of S927, but contains at least one bug: # https://github.com/dotnet/roslyn-analyzers/issues/6461 -# -# Since we do not enable any of the Sonar rules by default, we'll leave CA1725 enabled. -dotnet_diagnostic.CA1725.severity = error +dotnet_diagnostic.CA1725.severity = none # CA1825: Avoid zero-length array allocations # https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1825 @@ -594,12 +687,26 @@ dotnet_diagnostic.CA2208.severity = none # We use ECB mode as the basis for other modes (e.g. CTR) dotnet_diagnostic.CA5358.severity = none +# CA5389: Do not add archive item's path to the target file system path +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca5389 +dotnet_diagnostic.CA5389.severity = none + +# CA5390: Do not hard-code encryption key +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca5390 +dotnet_diagnostic.CA5390.severity = none + # CA5401: Do not use CreateEncryptor with non-default IV -# https://learn.microsoft.com/en-gb/dotnet/fundamentals/code-analysis/quality-rules/ca5401 -# -# We need to specify the IV. +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca5401 dotnet_diagnostic.CA5401.severity = none +# CA5402: Use CreateEncryptor with the default IV +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca5402 +dotnet_diagnostic.CA5402.severity = none + +# CA5403: Do not hard-code certificate +# https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca5403 +dotnet_diagnostic.CA5403.severity = none + #### Roslyn IDE analyser rules #### # IDE0028: Simplify collection initialization; and From 6d9d03205bf8351b0c7159da687f6e9c79a62fe3 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Mon, 4 Dec 2023 09:48:56 +0100 Subject: [PATCH 81/96] Rebased AsyncResult fix (#1184) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 馃悰 AsyncResult contains invalid value - AsyncResult should contain invalid value immediately after async operation is marked as completed - there was race condition problems with callback method which is invoked on different thread so updating of value is done without any synchronization. So in some cases async operation is marked as completed but async result value is not yet updated and contains invalid value * Revert test --------- Co-authored-by: Miroslav Pokorn媒 --- src/Renci.SshNet/SftpClient.cs | 33 ++++++++----------- .../SftpClientTest.Upload.cs | 10 +----- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/Renci.SshNet/SftpClient.cs b/src/Renci.SshNet/SftpClient.cs index aa30efadb..01472dbff 100644 --- a/src/Renci.SshNet/SftpClient.cs +++ b/src/Renci.SshNet/SftpClient.cs @@ -583,7 +583,7 @@ public IEnumerable ListDirectory(string path, Action listCallbac { CheckDisposed(); - return InternalListDirectory(path, listCallback); + return InternalListDirectory(path, asyncResult: null, listCallback); } /// @@ -666,12 +666,7 @@ public IAsyncResult BeginListDirectory(string path, AsyncCallback asyncCallback, { try { - var result = InternalListDirectory(path, count => - { - asyncResult.Update(count); - - listCallback?.Invoke(count); - }); + var result = InternalListDirectory(path, asyncResult, listCallback); asyncResult.SetAsCompleted(result, completedSynchronously: false); } @@ -898,12 +893,7 @@ public IAsyncResult BeginDownloadFile(string path, Stream output, AsyncCallback { try { - InternalDownloadFile(path, output, asyncResult, offset => - { - asyncResult.Update(offset); - - downloadCallback?.Invoke(offset); - }); + InternalDownloadFile(path, output, asyncResult, downloadCallback); asyncResult.SetAsCompleted(exception: null, completedSynchronously: false); } @@ -1131,11 +1121,7 @@ public IAsyncResult BeginUploadFile(Stream input, string path, bool canOverride, { try { - InternalUploadFile(input, path, flags, asyncResult, offset => - { - asyncResult.Update(offset); - uploadCallback?.Invoke(offset); - }); + InternalUploadFile(input, path, flags, asyncResult, uploadCallback); asyncResult.SetAsCompleted(exception: null, completedSynchronously: false); } @@ -2200,7 +2186,7 @@ private List InternalSynchronizeDirectories(string sourcePath, string #region Existing Files at The Destination - var destFiles = InternalListDirectory(destinationPath, listCallback: null); + var destFiles = InternalListDirectory(destinationPath, asyncResult: null, listCallback: null); var destDict = new Dictionary(); foreach (var destFile in destFiles) { @@ -2268,13 +2254,14 @@ private List InternalSynchronizeDirectories(string sourcePath, string /// Internals the list directory. /// /// The path. + /// An that references the asynchronous request. /// The list callback. /// /// A list of files in the specfied directory. /// /// is . /// Client not connected. - private List InternalListDirectory(string path, Action listCallback) + private List InternalListDirectory(string path, SftpListDirectoryAsyncResult asyncResult, Action listCallback) { if (path is null) { @@ -2314,6 +2301,8 @@ private List InternalListDirectory(string path, Action listCallb f.Value)); } + asyncResult?.Update(result.Count); + // Call callback to report number of files read if (listCallback is not null) { @@ -2380,6 +2369,8 @@ private void InternalDownloadFile(string path, Stream output, SftpDownloadAsyncR totalBytesRead += (ulong) data.Length; + asyncResult?.Update(totalBytesRead); + if (downloadCallback is not null) { // Copy offset to ensure it's not modified between now and execution of callback @@ -2452,6 +2443,8 @@ private void InternalUploadFile(Stream input, string path, Flags flags, SftpUplo _ = Interlocked.Decrement(ref expectedResponses); _ = responseReceivedWaitHandle.Set(); + asyncResult?.Update(writtenBytes); + // Call callback to report number of bytes written if (uploadCallback is not null) { diff --git a/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs index b4b620e77..91c248bd3 100644 --- a/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs +++ b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SftpClientTest.Upload.cs @@ -230,15 +230,7 @@ public void Test_Sftp_Multiple_Async_Upload_And_Download_10Files_5MB_Each() sftp.Disconnect(); Assert.IsTrue(hashMatches, "Hash does not match"); - if (!uploadDownloadSizeOk) - { - // TODO https://github.com/sshnet/SSH.NET/issues/1253 - Assert.Inconclusive("Uploaded and downloaded bytes should match, but test is not stable"); - } - else - { - Assert.IsTrue(uploadDownloadSizeOk, "Uploaded and downloaded bytes does not match"); - } + Assert.IsTrue(uploadDownloadSizeOk, "Uploaded and downloaded bytes does not match"); } } From 4c4883eed0ecb41fd0a077be3f179261b60391cb Mon Sep 17 00:00:00 2001 From: Jacob Slusser Date: Fri, 8 Dec 2023 22:39:33 -0800 Subject: [PATCH 82/96] Standardizes additional file types in .editorconfig (#1266) * Updates .gitignore to exclude test results * Adds .editorconfig for xml, csproj, and props files Formats xml, csproj, and props files * Hides stylecop.json from Solution Explorer projects --- .editorconfig | 5 ++ .gitignore | 2 +- Directory.Build.props | 58 +++++++++---------- src/Renci.SshNet/Renci.SshNet.csproj | 2 +- .../Renci.SshNet.IntegrationTests.csproj | 8 +-- .../Renci.SshNet.TestTools.OpenSSH.csproj | 22 +++---- .../Renci.SshNet.Tests.csproj | 10 ++-- 7 files changed, 56 insertions(+), 51 deletions(-) diff --git a/.editorconfig b/.editorconfig index aa407a9c4..91bdfb44f 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,6 +9,11 @@ indent_size = 4 tab_width = 4 end_of_line = crlf +[*.{xml,csproj,props}] + +indent_size = 2 +tab_width = 2 + [*.cs] #### Sonar rules #### diff --git a/.gitignore b/.gitignore index 8348fa321..483a79904 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ test/**/bin/** test/**/obj/** # MSTest test Results -src/TestResults/ +TestResults/ # User-specific files *.suo diff --git a/Directory.Build.props b/Directory.Build.props index 4ffd15e32..de4ae8456 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,42 +1,42 @@ - - - - - true - $(MSBuildThisFileDirectory)Renci.SshNet.snk - true - latest - 9999 - true - false - + + true + $(MSBuildThisFileDirectory)Renci.SshNet.snk + true + latest + 9999 + true + false + - - - true - preview-All - true - + + true + preview-All + true + - - - - + + + - - - - - - - + + + + + + diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index 824ff52a7..41d725344 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -2,7 +2,7 @@ false Renci.SshNet - net462;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0 + net462;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0 diff --git a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj index 40f0d3a08..f55b67440 100644 --- a/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj +++ b/test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj @@ -27,12 +27,12 @@ - runtime; build; native; contentfiles; analyzers; buildtransitive - all + runtime; build; native; contentfiles; analyzers; buildtransitive + all - build; native; contentfiles; analyzers; buildtransitive - all + build; native; contentfiles; analyzers; buildtransitive + all diff --git a/test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj b/test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj index 6efdde6c1..b60661536 100644 --- a/test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj +++ b/test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj @@ -1,13 +1,13 @@ 锘 - - net8.0 - enable - enable - $(NoWarn);SYSLIB0021;SYSLIB1045 - - - - - - + + net8.0 + enable + enable + $(NoWarn);SYSLIB0021;SYSLIB1045 + + + + + + \ No newline at end of file diff --git a/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj b/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj index 43db2f5ef..5ba659daa 100644 --- a/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj +++ b/test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj @@ -4,7 +4,7 @@ - + @@ -16,12 +16,12 @@ - runtime; build; native; contentfiles; analyzers; buildtransitive - all + runtime; build; native; contentfiles; analyzers; buildtransitive + all - build; native; contentfiles; analyzers; buildtransitive - all + build; native; contentfiles; analyzers; buildtransitive + all From f45af386281060f6deb562e48dacc33f5a5b486c Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Sat, 9 Dec 2023 08:52:31 +0100 Subject: [PATCH 83/96] Replace SemaphoreLight with SemaphoreSlim (#1265) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This paves the way for asynchronous synchronisation via WaitAsync (and eliminates a timing test which sometimes fails in CI) Co-authored-by: Wojciech Nag贸rski --- src/Renci.SshNet/Channels/Channel.cs | 2 +- src/Renci.SshNet/Common/SemaphoreLight.cs | 244 ------------------ src/Renci.SshNet/ISession.cs | 2 +- src/Renci.SshNet/Session.cs | 8 +- src/Renci.SshNet/Sftp/SftpFileReader.cs | 4 +- .../ChannelSessionTest_Dispose_Disposed.cs | 4 +- ...hannelEofReceived_DisposeInEventHandler.cs | 4 +- ...Received_SendChannelCloseMessageFailure.cs | 6 +- ...Received_SendChannelCloseMessageSuccess.cs | 6 +- ...Received_SendChannelCloseMessageFailure.cs | 4 +- ...Received_SendChannelCloseMessageSuccess.cs | 4 +- ...Received_SendChannelCloseMessageFailure.cs | 4 +- ...Received_SendChannelCloseMessageSuccess.cs | 4 +- ...Open_NoChannelCloseOrChannelEofReceived.cs | 6 +- ...ofReceived_SendChannelEofMessageFailure.cs | 4 +- ...sOpen_ChannelCloseAndChannelEofReceived.cs | 4 +- ...edAndChannelIsOpen_ChannelCloseReceived.cs | 4 +- ...Open_NoChannelCloseOrChannelEofReceived.cs | 4 +- ...ived_SessionIsConnectedAndChannelIsOpen.cs | 4 +- ...Open_ExceptionWaitingOnOpenConfirmation.cs | 4 +- ...nOpenFailureReceived_NoRetriesAvailable.cs | 4 +- ...n_OnOpenFailureReceived_RetriesAvalable.cs | 6 +- .../Classes/Common/SemaphoreLightTest.cs | 94 ------- 23 files changed, 46 insertions(+), 384 deletions(-) delete mode 100644 src/Renci.SshNet/Common/SemaphoreLight.cs delete mode 100644 test/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs diff --git a/src/Renci.SshNet/Channels/Channel.cs b/src/Renci.SshNet/Channels/Channel.cs index 580c63e0f..25975872d 100644 --- a/src/Renci.SshNet/Channels/Channel.cs +++ b/src/Renci.SshNet/Channels/Channel.cs @@ -285,7 +285,7 @@ protected IConnectionInfo ConnectionInfo /// Gets the session semaphore to control number of session channels. /// /// The session semaphore. - protected SemaphoreLight SessionSemaphore + protected SemaphoreSlim SessionSemaphore { get { return _session.SessionSemaphore; } } diff --git a/src/Renci.SshNet/Common/SemaphoreLight.cs b/src/Renci.SshNet/Common/SemaphoreLight.cs deleted file mode 100644 index 106b10180..000000000 --- a/src/Renci.SshNet/Common/SemaphoreLight.cs +++ /dev/null @@ -1,244 +0,0 @@ -锘縰sing System; -using System.Threading; - -namespace Renci.SshNet.Common -{ - /// - /// Light implementation of SemaphoreSlim. - /// - public sealed class SemaphoreLight : IDisposable - { - private readonly object _lock = new object(); - private ManualResetEvent _waitHandle; - - private int _currentCount; - - /// - /// Initializes a new instance of the class, specifying the initial number of requests that can - /// be granted concurrently. - /// - /// The initial number of requests for the semaphore that can be granted concurrently. - /// is a negative number. - public SemaphoreLight(int initialCount) - { - if (initialCount < 0) - { - throw new ArgumentOutOfRangeException(nameof(initialCount), "The value cannot be negative."); - } - - _currentCount = initialCount; - } - - /// - /// Gets the current count of the . - /// - public int CurrentCount - { - get { return _currentCount; } - } - - /// - /// Gets a that can be used to wait on the semaphore. - /// - /// - /// A that can be used to wait on the semaphore. - /// - /// - /// A successful wait on the does not imply a successful - /// wait on the itself. It should be followed by a true wait - /// on the semaphore. - /// - public WaitHandle AvailableWaitHandle - { - get - { - if (_waitHandle is null) - { - lock (_lock) - { - _waitHandle ??= new ManualResetEvent(_currentCount > 0); - } - } - - return _waitHandle; - } - } - - /// - /// Exits the once. - /// - /// The previous count of the . - public int Release() - { - return Release(1); - } - - /// - /// Exits the a specified number of times. - /// - /// The number of times to exit the semaphore. - /// - /// The previous count of the . - /// - public int Release(int releaseCount) - { - lock (_lock) - { - var oldCount = _currentCount; - - _currentCount += releaseCount; - - // signal waithandle when the original semaphore count was zero - if (_waitHandle != null && oldCount == 0) - { - _ = _waitHandle.Set(); - } - - Monitor.PulseAll(_lock); - - return oldCount; - } - } - - /// - /// Blocks the current thread until it can enter the . - /// - public void Wait() - { - lock (_lock) - { - while (_currentCount < 1) - { - _ = Monitor.Wait(_lock); - } - - _currentCount--; - - // unsignal waithandle when the semaphore count reaches zero - if (_waitHandle != null && _currentCount == 0) - { - _ = _waitHandle.Reset(); - } - - Monitor.PulseAll(_lock); - } - } - - /// - /// Blocks the current thread until it can enter the , using a 32-bit signed - /// integer that specifies the timeout. - /// - /// The number of milliseconds to wait, or Infinite(-1) to wait indefinitely. - /// - /// if the current thread successfully entered the ; otherwise, . - /// - public bool Wait(int millisecondsTimeout) - { - if (millisecondsTimeout < -1) - { - throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout), "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); - } - - return WaitWithTimeout(millisecondsTimeout); - } - - /// - /// Blocks the current thread until it can enter the , using a - /// to specify the timeout. - /// - /// A that represents the number of milliseconds to wait, or a that represents -1 milliseconds to wait indefinitely. - /// - /// if the current thread successfully entered the ; otherwise, . - /// - public bool Wait(TimeSpan timeout) - { - var timeoutInMilliseconds = timeout.TotalMilliseconds; - if (timeoutInMilliseconds is < -1d or > int.MaxValue) - { - throw new ArgumentOutOfRangeException(nameof(timeout), "The timeout must represent a value between -1 and Int32.MaxValue, inclusive."); - } - - return WaitWithTimeout((int) timeoutInMilliseconds); - } - - private bool WaitWithTimeout(int timeoutInMilliseconds) - { - lock (_lock) - { - if (timeoutInMilliseconds == Session.Infinite) - { - while (_currentCount < 1) - { - _ = Monitor.Wait(_lock); - } - } - else - { - if (_currentCount < 1) - { - if (timeoutInMilliseconds > 0) - { - return false; - } - - var remainingTimeInMilliseconds = timeoutInMilliseconds; - var startTicks = Environment.TickCount; - - while (_currentCount < 1) - { - if (!Monitor.Wait(_lock, remainingTimeInMilliseconds)) - { - return false; - } - - var elapsed = Environment.TickCount - startTicks; - remainingTimeInMilliseconds -= elapsed; - if (remainingTimeInMilliseconds < 0) - { - return false; - } - } - } - } - - _currentCount--; - - // unsignal waithandle when the semaphore count is zero - if (_waitHandle != null && _currentCount == 0) - { - _ = _waitHandle.Reset(); - } - - Monitor.PulseAll(_lock); - - return true; - } - } - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - Dispose(disposing: true); - GC.SuppressFinalize(this); - } - - /// - /// Releases unmanaged and - optionally - managed resources. - /// - /// to release both managed and unmanaged resources; to release only unmanaged resources. - private void Dispose(bool disposing) - { - if (disposing) - { - var waitHandle = _waitHandle; - if (waitHandle is not null) - { - waitHandle.Dispose(); - _waitHandle = null; - } - } - } - } -} diff --git a/src/Renci.SshNet/ISession.cs b/src/Renci.SshNet/ISession.cs index e78ff75f8..707d36805 100644 --- a/src/Renci.SshNet/ISession.cs +++ b/src/Renci.SshNet/ISession.cs @@ -36,7 +36,7 @@ internal interface ISession : IDisposable /// /// The session semaphore. /// - SemaphoreLight SessionSemaphore { get; } + SemaphoreSlim SessionSemaphore { get; } /// /// Gets a that can be used to wait for the message listener loop to complete. diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index c984d3109..5bf6d8eef 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -87,7 +87,7 @@ public class Session : ISession /// /// Some server may restrict number to prevent authentication attacks. /// - private static readonly SemaphoreLight AuthenticationConnection = new SemaphoreLight(3); + private static readonly SemaphoreSlim AuthenticationConnection = new SemaphoreSlim(3); /// /// Holds the factory to use for creating new services. @@ -196,7 +196,7 @@ public class Session : ISession private Compressor _clientCompression; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private bool _isDisconnectMessageSent; @@ -213,7 +213,7 @@ public class Session : ISession /// /// The session semaphore. /// - public SemaphoreLight SessionSemaphore + public SemaphoreSlim SessionSemaphore { get { @@ -221,7 +221,7 @@ public SemaphoreLight SessionSemaphore { lock (_connectAndLazySemaphoreInitLock) { - _sessionSemaphore ??= new SemaphoreLight(ConnectionInfo.MaxSessions); + _sessionSemaphore ??= new SemaphoreSlim(ConnectionInfo.MaxSessions); } } diff --git a/src/Renci.SshNet/Sftp/SftpFileReader.cs b/src/Renci.SshNet/Sftp/SftpFileReader.cs index af32f87a7..8d3ef211f 100644 --- a/src/Renci.SshNet/Sftp/SftpFileReader.cs +++ b/src/Renci.SshNet/Sftp/SftpFileReader.cs @@ -16,7 +16,7 @@ internal sealed class SftpFileReader : ISftpFileReader private readonly byte[] _handle; private readonly ISftpSession _sftpSession; private readonly uint _chunkSize; - private readonly SemaphoreLight _semaphore; + private readonly SemaphoreSlim _semaphore; private readonly object _readLock; private readonly ManualResetEvent _disposingWaitHandle; private readonly ManualResetEvent _readAheadCompleted; @@ -62,7 +62,7 @@ public SftpFileReader(byte[] handle, ISftpSession sftpSession, uint chunkSize, i _sftpSession = sftpSession; _chunkSize = chunkSize; _fileSize = fileSize; - _semaphore = new SemaphoreLight(maxPendingReads); + _semaphore = new SemaphoreSlim(maxPendingReads); _queue = new Dictionary(maxPendingReads); _readLock = new object(); _readAheadCompleted = new ManualResetEvent(initialState: false); diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs index 07ba0d53e..da5ce0d12 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_Disposed.cs @@ -23,7 +23,7 @@ public class ChannelSessionTest_Dispose_Disposed : ChannelSessionTestBase private uint _remotePacketSize; private uint _remoteChannelNumber; private TimeSpan _channelCloseTimeout; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private IList _channelClosedRegister; private List _channelExceptionRegister; @@ -38,7 +38,7 @@ protected override void SetupData() _remoteWindowSize = (uint)random.Next(0, int.MaxValue); _remotePacketSize = (uint)random.Next(100, 200); _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); - _sessionSemaphore = new SemaphoreLight(1); + _sessionSemaphore = new SemaphoreSlim(1); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); } diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs index be4fdc300..626a6519a 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_DisposeInEventHandler.cs @@ -24,7 +24,7 @@ public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_Chann private List _channelExceptionRegister; private ChannelSession _channel; private MockSequence _sequence; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; protected override void SetupData() @@ -41,7 +41,7 @@ protected override void SetupData() _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs index aac5c837c..dca9c0ecf 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageFailure.cs @@ -22,7 +22,7 @@ public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_Chann private List _channelExceptionRegister; private ChannelSession _channel; private MockSequence _sequence; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; protected override void SetupData() @@ -38,7 +38,7 @@ protected override void SetupData() _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); } protected override void SetupMocks() @@ -126,4 +126,4 @@ public void IsOpenShouldReturnFalse() Assert.IsFalse(_channel.IsOpen); } } -} \ No newline at end of file +} diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs index dd17c5ab5..7a68ff177 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived_SendChannelCloseMessageSuccess.cs @@ -23,7 +23,7 @@ public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_Chann private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; protected override void SetupData() @@ -40,7 +40,7 @@ protected override void SetupData() _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); } protected override void SetupMocks() @@ -134,4 +134,4 @@ public void IsOpenShouldReturnFalse() Assert.IsFalse(_channel.IsOpen); } } -} \ No newline at end of file +} diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs index 251adf5d0..6948fded2 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageFailure.cs @@ -22,7 +22,7 @@ public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_Chann private List _channelExceptionRegister; private ChannelSession _channel; private MockSequence _sequence; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; protected override void SetupData() @@ -38,7 +38,7 @@ protected override void SetupData() _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs index 37dff92fa..b07bf3d20 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelCloseReceived_SendChannelCloseMessageSuccess.cs @@ -23,7 +23,7 @@ public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_Chann private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; protected override void SetupData() @@ -40,7 +40,7 @@ protected override void SetupData() _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs index 83b40b327..d8294bf1f 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageFailure.cs @@ -22,7 +22,7 @@ public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_Chann private List _channelExceptionRegister; private ChannelSession _channel; private MockSequence _sequence; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; protected override void SetupData() @@ -38,7 +38,7 @@ protected override void SetupData() _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs index 5ab596264..3b340bd42 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_ChannelEofReceived_SendChannelCloseMessageSuccess.cs @@ -22,7 +22,7 @@ public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_Chann private IList _channelClosedRegister; private List _channelExceptionRegister; private ChannelSession _channel; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; protected override void SetupData() @@ -39,7 +39,7 @@ protected override void SetupData() _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs index 47c84903a..ce2bc0969 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs @@ -20,7 +20,7 @@ public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoCha private uint _remotePacketSize; private uint _remoteChannelNumber; private TimeSpan _channelCloseTimeout; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private IList _channelClosedRegister; private List _channelExceptionRegister; @@ -35,7 +35,7 @@ protected override void SetupData() _remoteWindowSize = (uint) random.Next(0, int.MaxValue); _remotePacketSize = (uint) random.Next(100, 200); _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); - _sessionSemaphore = new SemaphoreLight(1); + _sessionSemaphore = new SemaphoreSlim(1); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); } @@ -142,4 +142,4 @@ public void IsOpenShouldReturnFalse() Assert.IsFalse(_channel.IsOpen); } } -} \ No newline at end of file +} diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs index ce733bbcd..b547af778 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived_SendChannelEofMessageFailure.cs @@ -20,7 +20,7 @@ public class ChannelSessionTest_Dispose_SessionIsConnectedAndChannelIsOpen_NoCha private uint _remotePacketSize; private uint _remoteChannelNumber; private TimeSpan _channelCloseTimeout; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private IList _channelClosedRegister; private List _channelExceptionRegister; @@ -35,7 +35,7 @@ protected override void SetupData() _remoteWindowSize = (uint) random.Next(0, int.MaxValue); _remotePacketSize = (uint) random.Next(100, 200); _channelCloseTimeout = TimeSpan.FromSeconds(random.Next(10, 20)); - _sessionSemaphore = new SemaphoreLight(1); + _sessionSemaphore = new SemaphoreSlim(1); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); } diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs index d44f4e0ab..e2ded5942 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseAndChannelEofReceived.cs @@ -22,7 +22,7 @@ public class ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_Ch private List _channelExceptionRegister; private ChannelSession _channel; private MockSequence _sequence; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; protected override void SetupData() @@ -38,7 +38,7 @@ protected override void SetupData() _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs index fedd4cd64..62f5ab4ac 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_ChannelCloseReceived.cs @@ -22,7 +22,7 @@ public class ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_Ch private List _channelExceptionRegister; private ChannelSession _channel; private MockSequence _sequence; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; protected override void SetupData() @@ -38,7 +38,7 @@ protected override void SetupData() _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs index ce8fa16cd..08f00b905 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_NoChannelCloseOrChannelEofReceived.cs @@ -22,7 +22,7 @@ public class ChannelSessionTest_Dispose_SessionIsNotConnectedAndChannelIsOpen_No private List _channelExceptionRegister; private ChannelSession _channel; private MockSequence _sequence; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; protected override void SetupData() @@ -38,7 +38,7 @@ protected override void SetupData() _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs index 584c4e943..5771f4e10 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnectedAndChannelIsOpen.cs @@ -24,7 +24,7 @@ public class ChannelSessionTest_OnSessionChannelCloseReceived_SessionIsConnected private List _channelExceptionRegister; private ChannelSession _channel; private MockSequence _sequence; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; protected override void SetupData() @@ -41,7 +41,7 @@ protected override void SetupData() _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs index fbb27e38f..44b9800a2 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation.cs @@ -18,7 +18,7 @@ public class ChannelSessionTest_Open_ExceptionWaitingOnOpenConfirmation : Channe private uint _localPacketSize; private IList _channelClosedRegister; private List _channelExceptionRegister; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; private Exception _waitOnConfirmationException; private SystemException _actualException; @@ -31,7 +31,7 @@ protected override void SetupData() _localWindowSize = (uint) random.Next(2000, 3000); _localPacketSize = (uint) random.Next(1000, 2000); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _waitOnConfirmationException = new SystemException(); diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs index ab4ba4f60..37cf3ac06 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable.cs @@ -19,7 +19,7 @@ public class ChannelSessionTest_Open_OnOpenFailureReceived_NoRetriesAvailable : private uint _localPacketSize; private IList _channelClosedRegister; private List _channelExceptionRegister; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; private uint _failureReasonCode; private string _failureDescription; @@ -34,7 +34,7 @@ protected override void SetupData() _localWindowSize = (uint) random.Next(2000, 3000); _localPacketSize = (uint) random.Next(1000, 2000); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); _actualException = null; diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs index e6caeb222..9934c0715 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable.cs @@ -22,7 +22,7 @@ public class ChannelSessionTest_Open_OnOpenFailureReceived_RetriesAvalable : Cha private uint _remotePacketSize; private IList _channelClosedRegister; private List _channelExceptionRegister; - private SemaphoreLight _sessionSemaphore; + private SemaphoreSlim _sessionSemaphore; private int _initialSessionSemaphoreCount; private uint _failureReasonCode; private string _failureDescription; @@ -39,7 +39,7 @@ protected override void SetupData() _remoteWindowSize = (uint) random.Next(0, int.MaxValue); _remotePacketSize = (uint) random.Next(0, int.MaxValue); _initialSessionSemaphoreCount = random.Next(10, 20); - _sessionSemaphore = new SemaphoreLight(_initialSessionSemaphoreCount); + _sessionSemaphore = new SemaphoreSlim(_initialSessionSemaphoreCount); _channelClosedRegister = new List(); _channelExceptionRegister = new List(); @@ -147,4 +147,4 @@ public void IsOpenShouldReturnTrue() Assert.IsTrue(_channel.IsOpen); } } -} \ No newline at end of file +} diff --git a/test/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs b/test/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs deleted file mode 100644 index 5b4aa43b9..000000000 --- a/test/Renci.SshNet.Tests/Classes/Common/SemaphoreLightTest.cs +++ /dev/null @@ -1,94 +0,0 @@ -锘縰sing System; -using System.Diagnostics; -using System.Threading; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using Renci.SshNet.Common; -using Renci.SshNet.Tests.Common; - -namespace Renci.SshNet.Tests.Classes.Common -{ - [TestClass] - public class SemaphoreLightTest : TestBase - { - [TestMethod] - public void SemaphoreLightConstructorTest() - { - var initialCount = new Random().Next(1, 10); - var target = new SemaphoreLight(initialCount); - Assert.AreEqual(initialCount, target.CurrentCount); - } - - [TestMethod] - public void Release() - { - var initialCount = new Random().Next(1, 10); - var target = new SemaphoreLight(initialCount); - - Assert.AreEqual(initialCount, target.Release()); - Assert.AreEqual(initialCount + 1, target.CurrentCount); - - Assert.AreEqual(initialCount + 1, target.Release()); - Assert.AreEqual(initialCount + 2, target.CurrentCount); - } - - /// - ///A test for Release - /// - [TestMethod] - public void Release_ReleaseCount() - { - var initialCount = new Random().Next(1, 10); - var target = new SemaphoreLight(initialCount); - - var releaseCount1 = new Random().Next(1, 10); - Assert.AreEqual(initialCount, target.Release(releaseCount1)); - Assert.AreEqual(initialCount + releaseCount1, target.CurrentCount); - - var releaseCount2 = new Random().Next(1, 10); - Assert.AreEqual(initialCount + releaseCount1, target.Release(releaseCount2)); - Assert.AreEqual(initialCount + releaseCount1 + releaseCount2, target.CurrentCount); - } - - /// - ///A test for Wait - /// - [TestMethod] - public void WaitTest() - { - const int sleepTime = 200; - const int initialCount = 2; - var target = new SemaphoreLight(initialCount); - - var watch = new Stopwatch(); - watch.Start(); - - target.Wait(); - target.Wait(); - - Assert.IsTrue(watch.ElapsedMilliseconds < 50); - - var releaseThread = new Thread(() => - { - Thread.Sleep(sleepTime); - _ = target.Release(); - }); - releaseThread.Start(); - - target.Wait(); - - watch.Stop(); - - Assert.IsTrue(watch.ElapsedMilliseconds >= 200); - Assert.IsTrue(watch.ElapsedMilliseconds < 250); - } - - [TestMethod] - public void CurrentCountTest() - { - var initialCount = new Random().Next(1, 20); - var target = new SemaphoreLight(initialCount); - - Assert.AreEqual(initialCount, target.CurrentCount); - } - } -} From 04178d843241705f3d14fa6b999435eee37f92b0 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Sat, 9 Dec 2023 11:30:57 +0100 Subject: [PATCH 84/96] Always use factories for HmacAlgorithms (#1262) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Always use factories for HmacAlgorithms * Re-order HmacAlgorithms --------- Co-authored-by: Wojciech Nag贸rski --- src/Renci.SshNet/ConnectionInfo.cs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index 6ffbf5979..4a24e78a9 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -378,19 +378,21 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy { "cast128-cbc", new CipherInfo(128, (key, iv) => new CastCipher(key, new CbcCipherMode(iv), padding: null)) }, }; +#pragma warning disable IDE0200 // Remove unnecessary lambda expression; We want to prevent instantiating the HashAlgorithm objects. HmacAlgorithms = new Dictionary { - { "hmac-md5", new HashInfo(16*8, CryptoAbstraction.CreateHMACMD5) }, - { "hmac-md5-96", new HashInfo(16*8, key => CryptoAbstraction.CreateHMACMD5(key, 96)) }, - { "hmac-sha1", new HashInfo(20*8, CryptoAbstraction.CreateHMACSHA1) }, - { "hmac-sha1-96", new HashInfo(20*8, key => CryptoAbstraction.CreateHMACSHA1(key, 96)) }, - { "hmac-sha2-256", new HashInfo(32*8, CryptoAbstraction.CreateHMACSHA256) }, - { "hmac-sha2-256-96", new HashInfo(32*8, key => CryptoAbstraction.CreateHMACSHA256(key, 96)) }, - { "hmac-sha2-512", new HashInfo(64 * 8, CryptoAbstraction.CreateHMACSHA512) }, + { "hmac-sha2-256", new HashInfo(32*8, key => CryptoAbstraction.CreateHMACSHA256(key)) }, + { "hmac-sha2-512", new HashInfo(64 * 8, key => CryptoAbstraction.CreateHMACSHA512(key)) }, { "hmac-sha2-512-96", new HashInfo(64 * 8, key => CryptoAbstraction.CreateHMACSHA512(key, 96)) }, - { "hmac-ripemd160", new HashInfo(160, CryptoAbstraction.CreateHMACRIPEMD160) }, - { "hmac-ripemd160@openssh.com", new HashInfo(160, CryptoAbstraction.CreateHMACRIPEMD160) }, + { "hmac-sha2-256-96", new HashInfo(32*8, key => CryptoAbstraction.CreateHMACSHA256(key, 96)) }, + { "hmac-ripemd160", new HashInfo(160, key => CryptoAbstraction.CreateHMACRIPEMD160(key)) }, + { "hmac-ripemd160@openssh.com", new HashInfo(160, key => CryptoAbstraction.CreateHMACRIPEMD160(key)) }, + { "hmac-sha1", new HashInfo(20*8, key => CryptoAbstraction.CreateHMACSHA1(key)) }, + { "hmac-sha1-96", new HashInfo(20*8, key => CryptoAbstraction.CreateHMACSHA1(key, 96)) }, + { "hmac-md5", new HashInfo(16*8, key => CryptoAbstraction.CreateHMACMD5(key)) }, + { "hmac-md5-96", new HashInfo(16*8, key => CryptoAbstraction.CreateHMACMD5(key, 96)) }, }; +#pragma warning restore IDE0200 // Remove unnecessary lambda expression HostKeyAlgorithms = new Dictionary> { From 6220beb83d9734da6f5dc71345060bc226d1b101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Sat, 9 Dec 2023 12:28:06 +0100 Subject: [PATCH 85/96] Native async (#1267) --- src/Renci.SshNet/Abstractions/SocketAbstraction.cs | 11 +++++++++-- src/Renci.SshNet/Abstractions/SocketExtensions.cs | 4 +++- .../Connection/ProtocolVersionExchange.cs | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs index f8b289168..f5f840336 100644 --- a/src/Renci.SshNet/Abstractions/SocketAbstraction.cs +++ b/src/Renci.SshNet/Abstractions/SocketAbstraction.cs @@ -325,10 +325,17 @@ public static int Read(Socket socket, byte[] buffer, int offset, int size, TimeS return totalBytesRead; } - public static Task ReadAsync(Socket socket, byte[] buffer, int offset, int length, CancellationToken cancellationToken) +#if NET6_0_OR_GREATER + public static async Task ReadAsync(Socket socket, byte[] buffer, CancellationToken cancellationToken) { - return socket.ReceiveAsync(buffer, offset, length, cancellationToken); + return await socket.ReceiveAsync(buffer, SocketFlags.None, cancellationToken).ConfigureAwait(false); } +#else + public static Task ReadAsync(Socket socket, byte[] buffer, CancellationToken cancellationToken) + { + return socket.ReceiveAsync(buffer, 0, buffer.Length, cancellationToken); + } +#endif public static void Send(Socket socket, byte[] data) { diff --git a/src/Renci.SshNet/Abstractions/SocketExtensions.cs b/src/Renci.SshNet/Abstractions/SocketExtensions.cs index 9edfbf94b..2c34c899c 100644 --- a/src/Renci.SshNet/Abstractions/SocketExtensions.cs +++ b/src/Renci.SshNet/Abstractions/SocketExtensions.cs @@ -1,4 +1,5 @@ -锘縰sing System; +锘#if !NET6_0_OR_GREATER +using System; using System.Net; using System.Net.Sockets; using System.Runtime.CompilerServices; @@ -130,3 +131,4 @@ public static async Task ReceiveAsync(this Socket socket, byte[] buffer, in } } } +#endif diff --git a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs index 00c5d0573..bde732c06 100644 --- a/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs +++ b/src/Renci.SshNet/Connection/ProtocolVersionExchange.cs @@ -187,7 +187,7 @@ private static async Task SocketReadLineAsync(Socket socket, List // to be processed by subsequent invocations. while (true) { - var bytesRead = await SocketAbstraction.ReadAsync(socket, data, 0, data.Length, cancellationToken).ConfigureAwait(false); + var bytesRead = await SocketAbstraction.ReadAsync(socket, data, cancellationToken).ConfigureAwait(false); if (bytesRead == 0) { throw new SshConnectionException("The connection was closed by the remote host."); From f172ac587c68e1cf333be98de61b5d831f4d7117 Mon Sep 17 00:00:00 2001 From: Jacob Slusser Date: Sun, 10 Dec 2023 08:46:35 -0800 Subject: [PATCH 86/96] Removes MessageAttribute in favor of properties on Message class (#1270) * Exludes the test projects from code coverage reports * Removes MessageAttribute in favor of properties on Message class * Benchmark for removal of MessageAttribute --- .../Messages/Authentication/BannerMessage.cs | 19 ++++++- .../Messages/Authentication/FailureMessage.cs | 19 ++++++- .../InformationRequestMessage.cs | 19 ++++++- .../InformationResponseMessage.cs | 19 ++++++- .../PasswordChangeRequiredMessage.cs | 19 ++++++- .../Authentication/PublicKeyMessage.cs | 19 ++++++- .../Messages/Authentication/RequestMessage.cs | 19 ++++++- .../Messages/Authentication/SuccessMessage.cs | 19 ++++++- .../Connection/ChannelCloseMessage.cs | 19 ++++++- .../Messages/Connection/ChannelDataMessage.cs | 19 ++++++- .../Messages/Connection/ChannelEofMessage.cs | 19 ++++++- .../Connection/ChannelExtendedDataMessage.cs | 19 ++++++- .../Connection/ChannelFailureMessage.cs | 19 ++++++- .../ChannelOpen/ChannelOpenMessage.cs | 21 ++++++- .../ChannelOpenConfirmationMessage.cs | 19 ++++++- .../Connection/ChannelOpenFailureMessage.cs | 19 ++++++- .../ChannelRequest/ChannelRequestMessage.cs | 19 ++++++- .../Connection/ChannelSuccessMessage.cs | 19 ++++++- .../Connection/ChannelWindowAdjustMessage.cs | 19 ++++++- .../Connection/GlobalRequestMessage.cs | 19 ++++++- .../Connection/RequestFailureMessage.cs | 19 ++++++- .../Connection/RequestSuccessMessage.cs | 19 ++++++- src/Renci.SshNet/Messages/Message.cs | 56 +++++-------------- src/Renci.SshNet/Messages/MessageAttribute.cs | 38 ------------- .../Messages/Transport/DebugMessage.cs | 19 ++++++- .../Messages/Transport/DisconnectMessage.cs | 19 ++++++- .../Messages/Transport/IgnoreMessage.cs | 19 ++++++- .../KeyExchangeDhGroupExchangeGroup.cs | 21 ++++++- .../KeyExchangeDhGroupExchangeInit.cs | 19 ++++++- .../KeyExchangeDhGroupExchangeReply.cs | 19 ++++++- .../KeyExchangeDhGroupExchangeRequest.cs | 19 ++++++- .../Transport/KeyExchangeDhInitMessage.cs | 19 ++++++- .../Transport/KeyExchangeDhReplyMessage.cs | 19 ++++++- .../Transport/KeyExchangeEcdhInitMessage.cs | 19 ++++++- .../Transport/KeyExchangeEcdhReplyMessage.cs | 19 ++++++- .../Transport/KeyExchangeInitMessage.cs | 19 ++++++- .../Messages/Transport/NewKeysMessage.cs | 19 ++++++- .../Transport/ServiceAcceptMessage.cs | 19 ++++++- .../Transport/ServiceRequestMessage.cs | 19 ++++++- .../Transport/UnimplementedMessage.cs | 19 ++++++- .../Messages/MessageBenchmarks.cs | 35 ++++++++++++ .../Renci.SshNet.Benchmarks.csproj | 4 +- .../Properties/AssemblyInfo.cs | 5 ++ .../Connection/ChannelDataMessageTest.cs | 2 +- .../ChannelOpen/ChannelOpenMessageTest.cs | 6 +- .../Messages/Transport/IgnoreMessageTest.cs | 2 +- .../KeyExchangeDhGroupExchangeGroupBuilder.cs | 3 +- .../KeyExchangeDhGroupExchangeReplyBuilder.cs | 3 +- .../KeyExchangeDhGroupExchangeRequestTest.cs | 2 +- .../Classes/SessionTest_ConnectedBase.cs | 3 +- ...Connected_ServerAndClientDisconnectRace.cs | 3 +- .../Properties/AssemblyInfo.cs | 5 ++ 52 files changed, 755 insertions(+), 138 deletions(-) delete mode 100644 src/Renci.SshNet/Messages/MessageAttribute.cs create mode 100644 test/Renci.SshNet.Benchmarks/Messages/MessageBenchmarks.cs create mode 100644 test/Renci.SshNet.IntegrationTests/Properties/AssemblyInfo.cs create mode 100644 test/Renci.SshNet.Tests/Properties/AssemblyInfo.cs diff --git a/src/Renci.SshNet/Messages/Authentication/BannerMessage.cs b/src/Renci.SshNet/Messages/Authentication/BannerMessage.cs index 90652a34f..15f46386b 100644 --- a/src/Renci.SshNet/Messages/Authentication/BannerMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/BannerMessage.cs @@ -3,12 +3,29 @@ /// /// Represents SSH_MSG_USERAUTH_BANNER message. /// - [Message("SSH_MSG_USERAUTH_BANNER", 53)] public class BannerMessage : Message { private byte[] _message; private byte[] _language; + /// + public override string MessageName + { + get + { + return "SSH_MSG_USERAUTH_BANNER"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 53; + } + } + /// /// Gets banner message. /// diff --git a/src/Renci.SshNet/Messages/Authentication/FailureMessage.cs b/src/Renci.SshNet/Messages/Authentication/FailureMessage.cs index f02705ecb..1904fa1de 100644 --- a/src/Renci.SshNet/Messages/Authentication/FailureMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/FailureMessage.cs @@ -5,9 +5,26 @@ namespace Renci.SshNet.Messages.Authentication /// /// Represents SSH_MSG_USERAUTH_FAILURE message. /// - [Message("SSH_MSG_USERAUTH_FAILURE", 51)] public class FailureMessage : Message { + /// + public override string MessageName + { + get + { + return "SSH_MSG_USERAUTH_FAILURE"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 51; + } + } + /// /// Gets or sets the allowed authentications if available. /// diff --git a/src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs b/src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs index 7110222ac..9a45bcf2b 100644 --- a/src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/InformationRequestMessage.cs @@ -8,9 +8,26 @@ namespace Renci.SshNet.Messages.Authentication /// /// Represents SSH_MSG_USERAUTH_INFO_REQUEST message. /// - [Message("SSH_MSG_USERAUTH_INFO_REQUEST", 60)] internal sealed class InformationRequestMessage : Message { + /// + public override string MessageName + { + get + { + return "SSH_MSG_USERAUTH_INFO_REQUEST"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 60; + } + } + /// /// Gets information request name. /// diff --git a/src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs b/src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs index 9e3227342..27e4fe65b 100644 --- a/src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/InformationResponseMessage.cs @@ -6,9 +6,26 @@ namespace Renci.SshNet.Messages.Authentication /// /// Represents SSH_MSG_USERAUTH_INFO_RESPONSE message. /// - [Message("SSH_MSG_USERAUTH_INFO_RESPONSE", 61)] internal sealed class InformationResponseMessage : Message { + /// + public override string MessageName + { + get + { + return "SSH_MSG_USERAUTH_INFO_RESPONSE"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 61; + } + } + /// /// Gets authentication responses. /// diff --git a/src/Renci.SshNet/Messages/Authentication/PasswordChangeRequiredMessage.cs b/src/Renci.SshNet/Messages/Authentication/PasswordChangeRequiredMessage.cs index a87b53dfb..8cff4d1d7 100644 --- a/src/Renci.SshNet/Messages/Authentication/PasswordChangeRequiredMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/PasswordChangeRequiredMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_USERAUTH_PASSWD_CHANGEREQ message. /// - [Message("SSH_MSG_USERAUTH_PASSWD_CHANGEREQ", 60)] internal sealed class PasswordChangeRequiredMessage : Message { + /// + public override string MessageName + { + get + { + return "SSH_MSG_USERAUTH_PASSWD_CHANGEREQ"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 60; + } + } + /// /// Gets password change request message as UTF-8 encoded byte array. /// diff --git a/src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs b/src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs index b917ab99a..491d1262c 100644 --- a/src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/PublicKeyMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_USERAUTH_PK_OK message. /// - [Message("SSH_MSG_USERAUTH_PK_OK", 60)] internal sealed class PublicKeyMessage : Message { + /// + public override string MessageName + { + get + { + return "SSH_MSG_USERAUTH_PK_OK"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 60; + } + } + /// /// Gets the name of the public key algorithm as ASCII encoded byte array. /// diff --git a/src/Renci.SshNet/Messages/Authentication/RequestMessage.cs b/src/Renci.SshNet/Messages/Authentication/RequestMessage.cs index 57f60849f..58daa10fc 100644 --- a/src/Renci.SshNet/Messages/Authentication/RequestMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/RequestMessage.cs @@ -6,9 +6,26 @@ namespace Renci.SshNet.Messages.Authentication /// /// Represents SSH_MSG_USERAUTH_REQUEST message. Server as a base message for other user authentication requests. /// - [Message("SSH_MSG_USERAUTH_REQUEST", AuthenticationMessageCode)] public abstract class RequestMessage : Message { + /// + public override string MessageName + { + get + { + return "SSH_MSG_USERAUTH_REQUEST"; + } + } + + /// + public override byte MessageNumber + { + get + { + return AuthenticationMessageCode; + } + } + /// /// Returns the authentication message code for SSH_MSG_USERAUTH_REQUEST. /// diff --git a/src/Renci.SshNet/Messages/Authentication/SuccessMessage.cs b/src/Renci.SshNet/Messages/Authentication/SuccessMessage.cs index e21544211..03ed4a9a0 100644 --- a/src/Renci.SshNet/Messages/Authentication/SuccessMessage.cs +++ b/src/Renci.SshNet/Messages/Authentication/SuccessMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_USERAUTH_SUCCESS message. /// - [Message("SSH_MSG_USERAUTH_SUCCESS", 52)] public class SuccessMessage : Message { + /// + public override string MessageName + { + get + { + return "SSH_MSG_USERAUTH_SUCCESS"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 52; + } + } + /// /// Called when type specific data need to be loaded. /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelCloseMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelCloseMessage.cs index dfb430134..c66294a79 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelCloseMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelCloseMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_CHANNEL_CLOSE message. /// - [Message("SSH_MSG_CHANNEL_CLOSE", 97)] public class ChannelCloseMessage : ChannelMessage { + /// + public override string MessageName + { + get + { + return "SSH_MSG_CHANNEL_CLOSE"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 97; + } + } + /// /// Initializes a new instance of the class. /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs index 8a764d798..f387a7c36 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelDataMessage.cs @@ -5,10 +5,25 @@ namespace Renci.SshNet.Messages.Connection /// /// Represents SSH_MSG_CHANNEL_DATA message. /// - [Message("SSH_MSG_CHANNEL_DATA", MessageNumber)] public class ChannelDataMessage : ChannelMessage { - internal const byte MessageNumber = 94; + /// + public override string MessageName + { + get + { + return "SSH_MSG_CHANNEL_DATA"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 94; + } + } /// /// Gets the message data. diff --git a/src/Renci.SshNet/Messages/Connection/ChannelEofMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelEofMessage.cs index 0ad028242..1a7ca9bce 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelEofMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelEofMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_CHANNEL_EOF message. /// - [Message("SSH_MSG_CHANNEL_EOF", 96)] public class ChannelEofMessage : ChannelMessage { + /// + public override string MessageName + { + get + { + return "SSH_MSG_CHANNEL_EOF"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 96; + } + } + /// /// Initializes a new instance of the class. /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelExtendedDataMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelExtendedDataMessage.cs index 4546a7343..c3788ff3a 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelExtendedDataMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelExtendedDataMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_CHANNEL_EXTENDED_DATA message. /// - [Message("SSH_MSG_CHANNEL_EXTENDED_DATA", 95)] public class ChannelExtendedDataMessage : ChannelMessage { + /// + public override string MessageName + { + get + { + return "SSH_MSG_CHANNEL_EXTENDED_DATA"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 95; + } + } + /// /// Gets message data type code. /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelFailureMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelFailureMessage.cs index 5987534ca..a6b24d2da 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelFailureMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelFailureMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_CHANNEL_FAILURE message. /// - [Message("SSH_MSG_CHANNEL_FAILURE", 100)] public class ChannelFailureMessage : ChannelMessage { + /// + public override string MessageName + { + get + { + return "SSH_MSG_CHANNEL_FAILURE"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 100; + } + } + /// /// Initializes a new instance of the class. /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenMessage.cs index 3a18bb22f..a45eda441 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpen/ChannelOpenMessage.cs @@ -6,13 +6,28 @@ namespace Renci.SshNet.Messages.Connection /// /// Represents SSH_MSG_CHANNEL_OPEN message. /// - [Message("SSH_MSG_CHANNEL_OPEN", MessageNumber)] public class ChannelOpenMessage : Message { - internal const byte MessageNumber = 90; - private byte[] _infoBytes; + /// + public override string MessageName + { + get + { + return "SSH_MSG_CHANNEL_OPEN"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 90; + } + } + /// /// Gets the type of the channel as ASCII encoded byte array. /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpenConfirmationMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpenConfirmationMessage.cs index 0213136df..ae6db2bf9 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpenConfirmationMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpenConfirmationMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_CHANNEL_OPEN_CONFIRMATION message. /// - [Message("SSH_MSG_CHANNEL_OPEN_CONFIRMATION", 91)] public class ChannelOpenConfirmationMessage : ChannelMessage { + /// + public override string MessageName + { + get + { + return "SSH_MSG_CHANNEL_OPEN_CONFIRMATION"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 91; + } + } + /// /// Gets the remote channel number. /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelOpenFailureMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelOpenFailureMessage.cs index 4488f9f5f..e68ab0358 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelOpenFailureMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelOpenFailureMessage.cs @@ -3,7 +3,6 @@ /// /// Represents SSH_MSG_CHANNEL_OPEN_FAILURE message. /// - [Message("SSH_MSG_CHANNEL_OPEN_FAILURE", 92)] public class ChannelOpenFailureMessage : ChannelMessage { internal const uint AdministrativelyProhibited = 1; @@ -14,6 +13,24 @@ public class ChannelOpenFailureMessage : ChannelMessage private byte[] _description; private byte[] _language; + /// + public override string MessageName + { + get + { + return "SSH_MSG_CHANNEL_OPEN_FAILURE"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 92; + } + } + /// /// Gets failure reason code. /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs index fd9ad03b6..695c35b29 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelRequest/ChannelRequestMessage.cs @@ -3,12 +3,29 @@ /// /// Represents SSH_MSG_CHANNEL_REQUEST message. /// - [Message("SSH_MSG_CHANNEL_REQUEST", 98)] public class ChannelRequestMessage : ChannelMessage { private string _requestName; private byte[] _requestNameBytes; + /// + public override string MessageName + { + get + { + return "SSH_MSG_CHANNEL_REQUEST"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 98; + } + } + /// /// Gets the name of the request. /// diff --git a/src/Renci.SshNet/Messages/Connection/ChannelSuccessMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelSuccessMessage.cs index 50d302f21..c554f32e9 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelSuccessMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelSuccessMessage.cs @@ -3,7 +3,6 @@ /// /// Represents SSH_MSG_CHANNEL_SUCCESS message. /// - [Message("SSH_MSG_CHANNEL_SUCCESS", 99)] public class ChannelSuccessMessage : ChannelMessage { /// @@ -22,6 +21,24 @@ public ChannelSuccessMessage(uint localChannelNumber) { } + /// + public override string MessageName + { + get + { + return "SSH_MSG_CHANNEL_SUCCESS"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 99; + } + } + internal override void Process(Session session) { session.OnChannelSuccessReceived(this); diff --git a/src/Renci.SshNet/Messages/Connection/ChannelWindowAdjustMessage.cs b/src/Renci.SshNet/Messages/Connection/ChannelWindowAdjustMessage.cs index 315c98c8a..3e6ad90d1 100644 --- a/src/Renci.SshNet/Messages/Connection/ChannelWindowAdjustMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/ChannelWindowAdjustMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_CHANNEL_SUCCESS message. /// - [Message("SSH_MSG_CHANNEL_WINDOW_ADJUST", 93)] public class ChannelWindowAdjustMessage : ChannelMessage { + /// + public override string MessageName + { + get + { + return "SSH_MSG_CHANNEL_WINDOW_ADJUST"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 93; + } + } + /// /// Gets number of bytes to add to the window. /// diff --git a/src/Renci.SshNet/Messages/Connection/GlobalRequestMessage.cs b/src/Renci.SshNet/Messages/Connection/GlobalRequestMessage.cs index 6e0ca3a21..d34778e54 100644 --- a/src/Renci.SshNet/Messages/Connection/GlobalRequestMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/GlobalRequestMessage.cs @@ -3,11 +3,28 @@ /// /// Represents SSH_MSG_GLOBAL_REQUEST message. /// - [Message("SSH_MSG_GLOBAL_REQUEST", 80)] public class GlobalRequestMessage : Message { private byte[] _requestName; + /// + public override string MessageName + { + get + { + return "SSH_MSG_GLOBAL_REQUEST"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 80; + } + } + /// /// Gets the name of the request. /// diff --git a/src/Renci.SshNet/Messages/Connection/RequestFailureMessage.cs b/src/Renci.SshNet/Messages/Connection/RequestFailureMessage.cs index 553f95473..8602f5089 100644 --- a/src/Renci.SshNet/Messages/Connection/RequestFailureMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/RequestFailureMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_REQUEST_FAILURE message. /// - [Message("SSH_MSG_REQUEST_FAILURE", 82)] public class RequestFailureMessage : Message { + /// + public override string MessageName + { + get + { + return "SSH_MSG_REQUEST_FAILURE"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 82; + } + } + /// /// Called when type specific data need to be loaded. /// diff --git a/src/Renci.SshNet/Messages/Connection/RequestSuccessMessage.cs b/src/Renci.SshNet/Messages/Connection/RequestSuccessMessage.cs index 00ad1059d..68f5a2f84 100644 --- a/src/Renci.SshNet/Messages/Connection/RequestSuccessMessage.cs +++ b/src/Renci.SshNet/Messages/Connection/RequestSuccessMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_REQUEST_SUCCESS message. /// - [Message("SSH_MSG_REQUEST_SUCCESS", 81)] public class RequestSuccessMessage : Message { + /// + public override string MessageName + { + get + { + return "SSH_MSG_REQUEST_SUCCESS"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 81; + } + } + /// /// Gets the bound port. /// diff --git a/src/Renci.SshNet/Messages/Message.cs b/src/Renci.SshNet/Messages/Message.cs index ebe3a2e71..eab59815d 100644 --- a/src/Renci.SshNet/Messages/Message.cs +++ b/src/Renci.SshNet/Messages/Message.cs @@ -1,5 +1,4 @@ -锘縰sing System.Globalization; -using System.IO; +锘縰sing System.IO; using Renci.SshNet.Abstractions; using Renci.SshNet.Common; @@ -13,11 +12,16 @@ namespace Renci.SshNet.Messages public abstract class Message : SshData { /// - /// Gets the size of the message in bytes. + /// Gets the message name as defined in RFC 4250. /// - /// - /// The size of the messages in bytes. - /// + public abstract string MessageName { get; } + + /// + /// Gets the message number as defined in RFC 4250. + /// + public abstract byte MessageNumber { get; } + + /// protected override int BufferCapacity { get @@ -26,28 +30,11 @@ protected override int BufferCapacity } } - /// - /// Writes the message to the specified . - /// - /// The to write the message to. + /// protected override void WriteBytes(SshDataStream stream) { - var enumerator = GetType().GetCustomAttributes(inherit: true).GetEnumerator(); - try - { - if (!enumerator.MoveNext()) - { - throw new SshException(string.Format(CultureInfo.CurrentCulture, "Type '{0}' is not a valid message type.", GetType().AssemblyQualifiedName)); - } - - var messageAttribute = enumerator.Current; - stream.WriteByte(messageAttribute.Number); - base.WriteBytes(stream); - } - finally - { - enumerator.Dispose(); - } + stream.WriteByte(MessageNumber); + base.WriteBytes(stream); } internal byte[] GetPacket(byte paddingMultiplier, Compressor compressor) @@ -163,23 +150,10 @@ private static byte GetPaddingLength(byte paddingMultiplier, long packetLength) return paddingLength; } - /// - /// Returns a that represents this instance. - /// - /// - /// A that represents this instance. - /// + /// public override string ToString() { - using (var enumerator = GetType().GetCustomAttributes(inherit: true).GetEnumerator()) - { - if (!enumerator.MoveNext()) - { - return string.Format(CultureInfo.CurrentCulture, "'{0}' without Message attribute.", GetType().FullName); - } - - return enumerator.Current.Name; - } + return MessageName; } /// diff --git a/src/Renci.SshNet/Messages/MessageAttribute.cs b/src/Renci.SshNet/Messages/MessageAttribute.cs deleted file mode 100644 index f94d13c32..000000000 --- a/src/Renci.SshNet/Messages/MessageAttribute.cs +++ /dev/null @@ -1,38 +0,0 @@ -锘縰sing System; - -namespace Renci.SshNet.Messages -{ - /// - /// Indicates that a class represents SSH message. This class cannot be inherited. - /// - [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] - public sealed class MessageAttribute : Attribute - { - /// - /// Gets the message name as defined in RFC 4250. - /// - /// - /// The name. - /// - public string Name { get; } - - /// - /// Gets the message number as defined in RFC 4250. - /// - /// - /// The number. - /// - public byte Number { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The name. - /// The number. - public MessageAttribute(string name, byte number) - { - Name = name; - Number = number; - } - } -} diff --git a/src/Renci.SshNet/Messages/Transport/DebugMessage.cs b/src/Renci.SshNet/Messages/Transport/DebugMessage.cs index f550d95fe..0331107d9 100644 --- a/src/Renci.SshNet/Messages/Transport/DebugMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/DebugMessage.cs @@ -3,12 +3,29 @@ /// /// Represents SSH_MSG_DEBUG message. /// - [Message("SSH_MSG_DEBUG", 4)] public class DebugMessage : Message { private byte[] _message; private byte[] _language; + /// + public override string MessageName + { + get + { + return "SSH_MSG_DEBUG"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 4; + } + } + /// /// Gets a value indicating whether the message to be always displayed. /// diff --git a/src/Renci.SshNet/Messages/Transport/DisconnectMessage.cs b/src/Renci.SshNet/Messages/Transport/DisconnectMessage.cs index b5f43adfc..88ad5a01a 100644 --- a/src/Renci.SshNet/Messages/Transport/DisconnectMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/DisconnectMessage.cs @@ -3,12 +3,29 @@ /// /// Represents SSH_MSG_DISCONNECT message. /// - [Message("SSH_MSG_DISCONNECT", 1)] public class DisconnectMessage : Message, IKeyExchangedAllowed { private byte[] _description; private byte[] _language; + /// + public override string MessageName + { + get + { + return "SSH_MSG_DISCONNECT"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 1; + } + } + /// /// Gets disconnect reason code. /// diff --git a/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs b/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs index d657d2d46..b71b28788 100644 --- a/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/IgnoreMessage.cs @@ -5,10 +5,25 @@ namespace Renci.SshNet.Messages.Transport /// /// Represents SSH_MSG_IGNORE message. /// - [Message("SSH_MSG_IGNORE", MessageNumber)] public class IgnoreMessage : Message { - internal const byte MessageNumber = 2; + /// + public override string MessageName + { + get + { + return "SSH_MSG_IGNORE"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 2; + } + } /// /// Gets ignore message data if this message has been initialised diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs index f1010a19d..a17c23e33 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeGroup.cs @@ -5,14 +5,29 @@ namespace Renci.SshNet.Messages.Transport /// /// Represents SSH_MSG_KEX_DH_GEX_GROUP message. /// - [Message("SSH_MSG_KEX_DH_GEX_GROUP", MessageNumber)] public class KeyExchangeDhGroupExchangeGroup : Message { - internal const byte MessageNumber = 31; - private byte[] _safePrime; private byte[] _subGroup; + /// + public override string MessageName + { + get + { + return "SSH_MSG_KEX_DH_GEX_GROUP"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 31; + } + } + /// /// Gets the safe prime. /// diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs index 381c534b9..c63484739 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeInit.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_KEX_DH_GEX_INIT message. /// - [Message("SSH_MSG_KEX_DH_GEX_INIT", 32)] internal sealed class KeyExchangeDhGroupExchangeInit : Message, IKeyExchangedAllowed { + /// + public override string MessageName + { + get + { + return "SSH_MSG_KEX_DH_GEX_INIT"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 32; + } + } + /// /// Gets the E value. /// diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs index 7b446d962..090dd71ab 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeReply.cs @@ -3,10 +3,25 @@ /// /// Represents SSH_MSG_KEX_DH_GEX_REPLY message. /// - [Message("SSH_MSG_KEX_DH_GEX_REPLY", MessageNumber)] internal sealed class KeyExchangeDhGroupExchangeReply : Message { - internal const byte MessageNumber = 33; + /// + public override string MessageName + { + get + { + return "SSH_MSG_KEX_DH_GEX_REPLY"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 33; + } + } /// /// Gets server public host key and certificates. diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeRequest.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeRequest.cs index 9bb6c6bc8..1ad967c8e 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeRequest.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhGroupExchangeRequest.cs @@ -3,10 +3,25 @@ /// /// Represents SSH_MSG_KEX_DH_GEX_REQUEST message. /// - [Message("SSH_MSG_KEX_DH_GEX_REQUEST", MessageNumber)] internal sealed class KeyExchangeDhGroupExchangeRequest : Message, IKeyExchangedAllowed { - internal const byte MessageNumber = 34; + /// + public override string MessageName + { + get + { + return "SSH_MSG_KEX_DH_GEX_REQUEST"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 34; + } + } /// /// Gets the minimum size, in bits, of an acceptable group. diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs index 5b681d1b4..3ce030c8d 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhInitMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_KEXDH_INIT message. /// - [Message("SSH_MSG_KEXDH_INIT", 30)] internal sealed class KeyExchangeDhInitMessage : Message, IKeyExchangedAllowed { + /// + public override string MessageName + { + get + { + return "SSH_MSG_KEXDH_INIT"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 30; + } + } + /// /// Gets the E value. /// diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs index 8f0a1489f..efc280183 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeDhReplyMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_KEXDH_REPLY message. /// - [Message("SSH_MSG_KEXDH_REPLY", 31)] public class KeyExchangeDhReplyMessage : Message { + /// + public override string MessageName + { + get + { + return "SSH_MSG_KEXDH_REPLY"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 31; + } + } + /// /// Gets server public host key and certificates. /// diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs index 2d02d1480..ab5bc1c85 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhInitMessage.cs @@ -6,9 +6,26 @@ namespace Renci.SshNet.Messages.Transport /// /// Represents SSH_MSG_KEXECDH_INIT message. /// - [Message("SSH_MSG_KEX_ECDH_INIT", 30)] internal sealed class KeyExchangeEcdhInitMessage : Message, IKeyExchangedAllowed { + /// + public override string MessageName + { + get + { + return "SSH_MSG_KEX_ECDH_INIT"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 30; + } + } + /// /// Gets the client's ephemeral contribution to the ECDH exchange, encoded as an octet string. /// diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs index a5626aece..70ed96c00 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeEcdhReplyMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_KEXECDH_REPLY message. /// - [Message("SSH_MSG_KEX_ECDH_REPLY", 31)] public class KeyExchangeEcdhReplyMessage : Message { + /// + public override string MessageName + { + get + { + return "SSH_MSG_KEX_ECDH_REPLY"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 31; + } + } + /// /// Gets a string encoding an X.509v3 certificate containing the server's ECDSA public host key. /// diff --git a/src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs b/src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs index 43bcd72bf..7bfce46dc 100644 --- a/src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/KeyExchangeInitMessage.cs @@ -5,7 +5,6 @@ namespace Renci.SshNet.Messages.Transport /// /// Represents SSH_MSG_KEXINIT message. /// - [Message("SSH_MSG_KEXINIT", 20)] public class KeyExchangeInitMessage : Message, IKeyExchangedAllowed { /// @@ -20,6 +19,24 @@ public KeyExchangeInitMessage() #region Message Properties + /// + public override string MessageName + { + get + { + return "SSH_MSG_KEXINIT"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 20; + } + } + /// /// Gets session cookie. /// diff --git a/src/Renci.SshNet/Messages/Transport/NewKeysMessage.cs b/src/Renci.SshNet/Messages/Transport/NewKeysMessage.cs index 838d4373b..ea0f6b754 100644 --- a/src/Renci.SshNet/Messages/Transport/NewKeysMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/NewKeysMessage.cs @@ -3,9 +3,26 @@ /// /// Represents SSH_MSG_NEWKEYS message. /// - [Message("SSH_MSG_NEWKEYS", 21)] public class NewKeysMessage : Message, IKeyExchangedAllowed { + /// + public override string MessageName + { + get + { + return "SSH_MSG_NEWKEYS"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 21; + } + } + /// /// Called when type specific data need to be loaded. /// diff --git a/src/Renci.SshNet/Messages/Transport/ServiceAcceptMessage.cs b/src/Renci.SshNet/Messages/Transport/ServiceAcceptMessage.cs index a7c2a8c6f..ce16d9fd4 100644 --- a/src/Renci.SshNet/Messages/Transport/ServiceAcceptMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/ServiceAcceptMessage.cs @@ -6,10 +6,25 @@ namespace Renci.SshNet.Messages.Transport /// /// Represents SSH_MSG_SERVICE_ACCEPT message. /// - [Message("SSH_MSG_SERVICE_ACCEPT", MessageNumber)] public class ServiceAcceptMessage : Message { - internal const byte MessageNumber = 6; + /// + public override string MessageName + { + get + { + return "SSH_MSG_SERVICE_ACCEPT"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 6; + } + } /// /// Gets the name of the service. diff --git a/src/Renci.SshNet/Messages/Transport/ServiceRequestMessage.cs b/src/Renci.SshNet/Messages/Transport/ServiceRequestMessage.cs index c41a4f904..c7b6a6cbf 100644 --- a/src/Renci.SshNet/Messages/Transport/ServiceRequestMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/ServiceRequestMessage.cs @@ -6,11 +6,28 @@ namespace Renci.SshNet.Messages.Transport /// /// Represents SSH_MSG_SERVICE_REQUEST message. /// - [Message("SSH_MSG_SERVICE_REQUEST", 5)] public class ServiceRequestMessage : Message { private readonly byte[] _serviceName; + /// + public override string MessageName + { + get + { + return "SSH_MSG_SERVICE_REQUEST"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 5; + } + } + /// /// Gets the name of the service. /// diff --git a/src/Renci.SshNet/Messages/Transport/UnimplementedMessage.cs b/src/Renci.SshNet/Messages/Transport/UnimplementedMessage.cs index 323a01439..761156408 100644 --- a/src/Renci.SshNet/Messages/Transport/UnimplementedMessage.cs +++ b/src/Renci.SshNet/Messages/Transport/UnimplementedMessage.cs @@ -5,9 +5,26 @@ namespace Renci.SshNet.Messages.Transport /// /// Represents SSH_MSG_UNIMPLEMENTED message. /// - [Message("SSH_MSG_UNIMPLEMENTED", 3)] public class UnimplementedMessage : Message { + /// + public override string MessageName + { + get + { + return "SSH_MSG_UNIMPLEMENTED"; + } + } + + /// + public override byte MessageNumber + { + get + { + return 3; + } + } + /// /// Called when type specific data need to be loaded. /// diff --git a/test/Renci.SshNet.Benchmarks/Messages/MessageBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Messages/MessageBenchmarks.cs new file mode 100644 index 000000000..5a15773e4 --- /dev/null +++ b/test/Renci.SshNet.Benchmarks/Messages/MessageBenchmarks.cs @@ -0,0 +1,35 @@ +锘縰sing BenchmarkDotNet.Attributes; + +using Renci.SshNet.Common; +using Renci.SshNet.Messages; +using Renci.SshNet.Messages.Transport; + +namespace Renci.SshNet.Benchmarks.Messages +{ + [MemoryDiagnoser] + public class MessageBenchmarks + { + [Benchmark] + public Message WriteBytes() + { + using var sshDataStream = new SshDataStream(SshData.DefaultCapacity); + var bannerMessage = new WritableDisconnectMessage(DisconnectReason.ServiceNotAvailable, "Goodbye"); + bannerMessage.WritePrivateBytes(sshDataStream); + + return bannerMessage; // Avoid JIT elimination + } + + private sealed class WritableDisconnectMessage : DisconnectMessage + { + public WritableDisconnectMessage(DisconnectReason reasonCode, string message) + : base(reasonCode, message) + { + } + + public void WritePrivateBytes(SshDataStream sshDataStream) + { + WriteBytes(sshDataStream); + } + } + } +} diff --git a/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj b/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj index eee47fcf7..e9e964377 100644 --- a/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj +++ b/test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj @@ -1,4 +1,4 @@ - +锘 Exe net8.0 @@ -7,7 +7,7 @@ - + diff --git a/test/Renci.SshNet.IntegrationTests/Properties/AssemblyInfo.cs b/test/Renci.SshNet.IntegrationTests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..a3ec2d895 --- /dev/null +++ b/test/Renci.SshNet.IntegrationTests/Properties/AssemblyInfo.cs @@ -0,0 +1,5 @@ +锘#if NET6_0_OR_GREATER +using System.Diagnostics.CodeAnalysis; + +[assembly: ExcludeFromCodeCoverage] +#endif // NET6_0_OR_GREATER diff --git a/test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs index fbc5e1b46..31002433b 100644 --- a/test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelDataMessageTest.cs @@ -116,7 +116,7 @@ public void GetBytes() var sshDataStream = new SshDataStream(bytes); - Assert.AreEqual(ChannelDataMessage.MessageNumber, sshDataStream.ReadByte()); + Assert.AreEqual(target.MessageNumber, sshDataStream.ReadByte()); Assert.AreEqual(localChannelNumber, sshDataStream.ReadUInt32()); Assert.AreEqual((uint) size, sshDataStream.ReadUInt32()); diff --git a/test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs index 1a40d8609..d53568a83 100644 --- a/test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Messages/Connection/ChannelOpen/ChannelOpenMessageTest.cs @@ -94,7 +94,7 @@ public void GetBytes() var sshDataStream = new SshDataStream(bytes); - Assert.AreEqual(ChannelOpenMessage.MessageNumber, sshDataStream.ReadByte()); + Assert.AreEqual(target.MessageNumber, sshDataStream.ReadByte()); var actualChannelTypeLength = sshDataStream.ReadUInt32(); Assert.AreEqual((uint) target.ChannelType.Length, actualChannelTypeLength); @@ -225,16 +225,16 @@ public void Load_ShouldThrowNotSupportedExceptionWhenChannelTypeIsNotSupported() var maximumPacketSize = (uint)_random.Next(0, int.MaxValue); var channelName = "dunno_" + _random.Next().ToString(CultureInfo.InvariantCulture); var channelType = _ascii.GetBytes(channelName); + var target = new ChannelOpenMessage(); var sshDataStream = new SshDataStream(1 + 4 + channelType.Length + 4 + 4 + 4); - sshDataStream.WriteByte(ChannelOpenMessage.MessageNumber); + sshDataStream.WriteByte(target.MessageNumber); sshDataStream.Write((uint) channelType.Length); sshDataStream.Write(channelType, 0, channelType.Length); sshDataStream.Write(localChannelNumber); sshDataStream.Write(initialWindowSize); sshDataStream.Write(maximumPacketSize); var bytes = sshDataStream.ToArray(); - var target = new ChannelOpenMessage(); try { diff --git a/test/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs index ecdbf3310..ff8fd86dc 100644 --- a/test/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Messages/Transport/IgnoreMessageTest.cs @@ -68,7 +68,7 @@ public void GetBytes() var sshDataStream = new SshDataStream(bytes); - Assert.AreEqual(IgnoreMessage.MessageNumber, sshDataStream.ReadByte()); + Assert.AreEqual(request.MessageNumber, sshDataStream.ReadByte()); Assert.AreEqual((uint) _data.Length, sshDataStream.ReadUInt32()); var actualData = new byte[_data.Length]; diff --git a/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupBuilder.cs b/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupBuilder.cs index 4e71bbec4..c2dfe026b 100644 --- a/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupBuilder.cs +++ b/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeGroupBuilder.cs @@ -23,7 +23,8 @@ public KeyExchangeDhGroupExchangeGroupBuilder WithSubGroup(BigInteger subGroup) public byte[] Build() { var sshDataStream = new SshDataStream(0); - sshDataStream.WriteByte(KeyExchangeDhGroupExchangeGroup.MessageNumber); + var target = new KeyExchangeDhGroupExchangeGroup(); + sshDataStream.WriteByte(target.MessageNumber); sshDataStream.Write(_safePrime); sshDataStream.Write(_subGroup); return sshDataStream.ToArray(); diff --git a/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs b/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs index 81714f368..f257e6de3 100644 --- a/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs +++ b/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeReplyBuilder.cs @@ -41,7 +41,8 @@ public KeyExchangeDhGroupExchangeReplyBuilder WithSignature(byte[] signature) public byte[] Build() { var sshDataStream = new SshDataStream(0); - sshDataStream.WriteByte(KeyExchangeDhGroupExchangeReply.MessageNumber); + var target = new KeyExchangeDhGroupExchangeReply(); + sshDataStream.WriteByte(target.MessageNumber); sshDataStream.Write((uint)(4 + _hostKeyAlgorithm.Length + _hostKeys.Length)); sshDataStream.Write((uint) _hostKeyAlgorithm.Length); sshDataStream.Write(_hostKeyAlgorithm, 0, _hostKeyAlgorithm.Length); diff --git a/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs b/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs index 0120c5550..da1d04976 100644 --- a/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Messages/Transport/KeyExchangeDhGroupExchangeRequestTest.cs @@ -46,7 +46,7 @@ public void Test_KeyExchangeDhGroupExchangeRequest_GetBytes() var sshDataStream = new SshDataStream(bytes); - Assert.AreEqual(KeyExchangeDhGroupExchangeRequest.MessageNumber, sshDataStream.ReadByte()); + Assert.AreEqual(request.MessageNumber, sshDataStream.ReadByte()); Assert.AreEqual(_minimum, sshDataStream.ReadUInt32()); Assert.AreEqual(_preferred, sshDataStream.ReadUInt32()); Assert.AreEqual(_maximum, sshDataStream.ReadUInt32()); diff --git a/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs index 3c1c2fdcf..7fa1ac24e 100644 --- a/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs +++ b/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs @@ -244,11 +244,12 @@ public static ServiceAcceptMessageBuilder Create(ServiceName serviceName) public byte[] Build() { var serviceName = _serviceName.ToArray(); + var target = new ServiceAcceptMessage(); var sshDataStream = new SshDataStream(4 + 1 + 1 + 4 + serviceName.Length); sshDataStream.Write((uint)(sshDataStream.Capacity - 4)); // packet length sshDataStream.WriteByte(0); // padding length - sshDataStream.WriteByte(ServiceAcceptMessage.MessageNumber); + sshDataStream.WriteByte(target.MessageNumber); sshDataStream.WriteBinary(serviceName); return sshDataStream.ToArray(); } diff --git a/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs index b565fe1fb..96797d727 100644 --- a/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs +++ b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs @@ -222,11 +222,12 @@ public static ServiceAcceptMessageBuilder Create(ServiceName serviceName) public byte[] Build() { var serviceName = _serviceName.ToArray(); + var target = new ServiceAcceptMessage(); var sshDataStream = new SshDataStream(4 + 1 + 1 + 4 + serviceName.Length); sshDataStream.Write((uint)(sshDataStream.Capacity - 4)); // packet length sshDataStream.WriteByte(0); // padding length - sshDataStream.WriteByte(ServiceAcceptMessage.MessageNumber); + sshDataStream.WriteByte(target.MessageNumber); sshDataStream.WriteBinary(serviceName); return sshDataStream.ToArray(); } diff --git a/test/Renci.SshNet.Tests/Properties/AssemblyInfo.cs b/test/Renci.SshNet.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..a3ec2d895 --- /dev/null +++ b/test/Renci.SshNet.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,5 @@ +锘#if NET6_0_OR_GREATER +using System.Diagnostics.CodeAnalysis; + +[assembly: ExcludeFromCodeCoverage] +#endif // NET6_0_OR_GREATER From f4371ffcccd5cecac7193b8af919af0cf2743ce4 Mon Sep 17 00:00:00 2001 From: Jacob Slusser Date: Mon, 11 Dec 2023 01:07:32 -0800 Subject: [PATCH 87/96] Reduces heap allocations for the some byte[] uses (#1272) --- src/Renci.SshNet/Common/SshData.cs | 4 ++-- src/Renci.SshNet/Common/SshDataStream.cs | 28 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/Renci.SshNet/Common/SshData.cs b/src/Renci.SshNet/Common/SshData.cs index 4e7ff0438..f63a6bcb2 100644 --- a/src/Renci.SshNet/Common/SshData.cs +++ b/src/Renci.SshNet/Common/SshData.cs @@ -221,7 +221,7 @@ protected ushort ReadUInt16() /// Attempt to read past the end of the stream. protected uint ReadUInt32() { - return Pack.BigEndianToUInt32(ReadBytes(4)); + return _stream.ReadUInt32(); } /// @@ -233,7 +233,7 @@ protected uint ReadUInt32() /// Attempt to read past the end of the stream. protected ulong ReadUInt64() { - return Pack.BigEndianToUInt64(ReadBytes(8)); + return _stream.ReadUInt64(); } /// diff --git a/src/Renci.SshNet/Common/SshDataStream.cs b/src/Renci.SshNet/Common/SshDataStream.cs index 6bad5f21f..715ef29e4 100644 --- a/src/Renci.SshNet/Common/SshDataStream.cs +++ b/src/Renci.SshNet/Common/SshDataStream.cs @@ -188,8 +188,14 @@ public BigInteger ReadBigInt() /// public uint ReadUInt32() { +#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER + Span span = stackalloc byte[4]; + ReadBytes(span); + return System.Buffers.Binary.BinaryPrimitives.ReadUInt32BigEndian(span); +#else var data = ReadBytes(4); return Pack.BigEndianToUInt32(data); +#endif // NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER } /// @@ -200,8 +206,14 @@ public uint ReadUInt32() /// public ulong ReadUInt64() { +#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER + Span span = stackalloc byte[8]; + ReadBytes(span); + return System.Buffers.Binary.BinaryPrimitives.ReadUInt64BigEndian(span); +#else var data = ReadBytes(8); return Pack.BigEndianToUInt64(data); +#endif // NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER } /// @@ -264,5 +276,21 @@ private byte[] ReadBytes(int length) return data; } + +#if NETSTANDARD2_1 || NET6_0_OR_GREATER + /// + /// Reads data into the specified . + /// + /// The buffer to read into. + /// is larger than the total of bytes available. + private void ReadBytes(Span buffer) + { + var bytesRead = Read(buffer); + if (bytesRead < buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(buffer), string.Format(CultureInfo.InvariantCulture, "The requested length ({0}) is greater than the actual number of bytes read ({1}).", buffer.Length, bytesRead)); + } + } +#endif // NETSTANDARD2_1 || NET6_0_OR_GREATER } } From 326ce14c4caff3fdb8bc6bf4c29eeb535890dbcb Mon Sep 17 00:00:00 2001 From: Scott Xu Date: Fri, 15 Dec 2023 23:54:57 +0800 Subject: [PATCH 88/96] Maintain current build solution (#1268) * Add .NET 8.0 to current build project. Add dependency **Microsoft.Bcl.AsyncInterfaces** for net462 and netstandard2.0 for current nuget spec * Remove last new line * Tabify --- build/build.proj | 4 ++++ build/nuget/SSH.NET.nuspec | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/build/build.proj b/build/build.proj index 97b406cf6..00dc2dc12 100644 --- a/build/build.proj +++ b/build/build.proj @@ -37,6 +37,10 @@ Renci.SshNet\bin\$(Configuration)\net7.0 net7.0 + + Renci.SshNet\bin\$(Configuration)\net8.0 + net8.0 + diff --git a/build/nuget/SSH.NET.nuspec b/build/nuget/SSH.NET.nuspec index fec2d2fcf..18f62f056 100644 --- a/build/nuget/SSH.NET.nuspec +++ b/build/nuget/SSH.NET.nuspec @@ -16,8 +16,11 @@ en-US ssh scp sftp - + + + + From 34b5123f0a551e77fba62dcaf0d81d38274bf6cf Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Thu, 21 Dec 2023 05:54:32 +0000 Subject: [PATCH 89/96] Send the client key exchange init in Connect (#1274) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Send the client key exchange init in Connect * Add a test --------- Co-authored-by: Wojciech Nag贸rski --- src/Renci.SshNet/Security/IKeyExchange.cs | 5 +- src/Renci.SshNet/Security/KeyExchange.cs | 13 ++- .../Security/KeyExchangeDiffieHellman.cs | 10 +-- ...changeDiffieHellmanGroupExchangeShaBase.cs | 10 +-- .../KeyExchangeDiffieHellmanGroupShaBase.cs | 10 +-- src/Renci.SshNet/Security/KeyExchangeEC.cs | 10 +-- .../Security/KeyExchangeECCurve25519.cs | 10 +-- src/Renci.SshNet/Security/KeyExchangeECDH.cs | 10 +-- src/Renci.SshNet/Session.cs | 44 ++++++----- .../Classes/SessionTest_ConnectedBase.cs | 79 ++++++++++++------- ...Connected_ServerAndClientDisconnectRace.cs | 16 ++-- ...Test_Connected_ServerDoesNotSendKexInit.cs | 24 ++++++ 12 files changed, 135 insertions(+), 106 deletions(-) create mode 100644 test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerDoesNotSendKexInit.cs diff --git a/src/Renci.SshNet/Security/IKeyExchange.cs b/src/Renci.SshNet/Security/IKeyExchange.cs index f12a18322..7ffd2f465 100644 --- a/src/Renci.SshNet/Security/IKeyExchange.cs +++ b/src/Renci.SshNet/Security/IKeyExchange.cs @@ -38,8 +38,9 @@ public interface IKeyExchange : IDisposable /// Starts the key exchange algorithm. /// /// The session. - /// Key exchange init message. - void Start(Session session, KeyExchangeInitMessage message); + /// The key exchange init message received from the server. + /// Whether to send a key exchange init message in response. + void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage); /// /// Finishes the key exchange algorithm. diff --git a/src/Renci.SshNet/Security/KeyExchange.cs b/src/Renci.SshNet/Security/KeyExchange.cs index 44684a92e..f01a4b117 100644 --- a/src/Renci.SshNet/Security/KeyExchange.cs +++ b/src/Renci.SshNet/Security/KeyExchange.cs @@ -61,16 +61,15 @@ public byte[] ExchangeHash /// public event EventHandler HostKeyReceived; - /// - /// Starts key exchange algorithm. - /// - /// The session. - /// Key exchange init message. - public virtual void Start(Session session, KeyExchangeInitMessage message) + /// + public virtual void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) { Session = session; - SendMessage(session.ClientInitMessage); + if (sendClientInitMessage) + { + SendMessage(session.ClientInitMessage); + } // Determine encryption algorithm var clientEncryptionAlgorithmName = (from b in session.ConnectionInfo.Encryptions.Keys diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs index 4f31514a7..7dfc51e34 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellman.cs @@ -76,14 +76,10 @@ protected override bool ValidateExchangeHash() return ValidateExchangeHash(_hostKey, _signature); } - /// - /// Starts key exchange algorithm. - /// - /// The session. - /// Key exchange init message. - public override void Start(Session session, KeyExchangeInitMessage message) + /// + public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) { - base.Start(session, message); + base.Start(session, message, sendClientInitMessage); _serverPayload = message.GetBytes(); _clientPayload = Session.ClientInitMessage.GetBytes(); diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs index 93703ee8f..5774f2c34 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupExchangeShaBase.cs @@ -39,14 +39,10 @@ protected override byte[] CalculateHash() return Hash(groupExchangeHashData.GetBytes()); } - /// - /// Starts key exchange algorithm. - /// - /// The session. - /// Key exchange init message. - public override void Start(Session session, KeyExchangeInitMessage message) + /// + public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) { - base.Start(session, message); + base.Start(session, message, sendClientInitMessage); // Register SSH_MSG_KEX_DH_GEX_GROUP message Session.RegisterMessage("SSH_MSG_KEX_DH_GEX_GROUP"); diff --git a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs index 63c2bba40..b0db30eaa 100644 --- a/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs +++ b/src/Renci.SshNet/Security/KeyExchangeDiffieHellmanGroupShaBase.cs @@ -13,14 +13,10 @@ internal abstract class KeyExchangeDiffieHellmanGroupShaBase : KeyExchangeDiffie /// public abstract BigInteger GroupPrime { get; } - /// - /// Starts key exchange algorithm. - /// - /// The session. - /// Key exchange init message. - public override void Start(Session session, KeyExchangeInitMessage message) + /// + public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) { - base.Start(session, message); + base.Start(session, message, sendClientInitMessage); Session.RegisterMessage("SSH_MSG_KEXDH_REPLY"); diff --git a/src/Renci.SshNet/Security/KeyExchangeEC.cs b/src/Renci.SshNet/Security/KeyExchangeEC.cs index 4368affbf..8bc61e7fc 100644 --- a/src/Renci.SshNet/Security/KeyExchangeEC.cs +++ b/src/Renci.SshNet/Security/KeyExchangeEC.cs @@ -78,14 +78,10 @@ protected override bool ValidateExchangeHash() return ValidateExchangeHash(_hostKey, _signature); } - /// - /// Starts key exchange algorithm. - /// - /// The session. - /// Key exchange init message. - public override void Start(Session session, KeyExchangeInitMessage message) + /// + public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) { - base.Start(session, message); + base.Start(session, message, sendClientInitMessage); _serverPayload = message.GetBytes(); _clientPayload = Session.ClientInitMessage.GetBytes(); diff --git a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs index 18443fe73..c6c060bab 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECCurve25519.cs @@ -29,14 +29,10 @@ protected override int HashSize get { return 256; } } - /// - /// Starts key exchange algorithm. - /// - /// The session. - /// Key exchange init message. - public override void Start(Session session, KeyExchangeInitMessage message) + /// + public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) { - base.Start(session, message); + base.Start(session, message, sendClientInitMessage); Session.RegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); diff --git a/src/Renci.SshNet/Security/KeyExchangeECDH.cs b/src/Renci.SshNet/Security/KeyExchangeECDH.cs index c3fc7bfe4..c756fb6cb 100644 --- a/src/Renci.SshNet/Security/KeyExchangeECDH.cs +++ b/src/Renci.SshNet/Security/KeyExchangeECDH.cs @@ -24,14 +24,10 @@ internal abstract class KeyExchangeECDH : KeyExchangeEC private ECDHCBasicAgreement _keyAgreement; private ECDomainParameters _domainParameters; - /// - /// Starts key exchange algorithm. - /// - /// The session. - /// Key exchange init message. - public override void Start(Session session, KeyExchangeInitMessage message) + /// + public override void Start(Session session, KeyExchangeInitMessage message, bool sendClientInitMessage) { - base.Start(session, message); + base.Start(session, message, sendClientInitMessage); Session.RegisterMessage("SSH_MSG_KEX_ECDH_REPLY"); diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index 5bf6d8eef..a57d5a1e7 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -160,12 +160,7 @@ public class Session : ISession /// /// WaitHandle to signal that key exchange was completed. /// - private EventWaitHandle _keyExchangeCompletedWaitHandle = new ManualResetEvent(initialState: false); - - /// - /// WaitHandle to signal that key exchange is in progress. - /// - private bool _keyExchangeInProgress; + private ManualResetEventSlim _keyExchangeCompletedWaitHandle = new ManualResetEventSlim(initialState: false); /// /// Exception that need to be thrown by waiting thread. @@ -643,6 +638,11 @@ public void Connect() // Some server implementations might sent this message first, prior to establishing encryption algorithm RegisterMessage("SSH_MSG_USERAUTH_BANNER"); + // Send our key exchange init. + // We need to do this before starting the message listener to avoid the case where we receive the server + // key exchange init and we continue the key exchange before having sent our own init. + SendMessage(ClientInitMessage); + // Mark the message listener threads as started _ = _messageListenerCompleted.Reset(); @@ -651,7 +651,7 @@ public void Connect() _ = ThreadAbstraction.ExecuteThreadLongRunning(MessageListener); // Wait for key exchange to be completed - WaitOnHandle(_keyExchangeCompletedWaitHandle); + WaitOnHandle(_keyExchangeCompletedWaitHandle.WaitHandle); // If sessionId is not set then its not connected if (SessionId is null) @@ -757,6 +757,11 @@ public async Task ConnectAsync(CancellationToken cancellationToken) // Some server implementations might sent this message first, prior to establishing encryption algorithm RegisterMessage("SSH_MSG_USERAUTH_BANNER"); + // Send our key exchange init. + // We need to do this before starting the message listener to avoid the case where we receive the server + // key exchange init and we continue the key exchange before having sent our own init. + SendMessage(ClientInitMessage); + // Mark the message listener threads as started _ = _messageListenerCompleted.Reset(); @@ -765,7 +770,7 @@ public async Task ConnectAsync(CancellationToken cancellationToken) _ = ThreadAbstraction.ExecuteThreadLongRunning(MessageListener); // Wait for key exchange to be completed - WaitOnHandle(_keyExchangeCompletedWaitHandle); + WaitOnHandle(_keyExchangeCompletedWaitHandle.WaitHandle); // If sessionId is not set then its not connected if (SessionId is null) @@ -1046,10 +1051,10 @@ internal void SendMessage(Message message) throw new SshConnectionException("Client not connected."); } - if (_keyExchangeInProgress && message is not IKeyExchangedAllowed) + if (!_keyExchangeCompletedWaitHandle.IsSet && message is not IKeyExchangedAllowed) { // Wait for key exchange to be completed - WaitOnHandle(_keyExchangeCompletedWaitHandle); + WaitOnHandle(_keyExchangeCompletedWaitHandle.WaitHandle); } DiagnosticAbstraction.Log(string.Format("[{0}] Sending message '{1}' to server: '{2}'.", ToHex(SessionId), message.GetType().Name, message)); @@ -1394,9 +1399,15 @@ internal void OnKeyExchangeDhGroupExchangeReplyReceived(KeyExchangeDhGroupExchan /// message. internal void OnKeyExchangeInitReceived(KeyExchangeInitMessage message) { - _keyExchangeInProgress = true; + // If _keyExchangeCompletedWaitHandle is already set, then this is a key + // re-exchange initiated by the server, and we need to send our own init + // message. + // Otherwise, the wait handle is not set and this received init is part of the + // initial connection for which we have already sent our init, so we shouldn't + // send another one. + var sendClientInitMessage = _keyExchangeCompletedWaitHandle.IsSet; - _ = _keyExchangeCompletedWaitHandle.Reset(); + _keyExchangeCompletedWaitHandle.Reset(); // Disable messages that are not key exchange related _sshMessageFactory.DisableNonKeyExchangeMessages(); @@ -1411,7 +1422,7 @@ internal void OnKeyExchangeInitReceived(KeyExchangeInitMessage message) _keyExchange.HostKeyReceived += KeyExchange_HostKeyReceived; // Start the algorithm implementation - _keyExchange.Start(this, message); + _keyExchange.Start(this, message, sendClientInitMessage); KeyExchangeInitReceived?.Invoke(this, new MessageEventArgs(message)); } @@ -1477,9 +1488,7 @@ internal void OnNewKeysReceived(NewKeysMessage message) NewKeysReceived?.Invoke(this, new MessageEventArgs(message)); // Signal that key exchange completed - _ = _keyExchangeCompletedWaitHandle.Set(); - - _keyExchangeInProgress = false; + _keyExchangeCompletedWaitHandle.Set(); } /// @@ -1967,7 +1976,7 @@ private void RaiseError(Exception exp) private void Reset() { _ = _exceptionWaitHandle?.Reset(); - _ = _keyExchangeCompletedWaitHandle?.Reset(); + _keyExchangeCompletedWaitHandle?.Reset(); _ = _messageListenerCompleted?.Set(); SessionId = null; @@ -1975,7 +1984,6 @@ private void Reset() _isDisconnecting = false; _isAuthenticated = false; _exception = null; - _keyExchangeInProgress = false; } private static SshConnectionException CreateConnectionAbortedByServerException() diff --git a/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs index 7fa1ac24e..6331f7b9c 100644 --- a/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs +++ b/test/Renci.SshNet.Tests/Classes/SessionTest_ConnectedBase.cs @@ -49,6 +49,12 @@ public abstract class SessionTest_ConnectedBase internal SshIdentification ServerIdentification { get; set; } protected bool CallSessionConnectWhenArrange { get; set; } + /// + /// Should the "server" wait for the client kexinit before sending its own. + /// A regression test simulating e.g. cisco devices. + /// + protected bool WaitForClientKeyExchangeInit { get; set; } + [TestInitialize] public void Setup() { @@ -59,18 +65,18 @@ public void Setup() [TestCleanup] public void TearDown() { - if (ServerSocket != null) - { - ServerSocket.Dispose(); - ServerSocket = null; - } - if (ServerListener != null) { ServerListener.Dispose(); ServerListener = null; } + if (ServerSocket != null) + { + ServerSocket.Dispose(); + ServerSocket = null; + } + if (Session != null) { Session.Dispose(); @@ -115,6 +121,15 @@ protected virtual void SetupData() var newKeysMessage = new NewKeysMessage(); var newKeys = newKeysMessage.GetPacket(8, null); _ = ServerSocket.Send(newKeys, 4, newKeys.Length - 4, SocketFlags.None); + + if (!_authenticationStarted) + { + var serviceAcceptMessage = ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication) + .Build(); + _ = ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None); + + _authenticationStarted = true; + } }; ServerListener = new AsyncSocketListener(_serverEndPoint) @@ -125,36 +140,23 @@ protected virtual void SetupData() { ServerSocket = socket; - // Since we're mocking the protocol version exchange, we'll immediately stat KEX upon + // Since we're mocking the protocol version exchange, we'll immediately start KEX upon // having established the connection instead of when the client has been identified - var keyExchangeInitMessage = new KeyExchangeInitMessage - { - CompressionAlgorithmsClientToServer = new string[0], - CompressionAlgorithmsServerToClient = new string[0], - EncryptionAlgorithmsClientToServer = new string[0], - EncryptionAlgorithmsServerToClient = new string[0], - KeyExchangeAlgorithms = new[] { _keyExchangeAlgorithm }, - LanguagesClientToServer = new string[0], - LanguagesServerToClient = new string[0], - MacAlgorithmsClientToServer = new string[0], - MacAlgorithmsServerToClient = new string[0], - ServerHostKeyAlgorithms = new string[0] - }; - var keyExchangeInit = keyExchangeInitMessage.GetPacket(8, null); - _ = ServerSocket.Send(keyExchangeInit, 4, keyExchangeInit.Length - 4, SocketFlags.None); + if (!WaitForClientKeyExchangeInit) + { + SendKeyExchangeInit(); + } }; ServerListener.BytesReceived += (received, socket) => { ServerBytesReceivedRegister.Add(received); - if (!_authenticationStarted) + if (WaitForClientKeyExchangeInit && received.Length > 5 && received[5] == 20) { - var serviceAcceptMessage = ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication) - .Build(); - _ = ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None); - - _authenticationStarted = true; + // This is the KEXINIT. Send one back. + SendKeyExchangeInit(); + WaitForClientKeyExchangeInit = false; } }; ServerListener.Start(); @@ -162,6 +164,25 @@ protected virtual void SetupData() ClientSocket = new DirectConnector(_socketFactory).Connect(ConnectionInfo); CallSessionConnectWhenArrange = true; + + void SendKeyExchangeInit() + { + var keyExchangeInitMessage = new KeyExchangeInitMessage + { + CompressionAlgorithmsClientToServer = new string[0], + CompressionAlgorithmsServerToClient = new string[0], + EncryptionAlgorithmsClientToServer = new string[0], + EncryptionAlgorithmsServerToClient = new string[0], + KeyExchangeAlgorithms = new[] { _keyExchangeAlgorithm }, + LanguagesClientToServer = new string[0], + LanguagesServerToClient = new string[0], + MacAlgorithmsClientToServer = new string[0], + MacAlgorithmsServerToClient = new string[0], + ServerHostKeyAlgorithms = new string[0] + }; + var keyExchangeInit = keyExchangeInitMessage.GetPacket(8, null); + _ = ServerSocket.Send(keyExchangeInit, 4, keyExchangeInit.Length - 4, SocketFlags.None); + } } private void CreateMocks() @@ -187,7 +208,7 @@ private void SetupMocks() _ = ServiceFactoryMock.Setup(p => p.CreateKeyExchange(ConnectionInfo.KeyExchangeAlgorithms, new[] { _keyExchangeAlgorithm })).Returns(_keyExchangeMock.Object); _ = _keyExchangeMock.Setup(p => p.Name) .Returns(_keyExchangeAlgorithm); - _ = _keyExchangeMock.Setup(p => p.Start(Session, It.IsAny())); + _ = _keyExchangeMock.Setup(p => p.Start(Session, It.IsAny(), false)); _ = _keyExchangeMock.Setup(p => p.ExchangeHash) .Returns(SessionId); _ = _keyExchangeMock.Setup(p => p.CreateServerCipher()) diff --git a/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs index 96797d727..11cda2d90 100644 --- a/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs +++ b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerAndClientDisconnectRace.cs @@ -89,6 +89,13 @@ protected virtual void SetupData() var newKeysMessage = new NewKeysMessage(); var newKeys = newKeysMessage.GetPacket(8, null); _ = ServerSocket.Send(newKeys, 4, newKeys.Length - 4, SocketFlags.None); + + if (!_authenticationStarted) + { + var serviceAcceptMessage = ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication).Build(); + _ = ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None); + _authenticationStarted = true; + } }; ServerListener = new AsyncSocketListener(_serverEndPoint); @@ -118,13 +125,6 @@ protected virtual void SetupData() ServerListener.BytesReceived += (received, socket) => { ServerBytesReceivedRegister.Add(received); - - if (!_authenticationStarted) - { - var serviceAcceptMessage =ServiceAcceptMessageBuilder.Create(ServiceName.UserAuthentication).Build(); - _ = ServerSocket.Send(serviceAcceptMessage, 0, serviceAcceptMessage.Length, SocketFlags.None); - _authenticationStarted = true; - } }; ServerListener.Start(); @@ -156,7 +156,7 @@ private void SetupMocks() .Returns(_keyExchangeMock.Object); _ = _keyExchangeMock.Setup(p => p.Name) .Returns(_keyExchangeAlgorithm); - _ = _keyExchangeMock.Setup(p => p.Start(Session, It.IsAny())); + _ = _keyExchangeMock.Setup(p => p.Start(Session, It.IsAny(), false)); _ = _keyExchangeMock.Setup(p => p.ExchangeHash) .Returns(SessionId); _ = _keyExchangeMock.Setup(p => p.CreateServerCipher()) diff --git a/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerDoesNotSendKexInit.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerDoesNotSendKexInit.cs new file mode 100644 index 000000000..44bfa74fd --- /dev/null +++ b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected_ServerDoesNotSendKexInit.cs @@ -0,0 +1,24 @@ +锘縰sing Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace Renci.SshNet.Tests.Classes +{ + [TestClass] + public class SessionTest_Connected_ServerDoesNotSendKexInit : SessionTest_ConnectedBase + { + protected override void SetupData() + { + WaitForClientKeyExchangeInit = true; + + base.SetupData(); + } + + protected override void Act() + { + } + + [TestMethod] + public void ConnectShouldSucceed() + { + } + } +} From e998d875e02f4f2bf533d3e3468e509e0ad5f2f7 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Thu, 21 Dec 2023 20:32:20 +0000 Subject: [PATCH 90/96] Add a few spans on net6.0 or greater (#1138) --- src/Renci.SshNet/Common/Extensions.cs | 4 +++ src/Renci.SshNet/Common/SshData.cs | 16 ++---------- src/Renci.SshNet/Common/SshDataStream.cs | 33 ++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/Renci.SshNet/Common/Extensions.cs b/src/Renci.SshNet/Common/Extensions.cs index f364dc9f4..1d6ce3ca1 100644 --- a/src/Renci.SshNet/Common/Extensions.cs +++ b/src/Renci.SshNet/Common/Extensions.cs @@ -221,6 +221,9 @@ public static bool IsEqualTo(this byte[] left, byte[] right) return true; } +#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER + return left.AsSpan().SequenceEqual(right); +#else if (left.Length != right.Length) { return false; @@ -235,6 +238,7 @@ public static bool IsEqualTo(this byte[] left, byte[] right) } return true; +#endif } /// diff --git a/src/Renci.SshNet/Common/SshData.cs b/src/Renci.SshNet/Common/SshData.cs index f63a6bcb2..54b77c6d9 100644 --- a/src/Renci.SshNet/Common/SshData.cs +++ b/src/Renci.SshNet/Common/SshData.cs @@ -155,19 +155,7 @@ protected byte[] ReadBytes() /// is greater than the number of bytes available to be read. protected byte[] ReadBytes(int length) { - var data = new byte[length]; - var bytesRead = _stream.Read(data, 0, length); - -#if NET8_0_OR_GREATER - ArgumentOutOfRangeException.ThrowIfGreaterThan(length, bytesRead); -#else - if (bytesRead < length) - { - throw new ArgumentOutOfRangeException(nameof(length)); - } -#endif - - return data; + return _stream.ReadBytes(length); } /// @@ -209,7 +197,7 @@ protected bool ReadBoolean() /// Attempt to read past the end of the stream. protected ushort ReadUInt16() { - return Pack.BigEndianToUInt16(ReadBytes(2)); + return _stream.ReadUInt16(); } /// diff --git a/src/Renci.SshNet/Common/SshDataStream.cs b/src/Renci.SshNet/Common/SshDataStream.cs index 715ef29e4..9b64bed3a 100644 --- a/src/Renci.SshNet/Common/SshDataStream.cs +++ b/src/Renci.SshNet/Common/SshDataStream.cs @@ -62,8 +62,14 @@ public bool IsEndOfData /// data to write. public void Write(uint value) { +#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER + Span bytes = stackalloc byte[4]; + System.Buffers.Binary.BinaryPrimitives.WriteUInt32BigEndian(bytes, value); + Write(bytes); +#else var bytes = Pack.UInt32ToBigEndian(value); Write(bytes, 0, bytes.Length); +#endif } /// @@ -72,8 +78,14 @@ public void Write(uint value) /// data to write. public void Write(ulong value) { +#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER + Span bytes = stackalloc byte[8]; + System.Buffers.Binary.BinaryPrimitives.WriteUInt64BigEndian(bytes, value); + Write(bytes); +#else var bytes = Pack.UInt64ToBigEndian(value); Write(bytes, 0, bytes.Length); +#endif } /// @@ -180,6 +192,24 @@ public BigInteger ReadBigInt() return new BigInteger(data.Reverse()); } + /// + /// Reads the next data type from the SSH data stream. + /// + /// + /// The read from the SSH data stream. + /// + public ushort ReadUInt16() + { +#if NETSTANDARD2_1_OR_GREATER || NET6_0_OR_GREATER + Span bytes = stackalloc byte[2]; + ReadBytes(bytes); + return System.Buffers.Binary.BinaryPrimitives.ReadUInt16BigEndian(bytes); +#else + var data = ReadBytes(2); + return Pack.BigEndianToUInt16(data); +#endif + } + /// /// Reads the next data type from the SSH data stream. /// @@ -264,11 +294,10 @@ public override byte[] ToArray() /// An array of bytes that was read from the internal buffer. /// /// is greater than the internal buffer size. - private byte[] ReadBytes(int length) + internal byte[] ReadBytes(int length) { var data = new byte[length]; var bytesRead = Read(data, 0, length); - if (bytesRead < length) { throw new ArgumentOutOfRangeException(nameof(length), string.Format(CultureInfo.InvariantCulture, "The requested length ({0}) is greater than the actual number of bytes read ({1}).", length, bytesRead)); From 24838e6173e2a7d4cbb498ce5edc3e32b254ca11 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Thu, 21 Dec 2023 22:12:15 +0000 Subject: [PATCH 91/96] Make keys immutable (#1264) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes it easier to reason about Key instances in e.g. DigitalSignature implementations, because we know that the Key is initialised with its data and will not change. Co-authored-by: Wojciech Nag贸rski --- src/Renci.SshNet/Common/SshData.cs | 2 +- src/Renci.SshNet/Common/SshDataStream.cs | 6 +- src/Renci.SshNet/ConnectionInfo.cs | 16 +- src/Renci.SshNet/PrivateKeyFile.cs | 10 +- .../Security/Cryptography/DsaKey.cs | 107 ++++++----- .../Security/Cryptography/ED25519Key.cs | 68 +++---- .../Security/Cryptography/EcdsaKey.cs | 31 ++-- src/Renci.SshNet/Security/Cryptography/Key.cs | 46 +---- .../Security/Cryptography/RsaKey.cs | 171 ++++++----------- src/Renci.SshNet/Security/KeyHostAlgorithm.cs | 173 +----------------- src/Renci.SshNet/Security/SshKeyData.cs | 98 ++++++++++ .../Common/HostKeyEventArgsBenchmarks.cs | 3 +- .../Ciphers/RsaCipherBenchmarks.cs | 49 ----- .../Cryptography/RsaDigitalSignatureTest.cs | 21 +-- .../Classes/Security/KeyAlgorithmTest.cs | 10 +- 15 files changed, 295 insertions(+), 516 deletions(-) create mode 100644 src/Renci.SshNet/Security/SshKeyData.cs delete mode 100644 test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs diff --git a/src/Renci.SshNet/Common/SshData.cs b/src/Renci.SshNet/Common/SshData.cs index 54b77c6d9..578edb8c5 100644 --- a/src/Renci.SshNet/Common/SshData.cs +++ b/src/Renci.SshNet/Common/SshData.cs @@ -231,7 +231,7 @@ protected ulong ReadUInt64() /// /// The that was read. /// - protected string ReadString(Encoding encoding) + protected string ReadString(Encoding encoding = null) { return _stream.ReadString(encoding); } diff --git a/src/Renci.SshNet/Common/SshDataStream.cs b/src/Renci.SshNet/Common/SshDataStream.cs index 9b64bed3a..9e2a28051 100644 --- a/src/Renci.SshNet/Common/SshDataStream.cs +++ b/src/Renci.SshNet/Common/SshDataStream.cs @@ -249,12 +249,14 @@ public ulong ReadUInt64() /// /// Reads the next data type from the SSH data stream. /// - /// The character encoding to use. + /// The character encoding to use. Defaults to . /// /// The read from the SSH data stream. /// - public string ReadString(Encoding encoding) + public string ReadString(Encoding encoding = null) { + encoding ??= Encoding.UTF8; + var length = ReadUInt32(); if (length > int.MaxValue) diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index 4a24e78a9..7eccb8dff 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -396,16 +396,16 @@ public ConnectionInfo(string host, int port, string username, ProxyTypes proxyTy HostKeyAlgorithms = new Dictionary> { - { "ssh-ed25519", data => new KeyHostAlgorithm("ssh-ed25519", new ED25519Key(), data) }, - { "ecdsa-sha2-nistp256", data => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(), data) }, - { "ecdsa-sha2-nistp384", data => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(), data) }, - { "ecdsa-sha2-nistp521", data => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(), data) }, + { "ssh-ed25519", data => new KeyHostAlgorithm("ssh-ed25519", new ED25519Key(new SshKeyData(data))) }, + { "ecdsa-sha2-nistp256", data => new KeyHostAlgorithm("ecdsa-sha2-nistp256", new EcdsaKey(new SshKeyData(data))) }, + { "ecdsa-sha2-nistp384", data => new KeyHostAlgorithm("ecdsa-sha2-nistp384", new EcdsaKey(new SshKeyData(data))) }, + { "ecdsa-sha2-nistp521", data => new KeyHostAlgorithm("ecdsa-sha2-nistp521", new EcdsaKey(new SshKeyData(data))) }, #pragma warning disable SA1107 // Code should not contain multiple statements on one line - { "rsa-sha2-512", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-512", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); } }, - { "rsa-sha2-256", data => { var key = new RsaKey(); return new KeyHostAlgorithm("rsa-sha2-256", key, data, new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); } }, + { "rsa-sha2-512", data => { var key = new RsaKey(new SshKeyData(data)); return new KeyHostAlgorithm("rsa-sha2-512", key, new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); } }, + { "rsa-sha2-256", data => { var key = new RsaKey(new SshKeyData(data)); return new KeyHostAlgorithm("rsa-sha2-256", key, new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); } }, #pragma warning restore SA1107 // Code should not contain multiple statements on one line - { "ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(), data) }, - { "ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(), data) }, + { "ssh-rsa", data => new KeyHostAlgorithm("ssh-rsa", new RsaKey(new SshKeyData(data))) }, + { "ssh-dss", data => new KeyHostAlgorithm("ssh-dss", new DsaKey(new SshKeyData(data))) }, }; CompressionAlgorithms = new Dictionary diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 1373630cd..a93ffb195 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -573,12 +573,14 @@ private static Key ParseOpenSshV1Key(byte[] keyFileData, string passPhrase) switch (keyType) { case "ssh-ed25519": - // public key - publicKey = privateKeyReader.ReadBignum2(); + // https://datatracker.ietf.org/doc/html/draft-miller-ssh-agent-11#section-3.2.3 - // private key + // ENC(A) + _ = privateKeyReader.ReadBignum2(); + + // k || ENC(A) unencryptedPrivateKey = privateKeyReader.ReadBignum2(); - parsedKey = new ED25519Key(publicKey.Reverse(), unencryptedPrivateKey); + parsedKey = new ED25519Key(unencryptedPrivateKey); break; case "ecdsa-sha2-nistp256": case "ecdsa-sha2-nistp384": diff --git a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs index 65c6fceec..b0f915cc0 100644 --- a/src/Renci.SshNet/Security/Cryptography/DsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/DsaKey.cs @@ -1,4 +1,5 @@ 锘縰sing System; + using Renci.SshNet.Common; using Renci.SshNet.Security.Cryptography; @@ -15,57 +16,27 @@ public class DsaKey : Key, IDisposable /// /// Gets the P. /// - public BigInteger P - { - get - { - return _privateKey[0]; - } - } + public BigInteger P { get; } /// /// Gets the Q. /// - public BigInteger Q - { - get - { - return _privateKey[1]; - } - } + public BigInteger Q { get; } /// /// Gets the G. /// - public BigInteger G - { - get - { - return _privateKey[2]; - } - } + public BigInteger G { get; } /// /// Gets public key Y. /// - public BigInteger Y - { - get - { - return _privateKey[3]; - } - } + public BigInteger Y { get; } /// /// Gets private key X. /// - public BigInteger X - { - get - { - return _privateKey[4]; - } - } + public BigInteger X { get; } /// /// Gets the length of the key. @@ -94,10 +65,16 @@ protected internal override DigitalSignature DigitalSignature } /// - /// Gets or sets the public. + /// Gets the DSA public key. /// /// - /// The public. + /// An array whose values are: + /// + /// 0 + /// 1 + /// 2 + /// 3 + /// /// public override BigInteger[] Public { @@ -105,35 +82,53 @@ public override BigInteger[] Public { return new[] { P, Q, G, Y }; } - set - { - if (value.Length != 4) - { - throw new InvalidOperationException("Invalid public key."); - } - - _privateKey = value; - } } /// /// Initializes a new instance of the class. /// - public DsaKey() + /// The encoded public key data. + public DsaKey(SshKeyData publicKeyData) { - _privateKey = new BigInteger[5]; + if (publicKeyData is null) + { + throw new ArgumentNullException(nameof(publicKeyData)); + } + + if (publicKeyData.Name != "ssh-dss" || publicKeyData.Keys.Length != 4) + { + throw new ArgumentException($"Invalid DSA public key data. ({publicKeyData.Name}, {publicKeyData.Keys.Length}).", nameof(publicKeyData)); + } + + P = publicKeyData.Keys[0]; + Q = publicKeyData.Keys[1]; + G = publicKeyData.Keys[2]; + Y = publicKeyData.Keys[3]; } /// /// Initializes a new instance of the class. /// - /// DER encoded private key data. - public DsaKey(byte[] data) - : base(data) + /// DER encoded private key data. + public DsaKey(byte[] privateKeyData) { - if (_privateKey.Length != 5) + if (privateKeyData is null) + { + throw new ArgumentNullException(nameof(privateKeyData)); + } + + var der = new DerData(privateKeyData); + _ = der.ReadBigInteger(); // skip version + + P = der.ReadBigInteger(); + Q = der.ReadBigInteger(); + G = der.ReadBigInteger(); + Y = der.ReadBigInteger(); + X = der.ReadBigInteger(); + + if (!der.IsEndOfData) { - throw new InvalidOperationException("Invalid private key."); + throw new InvalidOperationException("Invalid private key (expected EOF)."); } } @@ -147,7 +142,11 @@ public DsaKey(byte[] data) /// The x. public DsaKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y, BigInteger x) { - _privateKey = new BigInteger[5] { p, q, g, y, x }; + P = p; + Q = q; + G = g; + Y = y; + X = x; } /// diff --git a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs index bb0037945..5ee2332c0 100644 --- a/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/ED25519Key.cs @@ -11,13 +11,7 @@ namespace Renci.SshNet.Security /// public class ED25519Key : Key, IDisposable { -#pragma warning disable IDE1006 // Naming Styles -#pragma warning disable SX1309 // Field names should begin with underscore - private readonly byte[] privateKey = new byte[Ed25519.ExpandedPrivateKeySizeInBytes]; -#pragma warning restore SX1309 // Field names should begin with underscore -#pragma warning restore IDE1006 // Naming Styles private ED25519DigitalSignature _digitalSignature; - private byte[] _publicKey = new byte[Ed25519.PublicKeySizeInBytes]; private bool _isDisposed; /// @@ -32,20 +26,16 @@ public override string ToString() } /// - /// Gets or sets the public. + /// Gets the Ed25519 public key. /// /// - /// The public. + /// An array with encoded at index 0. /// public override BigInteger[] Public { get { - return new BigInteger[] { _publicKey.ToBigInteger2() }; - } - set - { - _publicKey = value[0].ToByteArray().Reverse().TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + return new BigInteger[] { PublicKey.ToBigInteger2() }; } } @@ -78,52 +68,46 @@ protected internal override DigitalSignature DigitalSignature /// /// Gets the PublicKey Bytes. /// - public byte[] PublicKey - { - get - { - return _publicKey; - } - } + public byte[] PublicKey { get; } /// /// Gets the PrivateKey Bytes. /// - public byte[] PrivateKey - { - get - { - return privateKey; - } - } + public byte[] PrivateKey { get; } /// /// Initializes a new instance of the class. /// - public ED25519Key() + /// The encoded public key data. + public ED25519Key(SshKeyData publicKeyData) { - } + if (publicKeyData is null) + { + throw new ArgumentNullException(nameof(publicKeyData)); + } - /// - /// Initializes a new instance of the class. - /// - /// pk data. - public ED25519Key(byte[] pk) - { - _publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + if (publicKeyData.Name != "ssh-ed25519" || publicKeyData.Keys.Length != 1) + { + throw new ArgumentException($"Invalid Ed25519 public key data ({publicKeyData.Name}, {publicKeyData.Keys.Length}).", nameof(publicKeyData)); + } + + PublicKey = publicKeyData.Keys[0].ToByteArray().Reverse().TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + PrivateKey = new byte[Ed25519.ExpandedPrivateKeySizeInBytes]; } /// /// Initializes a new instance of the class. /// - /// pk data. - /// sk data. - public ED25519Key(byte[] pk, byte[] sk) + /// + /// The private key data k || ENC(A) as described in RFC 8032. + /// + public ED25519Key(byte[] privateKeyData) { - _publicKey = pk.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); var seed = new byte[Ed25519.PrivateKeySeedSizeInBytes]; - Buffer.BlockCopy(sk, 0, seed, 0, seed.Length); - Ed25519.KeyPairFromSeed(out _publicKey, out privateKey, seed); + Buffer.BlockCopy(privateKeyData, 0, seed, 0, seed.Length); + Ed25519.KeyPairFromSeed(out var publicKey, out var privateKey, seed); + PublicKey = publicKey; + PrivateKey = privateKey; } /// diff --git a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs index 455bb1363..7898a92c9 100644 --- a/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/EcdsaKey.cs @@ -140,10 +140,11 @@ protected internal override DigitalSignature DigitalSignature } /// - /// Gets or sets the public. + /// Gets the ECDSA public key. /// /// - /// The public. + /// An array with the ASCII-encoded curve identifier (e.g. "nistp256") + /// at index 0, and the public curve point Q at index 1. /// public override BigInteger[] Public { @@ -213,14 +214,6 @@ public override BigInteger[] Public // returns Curve-Name and x/y as ECPoint return new[] { new BigInteger(curve.Reverse()), new BigInteger(q.Reverse()) }; } - set - { - var curve_s = Encoding.ASCII.GetString(value[0].ToByteArray().Reverse()); - var curve_oid = GetCurveOid(curve_s); - - var publickey = value[1].ToByteArray().Reverse(); - Import(curve_oid, publickey, privatekey: null); - } } /// @@ -236,8 +229,24 @@ public override BigInteger[] Public /// /// Initializes a new instance of the class. /// - public EcdsaKey() + /// The encoded public key data. + public EcdsaKey(SshKeyData publicKeyData) { + if (publicKeyData is null) + { + throw new ArgumentNullException(nameof(publicKeyData)); + } + + if (!publicKeyData.Name.StartsWith("ecdsa-sha2-", StringComparison.Ordinal) || publicKeyData.Keys.Length != 2) + { + throw new ArgumentException($"Invalid ECDSA public key data. ({publicKeyData.Name}, {publicKeyData.Keys.Length}).", nameof(publicKeyData)); + } + + var curve_s = Encoding.ASCII.GetString(publicKeyData.Keys[0].ToByteArray().Reverse()); + var curve_oid = GetCurveOid(curve_s); + + var publickey = publicKeyData.Keys[1].ToByteArray().Reverse(); + Import(curve_oid, publickey, privatekey: null); } /// diff --git a/src/Renci.SshNet/Security/Cryptography/Key.cs b/src/Renci.SshNet/Security/Cryptography/Key.cs index 81580a1ab..54ecac7e4 100644 --- a/src/Renci.SshNet/Security/Cryptography/Key.cs +++ b/src/Renci.SshNet/Security/Cryptography/Key.cs @@ -1,7 +1,4 @@ -锘縰sing System; -using System.Collections.Generic; - -using Renci.SshNet.Common; +锘縰sing Renci.SshNet.Common; using Renci.SshNet.Security.Cryptography; namespace Renci.SshNet.Security @@ -11,25 +8,18 @@ namespace Renci.SshNet.Security /// public abstract class Key { - /// - /// Specifies array of big integers that represent private key. - /// -#pragma warning disable SA1401 // Fields should be private - protected BigInteger[] _privateKey; -#pragma warning restore SA1401 // Fields should be private - /// /// Gets the default digital signature implementation for this key. /// protected internal abstract DigitalSignature DigitalSignature { get; } /// - /// Gets or sets the public key. + /// Gets the public key. /// /// /// The public. /// - public abstract BigInteger[] Public { get; set; } + public abstract BigInteger[] Public { get; } /// /// Gets the length of the key. @@ -44,36 +34,6 @@ public abstract class Key /// public string Comment { get; set; } - /// - /// Initializes a new instance of the class. - /// - /// DER encoded private key data. - protected Key(byte[] data) - { - if (data is null) - { - throw new ArgumentNullException(nameof(data)); - } - - var der = new DerData(data); - _ = der.ReadBigInteger(); // skip version - - var keys = new List(); - while (!der.IsEndOfData) - { - keys.Add(der.ReadBigInteger()); - } - - _privateKey = keys.ToArray(); - } - - /// - /// Initializes a new instance of the class. - /// - protected Key() - { - } - /// /// Signs the specified data with the key. /// diff --git a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs index 19c8bedc7..f342db6c1 100644 --- a/src/Renci.SshNet/Security/Cryptography/RsaKey.cs +++ b/src/Renci.SshNet/Security/Cryptography/RsaKey.cs @@ -1,4 +1,5 @@ 锘縰sing System; + using Renci.SshNet.Common; using Renci.SshNet.Security.Cryptography; @@ -29,13 +30,7 @@ public override string ToString() /// /// The modulus. /// - public BigInteger Modulus - { - get - { - return _privateKey[0]; - } - } + public BigInteger Modulus { get; } /// /// Gets the exponent. @@ -43,13 +38,7 @@ public BigInteger Modulus /// /// The exponent. /// - public BigInteger Exponent - { - get - { - return _privateKey[1]; - } - } + public BigInteger Exponent { get; } /// /// Gets the D. @@ -57,18 +46,7 @@ public BigInteger Exponent /// /// The D. /// - public BigInteger D - { - get - { - if (_privateKey.Length > 2) - { - return _privateKey[2]; - } - - return BigInteger.Zero; - } - } + public BigInteger D { get; } /// /// Gets the P. @@ -76,18 +54,7 @@ public BigInteger D /// /// The P. /// - public BigInteger P - { - get - { - if (_privateKey.Length > 3) - { - return _privateKey[3]; - } - - return BigInteger.Zero; - } - } + public BigInteger P { get; } /// /// Gets the Q. @@ -95,18 +62,7 @@ public BigInteger P /// /// The Q. /// - public BigInteger Q - { - get - { - if (_privateKey.Length > 4) - { - return _privateKey[4]; - } - - return BigInteger.Zero; - } - } + public BigInteger Q { get; } /// /// Gets the DP. @@ -114,18 +70,7 @@ public BigInteger Q /// /// The DP. /// - public BigInteger DP - { - get - { - if (_privateKey.Length > 5) - { - return _privateKey[5]; - } - - return BigInteger.Zero; - } - } + public BigInteger DP { get; } /// /// Gets the DQ. @@ -133,18 +78,7 @@ public BigInteger DP /// /// The DQ. /// - public BigInteger DQ - { - get - { - if (_privateKey.Length > 6) - { - return _privateKey[6]; - } - - return BigInteger.Zero; - } - } + public BigInteger DQ { get; } /// /// Gets the inverse Q. @@ -152,18 +86,7 @@ public BigInteger DQ /// /// The inverse Q. /// - public BigInteger InverseQ - { - get - { - if (_privateKey.Length > 7) - { - return _privateKey[7]; - } - - return BigInteger.Zero; - } - } + public BigInteger InverseQ { get; } /// /// Gets the length of the key. @@ -196,10 +119,11 @@ protected internal override DigitalSignature DigitalSignature } /// - /// Gets or sets the public. + /// Gets the RSA public key. /// /// - /// The public. + /// An array with at index 0, and + /// at index 1. /// public override BigInteger[] Public { @@ -207,34 +131,54 @@ public override BigInteger[] Public { return new[] { Exponent, Modulus }; } - set - { - if (value.Length != 2) - { - throw new InvalidOperationException("Invalid private key."); - } - - _privateKey = new[] { value[1], value[0] }; - } } /// /// Initializes a new instance of the class. /// - public RsaKey() + /// The encoded public key data. + public RsaKey(SshKeyData publicKeyData) { + if (publicKeyData is null) + { + throw new ArgumentNullException(nameof(publicKeyData)); + } + + if (publicKeyData.Name != "ssh-rsa" || publicKeyData.Keys.Length != 2) + { + throw new ArgumentException($"Invalid RSA public key data. ({publicKeyData.Name}, {publicKeyData.Keys.Length}).", nameof(publicKeyData)); + } + + Exponent = publicKeyData.Keys[0]; + Modulus = publicKeyData.Keys[1]; } /// /// Initializes a new instance of the class. /// - /// DER encoded private key data. - public RsaKey(byte[] data) - : base(data) + /// DER encoded private key data. + public RsaKey(byte[] privateKeyData) { - if (_privateKey.Length != 8) + if (privateKeyData is null) { - throw new InvalidOperationException("Invalid private key."); + throw new ArgumentNullException(nameof(privateKeyData)); + } + + var der = new DerData(privateKeyData); + _ = der.ReadBigInteger(); // skip version + + Modulus = der.ReadBigInteger(); + Exponent = der.ReadBigInteger(); + D = der.ReadBigInteger(); + P = der.ReadBigInteger(); + Q = der.ReadBigInteger(); + DP = der.ReadBigInteger(); + DQ = der.ReadBigInteger(); + InverseQ = der.ReadBigInteger(); + + if (!der.IsEndOfData) + { + throw new InvalidOperationException("Invalid private key (expected EOF)."); } } @@ -249,22 +193,19 @@ public RsaKey(byte[] data) /// The inverse Q. public RsaKey(BigInteger modulus, BigInteger exponent, BigInteger d, BigInteger p, BigInteger q, BigInteger inverseQ) { - _privateKey = new BigInteger[8] - { - modulus, - exponent, - d, - p, - q, - PrimeExponent(d, p), - PrimeExponent(d, q), - inverseQ - }; + Modulus = modulus; + Exponent = exponent; + D = d; + P = p; + Q = q; + DP = PrimeExponent(d, p); + DQ = PrimeExponent(d, q); + InverseQ = inverseQ; } private static BigInteger PrimeExponent(BigInteger privateExponent, BigInteger prime) { - var pe = prime - new BigInteger(1); + var pe = prime - BigInteger.One; return privateExponent % pe; } diff --git a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs index 0a0232a58..5611c9713 100644 --- a/src/Renci.SshNet/Security/KeyHostAlgorithm.cs +++ b/src/Renci.SshNet/Security/KeyHostAlgorithm.cs @@ -1,8 +1,6 @@ -锘縰sing System.Collections.Generic; -using System.Text; +锘縰sing System.Text; using Renci.SshNet.Common; -using Renci.SshNet.Security.Chaos.NaCl; using Renci.SshNet.Security.Cryptography; namespace Renci.SshNet.Security @@ -15,17 +13,11 @@ public class KeyHostAlgorithm : HostAlgorithm /// /// Gets the key used in this host key algorithm. /// - /// - /// The key used in this host key algorithm. - /// public Key Key { get; private set; } /// /// Gets the signature implementation used in this host key algorithm. /// - /// - /// The signature implementation used in this host key algorithm. - /// public DigitalSignature DigitalSignature { get; private set; } /// @@ -47,11 +39,7 @@ public override byte[] Data /// Initializes a new instance of the class. /// /// The signature format identifier. - /// - /// - /// This constructor is typically passed a private key in order to create an encoded signature for later - /// verification by the host. - /// + /// The key used in this host key algorithm. public KeyHostAlgorithm(string name, Key key) : base(name) { @@ -63,13 +51,9 @@ public KeyHostAlgorithm(string name, Key key) /// Initializes a new instance of the class. /// /// The signature format identifier. - /// - /// + /// The key used in this host key algorithm. + /// The signature implementation used in this host key algorithm. /// - /// - /// This constructor is typically passed a private key in order to create an encoded signature for later - /// verification by the host. - /// /// The key used by is intended to be equal to . /// This is not verified. /// @@ -80,59 +64,6 @@ public KeyHostAlgorithm(string name, Key key, DigitalSignature digitalSignature) DigitalSignature = digitalSignature; } - /// - /// Initializes a new instance of the class - /// with the given encoded public key data. The data will be decoded into . - /// - /// The signature format identifier. - /// - /// Host key encoded data. - /// - /// This constructor is typically passed a new or reusable instance in - /// order to verify an encoded signature sent by the host, created by the private counterpart - /// to the host's public key, which is encoded in . - /// - public KeyHostAlgorithm(string name, Key key, byte[] data) - : base(name) - { - Key = key; - - var sshKey = new SshKeyData(); - sshKey.Load(data); - Key.Public = sshKey.Keys; - - DigitalSignature = key.DigitalSignature; - } - - /// - /// Initializes a new instance of the class - /// with the given encoded public key data. The data will be decoded into . - /// - /// The signature format identifier. - /// - /// Host key encoded data. - /// - /// - /// - /// This constructor is typically passed a new or reusable instance in - /// order to verify an encoded signature sent by the host, created by the private counterpart - /// to the host's public key, which is encoded in . - /// - /// The key used by is intended to be equal to . - /// This is not verified. - /// - public KeyHostAlgorithm(string name, Key key, byte[] data, DigitalSignature digitalSignature) - : base(name) - { - Key = key; - - var sshKey = new SshKeyData(); - sshKey.Load(data); - Key.Public = sshKey.Keys; - - DigitalSignature = digitalSignature; - } - /// /// Signs and encodes the specified data. /// @@ -162,98 +93,6 @@ public override bool VerifySignature(byte[] data, byte[] signature) return DigitalSignature.Verify(data, signatureData.Signature); } - private sealed class SshKeyData : SshData - { - private byte[] _name; - private List _keys; - - public BigInteger[] Keys - { - get - { - var keys = new BigInteger[_keys.Count]; - - for (var i = 0; i < _keys.Count; i++) - { - var key = _keys[i]; - keys[i] = key.ToBigInteger2(); - } - - return keys; - } - private set - { - _keys = new List(value.Length); - - foreach (var key in value) - { - var keyData = key.ToByteArray().Reverse(); - if (Name == "ssh-ed25519") - { - keyData = keyData.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); - } - - _keys.Add(keyData); - } - } - } - - private string Name - { - get { return Utf8.GetString(_name, 0, _name.Length); } - set { _name = Utf8.GetBytes(value); } - } - - protected override int BufferCapacity - { - get - { - var capacity = base.BufferCapacity; - capacity += 4; // Name length - capacity += _name.Length; // Name - - foreach (var key in _keys) - { - capacity += 4; // Key length - capacity += key.Length; // Key - } - - return capacity; - } - } - - public SshKeyData() - { - } - - public SshKeyData(string name, params BigInteger[] keys) - { - Name = name; - Keys = keys; - } - - protected override void LoadData() - { - _name = ReadBinary(); - _keys = new List(); - - while (!IsEndOfData) - { - _keys.Add(ReadBinary()); - } - } - - protected override void SaveData() - { - WriteBinaryString(_name); - - foreach (var key in _keys) - { - WriteBinaryString(key); - } - } - } - internal sealed class SignatureKeyData : SshData { /// @@ -306,7 +145,7 @@ public SignatureKeyData(string name, byte[] signature) /// protected override void LoadData() { - AlgorithmName = Encoding.UTF8.GetString(ReadBinary()); + AlgorithmName = ReadString(); Signature = ReadBinary(); } @@ -315,7 +154,7 @@ protected override void LoadData() /// protected override void SaveData() { - WriteBinaryString(Encoding.UTF8.GetBytes(AlgorithmName)); + Write(AlgorithmName); WriteBinaryString(Signature); } } diff --git a/src/Renci.SshNet/Security/SshKeyData.cs b/src/Renci.SshNet/Security/SshKeyData.cs new file mode 100644 index 000000000..6a3af835a --- /dev/null +++ b/src/Renci.SshNet/Security/SshKeyData.cs @@ -0,0 +1,98 @@ +锘縰sing System.Collections.Generic; +using System.Text; + +using Renci.SshNet.Common; +using Renci.SshNet.Security.Chaos.NaCl; + +namespace Renci.SshNet.Security +{ + /// + /// Facilitates (de)serializing encoded public key data in the format + /// specified by RFC 4253 section 6.6. + /// + /// + /// See https://datatracker.ietf.org/doc/html/rfc4253#section-6.6. + /// + public sealed class SshKeyData : SshData + { + /// + /// Gets the public key format identifier. + /// + public string Name { get; private set; } + + /// + /// Gets the public key constituents. + /// + public BigInteger[] Keys { get; private set; } + + /// + protected override int BufferCapacity + { + get + { + var capacity = base.BufferCapacity; + capacity += 4; // Name length + capacity += Encoding.UTF8.GetByteCount(Name); // Name + + foreach (var key in Keys) + { + capacity += 4; // Key length + capacity += key.BitLength / 8; // Key + } + + return capacity; + } + } + + /// + /// Initializes a new instance of the class. + /// + /// The encoded public key data. + public SshKeyData(byte[] data) + { + Load(data); + } + + /// + /// Initializes a new instance of the class. + /// + /// The public key format identifer. + /// The public key constituents. + public SshKeyData(string name, BigInteger[] keys) + { + Name = name; + Keys = keys; + } + + /// + protected override void LoadData() + { + Name = ReadString(); + var keys = new List(); + + while (!IsEndOfData) + { + keys.Add(ReadBinary().ToBigInteger2()); + } + + Keys = keys.ToArray(); + } + + /// + protected override void SaveData() + { + Write(Name); + + foreach (var key in Keys) + { + var keyData = key.ToByteArray().Reverse(); + if (Name == "ssh-ed25519") + { + keyData = keyData.TrimLeadingZeros().Pad(Ed25519.PublicKeySizeInBytes); + } + + WriteBinaryString(keyData); + } + } + } +} diff --git a/test/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs index 54900d046..c3b070884 100644 --- a/test/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs +++ b/test/Renci.SshNet.Benchmarks/Common/HostKeyEventArgsBenchmarks.cs @@ -1,6 +1,5 @@ 锘縰sing BenchmarkDotNet.Attributes; -using Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers; using Renci.SshNet.Common; using Renci.SshNet.Security; @@ -18,7 +17,7 @@ public HostKeyEventArgsBenchmarks() } private static KeyHostAlgorithm GetKeyHostAlgorithm() { - using (var s = typeof(RsaCipherBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.RSA.txt")) + using (var s = typeof(HostKeyEventArgsBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.RSA.txt")) { var privateKey = new PrivateKeyFile(s); return (KeyHostAlgorithm) privateKey.HostKeyAlgorithms.First(); diff --git a/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs b/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs deleted file mode 100644 index 13c08edb1..000000000 --- a/test/Renci.SshNet.Benchmarks/Security/Cryptography/Ciphers/RsaCipherBenchmarks.cs +++ /dev/null @@ -1,49 +0,0 @@ -锘縰sing BenchmarkDotNet.Attributes; - -using Renci.SshNet.Security; -using Renci.SshNet.Security.Cryptography.Ciphers; - -namespace Renci.SshNet.Benchmarks.Security.Cryptography.Ciphers -{ - [MemoryDiagnoser] - public class RsaCipherBenchmarks - { - private readonly RsaKey _privateKey; - private readonly RsaKey _publicKey; - private readonly byte[] _data; - - public RsaCipherBenchmarks() - { - _data = new byte[128]; - - Random random = new(Seed: 12345); - random.NextBytes(_data); - - using (var s = typeof(RsaCipherBenchmarks).Assembly.GetManifestResourceStream("Renci.SshNet.Benchmarks.Data.Key.RSA.txt")) - { - - _privateKey = (RsaKey)new PrivateKeyFile(s).Key; - - // The implementations of RsaCipher.Encrypt/Decrypt differ based on whether the supplied RsaKey has private key information - // or only public. So we extract out the public key information to a separate variable. - _publicKey = new RsaKey() - { - Public = _privateKey.Public - }; - } - } - - [Benchmark] - public byte[] Encrypt() - { - return new RsaCipher(_publicKey).Encrypt(_data); - } - - // RSA Decrypt does not work - // [Benchmark] - // public byte[] Decrypt() - // { - // return new RsaCipher(_privateKey).Decrypt(_data); - // } - } -} diff --git a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs index d7558c2c4..acfc16382 100644 --- a/test/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Security/Cryptography/RsaDigitalSignatureTest.cs @@ -57,10 +57,7 @@ public void Sha1_SignAndVerify() //Assert.IsTrue(digitalSignature.Verify(data, signedBytes)); // 'Workaround': use a key with no private key information - var digitalSignaturePublic = new RsaDigitalSignature(new RsaKey() - { - Public = rsaKey.Public - }); + var digitalSignaturePublic = new RsaDigitalSignature(new RsaKey(rsaKey.Modulus, rsaKey.Exponent, default, default, default, default)); Assert.IsTrue(digitalSignaturePublic.Verify(data, signedBytes)); } @@ -101,10 +98,9 @@ public void Sha256_SignAndVerify() //Assert.IsTrue(digitalSignature.Verify(data, signedBytes)); // 'Workaround': use a key with no private key information - var digitalSignaturePublic = new RsaDigitalSignature(new RsaKey() - { - Public = rsaKey.Public - }, HashAlgorithmName.SHA256); + var digitalSignaturePublic = new RsaDigitalSignature( + new RsaKey(rsaKey.Modulus, rsaKey.Exponent, default, default, default, default), + HashAlgorithmName.SHA256); Assert.IsTrue(digitalSignaturePublic.Verify(data, signedBytes)); } @@ -144,10 +140,9 @@ public void Sha512_SignAndVerify() //Assert.IsTrue(digitalSignature.Verify(data, signedBytes)); // 'Workaround': use a key with no private key information - var digitalSignaturePublic = new RsaDigitalSignature(new RsaKey() - { - Public = rsaKey.Public - }, HashAlgorithmName.SHA512); + var digitalSignaturePublic = new RsaDigitalSignature( + new RsaKey(rsaKey.Modulus, rsaKey.Exponent, default, default, default, default), + HashAlgorithmName.SHA512); Assert.IsTrue(digitalSignaturePublic.Verify(data, signedBytes)); } @@ -155,7 +150,7 @@ public void Sha512_SignAndVerify() public void Constructor_InvalidHashAlgorithm_ThrowsArgumentException() { ArgumentException exception = Assert.ThrowsException( - () => new RsaDigitalSignature(new RsaKey(), new HashAlgorithmName("invalid"))); + () => new RsaDigitalSignature(GetRsaKey(), new HashAlgorithmName("invalid"))); Assert.AreEqual("hashAlgorithmName", exception.ParamName); } diff --git a/test/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs b/test/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs index d024c05a6..d41199817 100644 --- a/test/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Security/KeyAlgorithmTest.cs @@ -86,7 +86,7 @@ public void SshRsa_SignAndVerify() CollectionAssert.AreEqual(expectedEncodedSignatureBytes, keyAlgorithm.Sign(data)); - keyAlgorithm = new KeyHostAlgorithm("ssh-rsa", new RsaKey(), GetRsaPublicKeyBytes()); + keyAlgorithm = new KeyHostAlgorithm("ssh-rsa", new RsaKey(new SshKeyData(GetRsaPublicKeyBytes()))); Assert.IsTrue(keyAlgorithm.VerifySignature(data, expectedEncodedSignatureBytes)); } @@ -126,8 +126,8 @@ public void RsaSha256_SignAndVerify() CollectionAssert.AreEqual(expectedEncodedSignatureBytes, keyAlgorithm.Sign(data)); - key = new RsaKey(); - keyAlgorithm = new KeyHostAlgorithm("rsa-sha2-256", key, GetRsaPublicKeyBytes(), new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); + key = new RsaKey(new SshKeyData(GetRsaPublicKeyBytes())); + keyAlgorithm = new KeyHostAlgorithm("rsa-sha2-256", key, new RsaDigitalSignature(key, HashAlgorithmName.SHA256)); Assert.IsTrue(keyAlgorithm.VerifySignature(data, expectedEncodedSignatureBytes)); } @@ -167,8 +167,8 @@ public void RsaSha512_SignAndVerify() CollectionAssert.AreEqual(expectedEncodedSignatureBytes, keyAlgorithm.Sign(data)); - key = new RsaKey(); - keyAlgorithm = new KeyHostAlgorithm("rsa-sha2-512", key, GetRsaPublicKeyBytes(), new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); + key = new RsaKey(new SshKeyData(GetRsaPublicKeyBytes())); + keyAlgorithm = new KeyHostAlgorithm("rsa-sha2-512", key, new RsaDigitalSignature(key, HashAlgorithmName.SHA512)); Assert.IsTrue(keyAlgorithm.VerifySignature(data, expectedEncodedSignatureBytes)); } From b0d01df91f79195658778dd21717369b02150bf1 Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Fri, 22 Dec 2023 07:37:30 +0000 Subject: [PATCH 92/96] Try to stabilise a few tests (#1278) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Try to stabilise a few tests * Fix random 0 buffer sizes --------- Co-authored-by: Wojciech Nag贸rski --- .../OldIntegrationTests/SshCommandTest.cs | 12 ++++-------- test/Renci.SshNet.IntegrationTests/SftpTests.cs | 7 +------ ...est_Dispose_SessionIsConnectedAndChannelIsOpen.cs | 2 ++ ...ForwardedPortRemoteTest_Start_PortNeverStarted.cs | 2 ++ .../Classes/SessionTest_Connected.cs | 6 ++++++ ...tpFileStreamTest_CanRead_Closed_FileAccessRead.cs | 4 ++-- ...eStreamTest_CanRead_Closed_FileAccessReadWrite.cs | 6 +++--- ...pFileStreamTest_CanRead_Closed_FileAccessWrite.cs | 6 +++--- ...FileStreamTest_CanRead_Disposed_FileAccessRead.cs | 6 +++--- ...treamTest_CanRead_Disposed_FileAccessReadWrite.cs | 6 +++--- ...ileStreamTest_CanRead_Disposed_FileAccessWrite.cs | 6 +++--- ...pFileStreamTest_CanWrite_Closed_FileAccessRead.cs | 6 +++--- ...StreamTest_CanWrite_Closed_FileAccessReadWrite.cs | 6 +++--- ...FileStreamTest_CanWrite_Closed_FileAccessWrite.cs | 6 +++--- ...ileStreamTest_CanWrite_Disposed_FileAccessRead.cs | 6 +++--- ...reamTest_CanWrite_Disposed_FileAccessReadWrite.cs | 6 +++--- ...leStreamTest_CanWrite_Disposed_FileAccessWrite.cs | 6 +++--- .../Sftp/SftpFileStreamTest_Close_Disposed.cs | 4 ++-- .../Sftp/SftpFileStreamTest_Close_SessionNotOpen.cs | 4 ++-- .../Sftp/SftpFileStreamTest_Close_SessionOpen.cs | 4 ++-- .../Sftp/SftpFileStreamTest_Dispose_Closed.cs | 4 ++-- .../Sftp/SftpFileStreamTest_Dispose_Disposed.cs | 4 ++-- .../SftpFileStreamTest_Dispose_SessionNotOpen.cs | 4 ++-- .../Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs | 4 ++-- .../Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs | 4 ++-- ...e_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs | 4 ++-- .../Sftp/SftpFileStreamTest_SetLength_Disposed.cs | 4 ++-- .../SftpFileStreamTest_SetLength_SessionNotOpen.cs | 4 ++-- ...treamTest_SetLength_SessionOpen_FIleAccessRead.cs | 4 ++-- ...Test_SetLength_SessionOpen_FIleAccessReadWrite.cs | 4 ++-- ...reamTest_SetLength_SessionOpen_FIleAccessWrite.cs | 4 ++-- 31 files changed, 78 insertions(+), 77 deletions(-) diff --git a/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs index d852a093a..e5e78a762 100644 --- a/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs +++ b/test/Renci.SshNet.IntegrationTests/OldIntegrationTests/SshCommandTest.cs @@ -290,13 +290,11 @@ public void Test_Execute_Command_Asynchronously_With_Callback() { callbackCalled = true; }), null); - while (!asyncResult.IsCompleted) - { - Thread.Sleep(100); - } cmd.EndExecute(asyncResult); + Thread.Sleep(100); + Assert.IsTrue(callbackCalled); client.Disconnect(); @@ -318,13 +316,11 @@ public void Test_Execute_Command_Asynchronously_With_Callback_On_Different_Threa { callbackThreadId = Thread.CurrentThread.ManagedThreadId; }), null); - while (!asyncResult.IsCompleted) - { - Thread.Sleep(100); - } cmd.EndExecute(asyncResult); + Thread.Sleep(100); + Assert.AreNotEqual(currentThreadId, callbackThreadId); client.Disconnect(); diff --git a/test/Renci.SshNet.IntegrationTests/SftpTests.cs b/test/Renci.SshNet.IntegrationTests/SftpTests.cs index e6f40c05e..ee00bb15e 100644 --- a/test/Renci.SshNet.IntegrationTests/SftpTests.cs +++ b/test/Renci.SshNet.IntegrationTests/SftpTests.cs @@ -6230,19 +6230,14 @@ public void Sftp_SetLastWriteTimeUtc() client.Connect(); using var fileStream = new MemoryStream(Encoding.UTF8.GetBytes(testContent)); - var currentTime = DateTime.UtcNow; client.UploadFile(fileStream, testFilePath); try { - var time = client.GetLastWriteTimeUtc(testFilePath); - - DateTimeAssert.AreEqual(currentTime.TruncateToWholeSeconds(), time); - var newTime = new DateTime(1986, 03, 15, 01, 02, 03, 123, DateTimeKind.Utc); client.SetLastWriteTimeUtc(testFilePath, newTime); - time = client.GetLastWriteTimeUtc(testFilePath); + var time = client.GetLastWriteTimeUtc(testFilePath); DateTimeAssert.AreEqual(newTime.TruncateToWholeSeconds(), time); } diff --git a/test/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs b/test/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs index 6ccda5c82..cf6d17bb0 100644 --- a/test/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs +++ b/test/Renci.SshNet.Tests/Classes/Channels/ChannelDirectTcpipTest_Dispose_SessionIsConnectedAndChannelIsOpen.cs @@ -175,6 +175,8 @@ private void Arrange() private void Act() { _channel?.Dispose(); + + Thread.Sleep(200); } [TestMethod] diff --git a/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortNeverStarted.cs b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortNeverStarted.cs index 4b6a420d4..a090f289b 100644 --- a/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortNeverStarted.cs +++ b/test/Renci.SshNet.Tests/Classes/ForwardedPortRemoteTest_Start_PortNeverStarted.cs @@ -122,6 +122,8 @@ public void ForwardedPortShouldAcceptNewConnections() new ForwardedTcpipChannelInfo(_forwardedPort.BoundHost, _forwardedPort.BoundPort, originatorAddress, originatorPort)))); + Thread.Sleep(200); + _sessionMock.Verify(p => p.CreateChannelForwardedTcpip(channelNumber, initialWindowSize, maximumPacketSize), Times.Once); channelMock.Verify(p => p.Bind(It.Is(ep => ep.Address.Equals(_remoteEndpoint.Address) && ep.Port == _remoteEndpoint.Port), _forwardedPort), Times.Once); channelMock.Verify(p => p.Dispose(), Times.Once); diff --git a/test/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs index f841926b4..e4f7f2430 100644 --- a/test/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs +++ b/test/Renci.SshNet.Tests/Classes/SessionTest_Connected.cs @@ -45,6 +45,8 @@ public void IsConnectedShouldReturnTrue() [TestMethod] public void SendMessageShouldSendPacketToServer() { + Thread.Sleep(100); + ServerBytesReceivedRegister.Clear(); Session.SendMessage(_ignoreMessage); @@ -123,6 +125,8 @@ public void ISession_MessageListenerCompletedShouldNotBeSignaled() [TestMethod] public void ISession_SendMessageShouldSendPacketToServer() { + Thread.Sleep(100); + var session = (ISession) Session; ServerBytesReceivedRegister.Clear(); @@ -137,6 +141,8 @@ public void ISession_SendMessageShouldSendPacketToServer() [TestMethod] public void ISession_TrySendMessageShouldSendPacketToServerAndReturnTrue() { + Thread.Sleep(100); + var session = (ISession) Session; ServerBytesReceivedRegister.Clear(); diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs index aaa62c856..87ff5fbec 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessRead.cs @@ -25,8 +25,8 @@ protected override void SetupData() _path = random.Next().ToString(); _handle = GenerateRandom(3, random); _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite.cs index b5b9b8636..2ae877f3b 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessReadWrite.cs @@ -24,9 +24,9 @@ protected override void SetupData() var random = new Random(); _path = random.Next().ToString(); _handle = GenerateRandom(3, random); - _bufferSize = (uint) random.Next(0, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _bufferSize = (uint) random.Next(1, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessWrite.cs index 3817f6bcb..e82b347a2 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessWrite.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Closed_FileAccessWrite.cs @@ -24,9 +24,9 @@ protected override void SetupData() var random = new Random(); _path = random.Next().ToString(); _handle = GenerateRandom(3, random); - _bufferSize = (uint) random.Next(0, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _bufferSize = (uint) random.Next(1, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessRead.cs index bbbcb6243..a1ab8bec8 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessRead.cs @@ -24,9 +24,9 @@ protected override void SetupData() var random = new Random(); _path = random.Next().ToString(); _handle = GenerateRandom(1, random); - _bufferSize = (uint) random.Next(0, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _bufferSize = (uint) random.Next(1, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite.cs index 93736b6fe..97d7df8f4 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessReadWrite.cs @@ -24,9 +24,9 @@ protected override void SetupData() var random = new Random(); _path = random.Next().ToString(); _handle = GenerateRandom(1, random); - _bufferSize = (uint) random.Next(0, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _bufferSize = (uint) random.Next(1, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs index 94d6be78f..d6b4856e1 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanRead_Disposed_FileAccessWrite.cs @@ -24,9 +24,9 @@ protected override void SetupData() var random = new Random(); _path = random.Next().ToString(); _handle = GenerateRandom(1, random); - _bufferSize = (uint) random.Next(0, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _bufferSize = (uint) random.Next(1, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs index 932a88ab5..0105a780f 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessRead.cs @@ -24,9 +24,9 @@ protected override void SetupData() var random = new Random(); _path = random.Next().ToString(); _handle = GenerateRandom(1, random); - _bufferSize = (uint) random.Next(0, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _bufferSize = (uint) random.Next(1, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite.cs index 9253bd763..9dffd925c 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessReadWrite.cs @@ -24,9 +24,9 @@ protected override void SetupData() var random = new Random(); _path = random.Next().ToString(); _handle = GenerateRandom(1, random); - _bufferSize = (uint) random.Next(0, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _bufferSize = (uint) random.Next(1, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessWrite.cs index 0b630d880..c51af38d2 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessWrite.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Closed_FileAccessWrite.cs @@ -24,9 +24,9 @@ protected override void SetupData() var random = new Random(); _path = random.Next().ToString(); _handle = GenerateRandom(1, random); - _bufferSize = (uint) random.Next(0, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _bufferSize = (uint) random.Next(1, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessRead.cs index f13a072ec..8c0f4e143 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessRead.cs @@ -24,9 +24,9 @@ protected override void SetupData() var random = new Random(); _path = random.Next().ToString(); _handle = GenerateRandom(1, random); - _bufferSize = (uint) random.Next(0, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _bufferSize = (uint) random.Next(1, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite.cs index 0f70b8750..b669811dc 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessReadWrite.cs @@ -24,9 +24,9 @@ protected override void SetupData() var random = new Random(); _path = random.Next().ToString(); _handle = GenerateRandom(1, random); - _bufferSize = (uint) random.Next(0, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _bufferSize = (uint) random.Next(1, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs index 4474cafdf..58238385b 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_CanWrite_Disposed_FileAccessWrite.cs @@ -24,9 +24,9 @@ protected override void SetupData() var random = new Random(); _path = random.Next().ToString(); _handle = GenerateRandom(1, random); - _bufferSize = (uint) random.Next(0, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _bufferSize = (uint) random.Next(1, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs index 59a6357b5..ee7d6548f 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_Disposed.cs @@ -24,8 +24,8 @@ protected override void SetupData() _path = random.Next().ToString(); _handle = GenerateRandom(2, random); _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionNotOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionNotOpen.cs index 0d3dc1b22..2d4c6e424 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionNotOpen.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionNotOpen.cs @@ -24,8 +24,8 @@ protected override void SetupData() _path = random.Next().ToString(); _handle = GenerateRandom(2, random); _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs index 8ad19bce6..ce7a09a2d 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Close_SessionOpen.cs @@ -27,8 +27,8 @@ protected override void SetupData() _path = random.Next().ToString(); _handle = GenerateRandom(2, random); _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs index 0c6986242..b194338f1 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Closed.cs @@ -27,8 +27,8 @@ protected override void SetupData() _path = random.Next().ToString(); _handle = GenerateRandom(random.Next(1, 5), random); _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Disposed.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Disposed.cs index 2fccf0483..31b3e0962 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Disposed.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_Disposed.cs @@ -24,8 +24,8 @@ protected override void SetupData() _path = random.Next().ToString(); _handle = GenerateRandom(1, random); _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs index e1aae67bc..27858090c 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionNotOpen.cs @@ -27,8 +27,8 @@ protected override void SetupData() _path = random.Next().ToString(); _handle = GenerateRandom(2, random); _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs index 9429579f0..09fec553a 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Dispose_SessionOpen.cs @@ -28,8 +28,8 @@ protected override void SetupData() _path = random.Next().ToString(CultureInfo.InvariantCulture); _handle = GenerateRandom(2, random); _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs index 7ea748873..1d55e17f4 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_Finalize_SessionOpen.cs @@ -25,8 +25,8 @@ protected override void SetupData() _path = random.Next().ToString(CultureInfo.InvariantCulture); _handle = GenerateRandom(7, random); _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs index 75da00bd7..d3bd505a8 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_ReadByte_ReadMode_NoDataInWriteBufferAndNoDataInReadBuffer_Eof.cs @@ -25,8 +25,8 @@ protected override void SetupData() _path = random.Next().ToString(); _handle = GenerateRandom(1, random); _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); } protected override void SetupMocks() diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Disposed.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Disposed.cs index e49cda8ff..22db2ac45 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Disposed.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_Disposed.cs @@ -31,8 +31,8 @@ protected void Arrange() _path = random.Next().ToString(); _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)}; _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); _sftpSessionMock = new Mock(MockBehavior.Strict); diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionNotOpen.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionNotOpen.cs index 8304db053..a7e707653 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionNotOpen.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionNotOpen.cs @@ -26,8 +26,8 @@ protected override void SetupData() _path = random.Next().ToString(); _handle = GenerateRandom(4, random); _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); _length = random.Next(); } diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessRead.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessRead.cs index 047beb1eb..e93017f53 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessRead.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessRead.cs @@ -26,8 +26,8 @@ protected override void SetupData() _path = random.Next().ToString(); _handle = GenerateRandom(5, random); _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); _length = random.Next(); } diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs index ef89483b3..f18711762 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessReadWrite.cs @@ -44,8 +44,8 @@ protected void Arrange() _path = random.Next().ToString(CultureInfo.InvariantCulture); _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)}; _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); _length = random.Next(); _fileAttributesLastAccessTime = DateTime.UtcNow.AddSeconds(random.Next()); diff --git a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs index 73b5a9536..d741ad1fd 100644 --- a/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs +++ b/test/Renci.SshNet.Tests/Classes/Sftp/SftpFileStreamTest_SetLength_SessionOpen_FIleAccessWrite.cs @@ -44,8 +44,8 @@ protected void Arrange() _path = random.Next().ToString(CultureInfo.InvariantCulture); _handle = new[] {(byte) random.Next(byte.MinValue, byte.MaxValue)}; _bufferSize = (uint) random.Next(1, 1000); - _readBufferSize = (uint) random.Next(0, 1000); - _writeBufferSize = (uint) random.Next(0, 1000); + _readBufferSize = (uint) random.Next(1, 1000); + _writeBufferSize = (uint) random.Next(1, 1000); _length = random.Next(); _fileAttributesLastAccessTime = DateTime.UtcNow.AddSeconds(random.Next()); From e7a64dda97e7572cd89a1edc9dd02aca5a9b4f45 Mon Sep 17 00:00:00 2001 From: Jim Killingsworth Date: Thu, 28 Dec 2023 02:52:00 -0800 Subject: [PATCH 93/96] Fix hung dispose caused by infinite socket timeout (#1280) Co-authored-by: Rob Hague --- src/Renci.SshNet/Session.cs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Renci.SshNet/Session.cs b/src/Renci.SshNet/Session.cs index a57d5a1e7..dab919552 100644 --- a/src/Renci.SshNet/Session.cs +++ b/src/Renci.SshNet/Session.cs @@ -1788,9 +1788,17 @@ internal static string ToHex(byte[] bytes) /// when the value of is obtained. To workaround this issue /// we synchronize reads from the . /// + /// + /// We assume the socket is still connected if the read lock cannot be acquired immediately. + /// In this case, we just return without actually waiting to acquire + /// the lock. We don't want to wait for the read lock if another thread already has it because + /// there are cases where the other thread holding the lock can be waiting indefinitely for + /// a socket read operation to complete. + /// /// private bool IsSocketConnected() { +#pragma warning disable S2222 // Locks should be released on all paths lock (_socketDisposeLock) { if (!_socket.IsConnected()) @@ -1798,12 +1806,22 @@ private bool IsSocketConnected() return false; } - lock (_socketReadLock) + if (!Monitor.TryEnter(_socketReadLock)) + { + return true; + } + + try { var connectionClosedOrDataAvailable = _socket.Poll(0, SelectMode.SelectRead); return !(connectionClosedOrDataAvailable && _socket.Available == 0); } + finally + { + Monitor.Exit(_socketReadLock); + } } +#pragma warning restore S2222 // Locks should be released on all paths } /// From 2b53e462dd77fd41978e05a6dff475c999e7424e Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Thu, 28 Dec 2023 19:55:07 +0000 Subject: [PATCH 94/96] Authenticate with ssh-rsa by default (#1283) --- src/Renci.SshNet/PrivateKeyFile.cs | 6 +++--- .../Classes/Common/HostKeyEventArgsTest.cs | 2 +- test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs | 8 +++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index a93ffb195..9f6d728bc 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -250,11 +250,11 @@ private void Open(Stream privateKey, string passPhrase) case "RSA": var rsaKey = new RsaKey(decryptedData); _key = rsaKey; + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); #pragma warning disable CA2000 // Dispose objects before losing scope _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA512))); _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(rsaKey, HashAlgorithmName.SHA256))); #pragma warning restore CA2000 // Dispose objects before losing scope - _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); break; case "DSA": _key = new DsaKey(decryptedData); @@ -268,11 +268,11 @@ private void Open(Stream privateKey, string passPhrase) _key = ParseOpenSshV1Key(decryptedData, passPhrase); if (_key is RsaKey parsedRsaKey) { + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); #pragma warning disable CA2000 // Dispose objects before losing scope _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA512))); _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(parsedRsaKey, HashAlgorithmName.SHA256))); #pragma warning restore CA2000 // Dispose objects before losing scope - _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); } else { @@ -337,11 +337,11 @@ private void Open(Stream privateKey, string passPhrase) var p = reader.ReadBigIntWithBits(); // q var decryptedRsaKey = new RsaKey(modulus, exponent, d, p, q, inverseQ); _key = decryptedRsaKey; + _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); #pragma warning disable CA2000 // Dispose objects before losing scope _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-512", _key, new RsaDigitalSignature(decryptedRsaKey, HashAlgorithmName.SHA512))); _hostAlgorithms.Add(new KeyHostAlgorithm("rsa-sha2-256", _key, new RsaDigitalSignature(decryptedRsaKey, HashAlgorithmName.SHA256))); #pragma warning restore CA2000 // Dispose objects before losing scope - _hostAlgorithms.Add(new KeyHostAlgorithm("ssh-rsa", _key)); } else if (keyType == "dl-modp{sign{dsa-nist-sha1},dh{plain}}") { diff --git a/test/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs b/test/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs index f3d0ae55b..84d899f8c 100644 --- a/test/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs +++ b/test/Renci.SshNet.Tests/Classes/Common/HostKeyEventArgsTest.cs @@ -88,7 +88,7 @@ private static KeyHostAlgorithm GetKeyHostAlgorithm() using (var s = GetData("Key.RSA.txt")) { var privateKey = new PrivateKeyFile(s); - return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.First(); + return (KeyHostAlgorithm)privateKey.HostKeyAlgorithms.Single(x => x.Name == "rsa-sha2-512"); } } diff --git a/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs b/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs index c536dc5c1..dfd02044a 100644 --- a/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs +++ b/test/Renci.SshNet.Tests/Classes/PrivateKeyFileTest.cs @@ -687,9 +687,11 @@ private static void TestRsaKeyFile(PrivateKeyFile rsaPrivateKeyFile) var algorithms = rsaPrivateKeyFile.HostKeyAlgorithms.ToList(); - Assert.AreEqual("rsa-sha2-512", algorithms[0].Name); - Assert.AreEqual("rsa-sha2-256", algorithms[1].Name); - Assert.AreEqual("ssh-rsa", algorithms[2].Name); + // ssh-rsa should be attempted first during authentication by default. + // See https://github.com/sshnet/SSH.NET/issues/1233#issuecomment-1871196405 + Assert.AreEqual("ssh-rsa", algorithms[0].Name); + Assert.AreEqual("rsa-sha2-512", algorithms[1].Name); + Assert.AreEqual("rsa-sha2-256", algorithms[2].Name); } } } From 4c2dcd56134f75c0f40c6470805e9ca737e22f9b Mon Sep 17 00:00:00 2001 From: Rob Hague Date: Fri, 29 Dec 2023 04:06:50 +0000 Subject: [PATCH 95/96] Upgrade packages (#1279) --- Directory.Build.props | 5 ++--- build/nuget/SSH.NET.nuspec | 4 ++-- src/Renci.SshNet/Renci.SshNet.csproj | 2 +- test/.editorconfig | 5 +++++ test/Renci.SshNet.IntegrationTests/HostConfig.cs | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index de4ae8456..639770b43 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -34,9 +34,8 @@ Use fixed version of analyzers. --> - - + - + diff --git a/build/nuget/SSH.NET.nuspec b/build/nuget/SSH.NET.nuspec index 18f62f056..50074d866 100644 --- a/build/nuget/SSH.NET.nuspec +++ b/build/nuget/SSH.NET.nuspec @@ -17,10 +17,10 @@ ssh scp sftp - + - + diff --git a/src/Renci.SshNet/Renci.SshNet.csproj b/src/Renci.SshNet/Renci.SshNet.csproj index 41d725344..877b3b891 100644 --- a/src/Renci.SshNet/Renci.SshNet.csproj +++ b/src/Renci.SshNet/Renci.SshNet.csproj @@ -14,7 +14,7 @@ - + diff --git a/test/.editorconfig b/test/.editorconfig index d6a4af76e..d04fb3f83 100644 --- a/test/.editorconfig +++ b/test/.editorconfig @@ -130,6 +130,11 @@ dotnet_diagnostic.CA1711.severity = none # We do not care about this for unit tests. dotnet_diagnostic.CA1720.severity = none +# CA1861: Avoid constant arrays as arguments +# +# We do not care about this for unit tests. +dotnet_diagnostic.CA1861.severity = none + # CA5351: Do not use broken cryptographic algorithms # # We do not care about this for unit tests. diff --git a/test/Renci.SshNet.IntegrationTests/HostConfig.cs b/test/Renci.SshNet.IntegrationTests/HostConfig.cs index d501dd384..c328a729c 100644 --- a/test/Renci.SshNet.IntegrationTests/HostConfig.cs +++ b/test/Renci.SshNet.IntegrationTests/HostConfig.cs @@ -29,7 +29,7 @@ public static HostConfig Read(ScpClient scpClient, string path) while ((line = sr.ReadLine()) != null) { // skip comments - if (line.StartsWith("#")) + if (line.StartsWith('#')) { continue; } From 7436a38b7827c50325aa66c78b8b6800f94a813f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wojciech=20Nag=C3=B3rski?= Date: Fri, 29 Dec 2023 07:45:20 +0100 Subject: [PATCH 96/96] Remove code examples (#1210) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Release 2023.0.0 (#1201) * Assets/logos (#782) * Added logo assets * Added PNG 1260x640 with white border Co-authored-by: 103filgualan * OPENSSH KeyReader for more keys (#614) * OPENSSH KeyReader for more keys Add support to parse OpenSSH Keys with ECDSA 256/384/521 and RSA. https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key Change-Id: Iaa9cce0f2522e5fee377a82cb252f81f0b7cc563 * Fix ED25519Key KeyLength * Fix ED25519 PubKey-auth LeadingZeros of BigInteger-Conversion have to be removed before sending the Key. * Add interface to SftpFile #120 (#812) * Create ISftpFile interface. SftpFile sealed. Return ISftpFile from SftpClient instead of SftpFile. Make ISftpClient interface disposable. Co-authored-by: Wojciech Swieboda * Start MessageListener with ThreadAbstraction.ExecuteThreadLongRunning (#902) * Fix Thread pool exhaustion due to MessageListener running on ThreadPool * Mark long running thread as background * Add async support to SftpClient and SftpFileStream (#819) * Add FEATURE_TAP and net472 target * Add TAP async support to SftpClient and SftpFileStream * Add async support to DnsAbstraction and SocketAbstraction * Add async support to *Connector and refactor the hierarchy * Add ConnectAsync to BaseClient * Add CODEOWNERS file. * Fix virus false-positive by Defender on Renci.SSHNet.Tests.dll (#867) Co-authored-by: Pedro Fonseca * Add unit tests for task-based asynchronous API (#906) * Fix runtime and culture dependant tests. * Set C# 7.3 in Tests.csproj to limit intellisense's suggestions under different targets * Add SftpClientTest.*Async * Add SftpFileStreamTest_OpenAsync_* * Add SftpFileStreamTest_WriteAsync_* * Add SftpFileStreamTest_ReadAsync_* * Align AppVeyor script with Test project target frameworks * correct 'Documenation' to 'Documentation' (#838) in the documentation's window title * Agent auth and Keygen (#794) * Allow to set PrivateKeyFile Key directly So you can add your own Key-Classes to SSH.NET * Add ED25519 ctor for just pub key part. * Make ECDSA Key Bits accessible You cant export imported CngKeys. To be able to export them to agent or Key-Files make the private bits also accessible. * Better NETFRAMEWORK vs NETSTANDARD handling * Add Comment Property to Key * Add IPrivateKeySource So Extension can add own PrivateKeyFiles, e.g. PuttyKeyFile. * Use cryptographically secure random number generator. Fixes CVE-2022-29245. * Remove unused import. * Add IBaseClient for BaseClient and ISftpClient to inherit from (#975) Add IBaseClient for BaseClient and ISftpClient to inherit from * fix typo (#999) * Fix Seek Operations in SftpFileStream (#910) * Fix offset operations in SftpFileStream.Seek * Fix seek exception message and add default case for invalid seek origin * Use named params when throwing ArgumentException * Add tests for seeking from end of file * Add back copyright to license. (#1060) Fixes #1059. * Removing old target frameworks (#1109) Remove support for legacy / deprecated target frameworks while adding support for .NET 6.0 (and higher). The supported target frameworks are now: * .NETFramework 4.6.2 (and higher) * .NET Standard 2.0 * .NET 6.0 (and higher) * Remove old features [Part 1] (#1117) Remove obsolete feature switches (now that we've remove support for legacy target frameworks) and remove corresponding conditional code. * Remove FEATURE_DIRECTORYINFO_ENUMERATEFILES (#1119) * Remove FEATURE_DIRECTORYINFO_ENUMERATEFILES * Add exception documentation * Fix some (lots of) issues reported by analyzers. (#1125) Fix some (lots of) issues reported by analyzers. * Round 2 of analyzer fixes and general cleanup. (#1132) * Analyzer fixes round 3. (#1135) * Replace Array.Empty with Array.Empty() (#1137) * Replace IsNullOrWhiteSpace extension (#1142) * Use License Expression for NuGet Package licenseUrl is deprecated, see https://github.com/NuGet/Announcements/issues/32 * Integration tests * Remove todos * Update CODEOWNERS * Use correct SSH.NET * ListDirectoryAsync return IAsyncEnumerable (#1126) * ListDirectoryAsync return IAsyncEnumerable * Fix documentation * Update README.md * Fix * Add Sftp ListDirectoryAsync test * Revert * Integration tests for ListDirectoryAsync with IAsyncEnumerable * Fix the assembly resolution build warning (#1165) * Delete performance/longrunning tests (#1143) Co-authored-by: Wojciech Nag贸rski * Move Integration tests (#1173) * Renci.SshNet.IntegrationTests * Renci.SshNet.TestTools.OpenSSH * Move integration tests to main repo * Move old tests to new integration tests * Move old integration tests to new integration tests * Move more tests * Move authentication tests * Move SshClientTests * Fix some tests * Remove duplicated test * Poc of ProcessDisruptor * Rename * Some fixes * Remove performance tests * Small improvements * Add a benchmarks project (#1151) * Add a benchmarks project * Small improvements --------- Co-authored-by: Wojciech Nag贸rski * Use ExceptionDispatchInfo to retain call stack in Session.WaitOnHandle() (#936) * Use ExceptionDispatchInfo to retain call stack in Session.WaitOnHandle() * merge * Update src/Renci.SshNet/Session.cs Co-authored-by: Rob Hague --------- Co-authored-by: Wojciech Nag贸rski Co-authored-by: Rob Hague * Support SHA256 fingerprints for host key validation (#1098) * Add tests for HostKeyEventArgs * Add SHA256 fingerprint support * Add support for RSA SHA-2 public key algorithms (#1177) * Abstract out the hash algorithm from RsaDigitalSignature * Add integration tests * Add DigitalSignature property to KeyHostAlgorithm * Add IHostAlgorithmsProvider interface * Verify the host signature * Fix HostKeyEventArgsTest after merge * Remove PubkeyAcceptedAlgorithms ssh-rsa * Add test coverage for RSA keys in PrivateKeyFile * Obsolete IPrivateKeySource --------- Co-authored-by: Wojciech Nag贸rski * Improvements after #1177 (#1180) * Use ExceptionDispatchInfo in more places (#1182) Co-authored-by: Wojciech Nag贸rski * Try to "fix" the flaky test (#1185) * Enable DSA tests (#1181) Co-authored-by: Wojciech Nag贸rski * FingerPrints (#1186) * Use OS-agnostic socket error codes to allow tests run on different OSes (#1179) SocketErrorCode is OS agnostic, ErrorCode is OS specific. On Windows ErrorCode = (int) SocketErrorCode, but on Mac and Unix it is not. For example ExitCode for HostNotFound (11001) on Windows is 11001, on Mac & Unix is -131073. So testing for ExitCode == 11001 fails on Mac & Unix. Co-authored-by: Wojciech Nag贸rski * Fix for channel session semaphore from thread blocking (#1071) * Merging fix from @clivetong into our own SSH.NET fork - The following article describes some of the issues with the double check lock that we have seen issues with: https://www.sudhanshutheone.com/posts/double-check-lock-csharp * Merging fix from @clivetong into our own SSH.NET fork - The following article describes some of the issues with the double check lock that we have seen issues with: https://www.sudhanshutheone.com/posts/double-check-lock-csharp * Update Channel to fix AppVeyor failure (field should be readonly) * Update ISftpClient for #120 (#1193) * Implement set last write and access time (#1194) * Add/migrate hmac+cipher integration tests (#1189) * Add/migrate hmac+cipher integration tests * fix integration tests --------- Co-authored-by: Wojciech Nag贸rski * Update tests for SetLastAccessTime(Utc) to also verify the time component and the Kind of the DateTime value returned by GetLastAccessTime(Utc). (#1198) --------- Co-authored-by: Filippo Gualandi Co-authored-by: 103filgualan Co-authored-by: Stefan Rinkes Co-authored-by: wxtsxt Co-authored-by: Wojciech Swieboda Co-authored-by: Igor Milavec Co-authored-by: drieseng Co-authored-by: Pedro Fonseca Co-authored-by: Pedro Fonseca Co-authored-by: Maximiliano Jabase Co-authored-by: Owen Krueger <37021716+Owen-Krueger@users.noreply.github.com> Co-authored-by: Masuri Co-authored-by: LemonPi314 <49930425+LemonPi314@users.noreply.github.com> Co-authored-by: Gert Driesen Co-authored-by: Rob Hague Co-authored-by: Rob Hague Co-authored-by: Marius Thesing Co-authored-by: D膩vis Mo拧enkovs Co-authored-by: Dmitry Tsarevich Co-authored-by: Patrick Yates <114094360+patrick-yates-redgate@users.noreply.github.com> * Remove code examples --------- Co-authored-by: Filippo Gualandi Co-authored-by: 103filgualan Co-authored-by: Stefan Rinkes Co-authored-by: wxtsxt Co-authored-by: Wojciech Swieboda Co-authored-by: Igor Milavec Co-authored-by: drieseng Co-authored-by: Pedro Fonseca Co-authored-by: Pedro Fonseca Co-authored-by: Maximiliano Jabase Co-authored-by: Owen Krueger <37021716+Owen-Krueger@users.noreply.github.com> Co-authored-by: Masuri Co-authored-by: LemonPi314 <49930425+LemonPi314@users.noreply.github.com> Co-authored-by: Gert Driesen Co-authored-by: Rob Hague Co-authored-by: Rob Hague Co-authored-by: Marius Thesing Co-authored-by: D膩vis Mo拧enkovs Co-authored-by: Dmitry Tsarevich Co-authored-by: Patrick Yates <114094360+patrick-yates-redgate@users.noreply.github.com> --- src/Renci.SshNet/BaseClient.cs | 6 ---- src/Renci.SshNet/ConnectionInfo.cs | 6 ---- src/Renci.SshNet/ForwardedPortLocal.cs | 3 -- src/Renci.SshNet/ForwardedPortRemote.cs | 3 -- src/Renci.SshNet/IBaseClient.cs | 6 ---- src/Renci.SshNet/IConnectionInfo.cs | 3 -- .../KeyboardInteractiveConnectionInfo.cs | 6 ---- src/Renci.SshNet/PasswordConnectionInfo.cs | 11 ------- src/Renci.SshNet/PrivateKeyConnectionInfo.cs | 7 ----- src/Renci.SshNet/PrivateKeyFile.cs | 3 -- src/Renci.SshNet/SshClient.cs | 25 ---------------- src/Renci.SshNet/SshCommand.cs | 29 ------------------- 12 files changed, 108 deletions(-) diff --git a/src/Renci.SshNet/BaseClient.cs b/src/Renci.SshNet/BaseClient.cs index bdfd5cb5f..56d2145cc 100644 --- a/src/Renci.SshNet/BaseClient.cs +++ b/src/Renci.SshNet/BaseClient.cs @@ -140,17 +140,11 @@ public TimeSpan KeepAliveInterval /// /// Occurs when an error occurred. /// - /// - /// - /// public event EventHandler ErrorOccurred; /// /// Occurs when host key received. /// - /// - /// - /// public event EventHandler HostKeyReceived; /// diff --git a/src/Renci.SshNet/ConnectionInfo.cs b/src/Renci.SshNet/ConnectionInfo.cs index 7eccb8dff..721a45762 100644 --- a/src/Renci.SshNet/ConnectionInfo.cs +++ b/src/Renci.SshNet/ConnectionInfo.cs @@ -144,9 +144,6 @@ public class ConnectionInfo : IConnectionInfoInternal /// /// The connection timeout. The default value is 30 seconds. /// - /// - /// - /// public TimeSpan Timeout { get; set; } /// @@ -190,9 +187,6 @@ public class ConnectionInfo : IConnectionInfoInternal /// /// Occurs when authentication banner is sent by the server. /// - /// - /// - /// public event EventHandler AuthenticationBanner; /// diff --git a/src/Renci.SshNet/ForwardedPortLocal.cs b/src/Renci.SshNet/ForwardedPortLocal.cs index 3d5b58768..72bf08dc7 100644 --- a/src/Renci.SshNet/ForwardedPortLocal.cs +++ b/src/Renci.SshNet/ForwardedPortLocal.cs @@ -58,9 +58,6 @@ public override bool IsStarted /// is greater than . /// is . /// is greater than . - /// - /// - /// public ForwardedPortLocal(uint boundPort, string host, uint port) : this(string.Empty, boundPort, host, port) { diff --git a/src/Renci.SshNet/ForwardedPortRemote.cs b/src/Renci.SshNet/ForwardedPortRemote.cs index af7fd48a2..1b4a74eb4 100644 --- a/src/Renci.SshNet/ForwardedPortRemote.cs +++ b/src/Renci.SshNet/ForwardedPortRemote.cs @@ -112,9 +112,6 @@ public ForwardedPortRemote(IPAddress boundHostAddress, uint boundPort, IPAddress /// The bound port. /// The host. /// The port. - /// - /// - /// public ForwardedPortRemote(uint boundPort, string host, uint port) : this(string.Empty, boundPort, host, port) { diff --git a/src/Renci.SshNet/IBaseClient.cs b/src/Renci.SshNet/IBaseClient.cs index add066f73..c42df3426 100644 --- a/src/Renci.SshNet/IBaseClient.cs +++ b/src/Renci.SshNet/IBaseClient.cs @@ -43,17 +43,11 @@ public interface IBaseClient : IDisposable /// /// Occurs when an error occurred. /// - /// - /// - /// event EventHandler ErrorOccurred; /// /// Occurs when host key received. /// - /// - /// - /// event EventHandler HostKeyReceived; /// diff --git a/src/Renci.SshNet/IConnectionInfo.cs b/src/Renci.SshNet/IConnectionInfo.cs index a0f2898ef..35dabcc2f 100644 --- a/src/Renci.SshNet/IConnectionInfo.cs +++ b/src/Renci.SshNet/IConnectionInfo.cs @@ -98,9 +98,6 @@ internal interface IConnectionInfo /// /// The connection timeout. The default value is 30 seconds. /// - /// - /// - /// TimeSpan Timeout { get; } /// diff --git a/src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs b/src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs index 2d3825b3f..a2738796a 100644 --- a/src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs +++ b/src/Renci.SshNet/KeyboardInteractiveConnectionInfo.cs @@ -6,9 +6,6 @@ namespace Renci.SshNet /// /// Provides connection information when keyboard interactive authentication method is used. /// - /// - /// - /// public class KeyboardInteractiveConnectionInfo : ConnectionInfo, IDisposable { private bool _isDisposed; @@ -16,9 +13,6 @@ public class KeyboardInteractiveConnectionInfo : ConnectionInfo, IDisposable /// /// Occurs when server prompts for more authentication information. /// - /// - /// - /// public event EventHandler AuthenticationPrompt; /// diff --git a/src/Renci.SshNet/PasswordConnectionInfo.cs b/src/Renci.SshNet/PasswordConnectionInfo.cs index 08ef59dea..072b32147 100644 --- a/src/Renci.SshNet/PasswordConnectionInfo.cs +++ b/src/Renci.SshNet/PasswordConnectionInfo.cs @@ -8,11 +8,6 @@ namespace Renci.SshNet /// /// Provides connection information when password authentication method is used. /// - /// - /// - /// - /// - /// public class PasswordConnectionInfo : ConnectionInfo, IDisposable { private bool _isDisposed; @@ -20,9 +15,6 @@ public class PasswordConnectionInfo : ConnectionInfo, IDisposable /// /// Occurs when user's password has expired and needs to be changed. /// - /// - /// - /// public event EventHandler PasswordExpired; /// @@ -31,9 +23,6 @@ public class PasswordConnectionInfo : ConnectionInfo, IDisposable /// Connection host. /// Connection username. /// Connection password. - /// - /// - /// /// is . /// is invalid, or is or contains only whitespace characters. public PasswordConnectionInfo(string host, string username, string password) diff --git a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs index ecd0bbb8a..dacfc36b1 100644 --- a/src/Renci.SshNet/PrivateKeyConnectionInfo.cs +++ b/src/Renci.SshNet/PrivateKeyConnectionInfo.cs @@ -7,9 +7,6 @@ namespace Renci.SshNet /// /// Provides connection information when private key authentication method is used. /// - /// - /// - /// public class PrivateKeyConnectionInfo : ConnectionInfo, IDisposable { private bool _isDisposed; @@ -25,10 +22,6 @@ public class PrivateKeyConnectionInfo : ConnectionInfo, IDisposable /// Connection host. /// Connection username. /// Connection key files. - /// - /// - /// - /// public PrivateKeyConnectionInfo(string host, string username, params PrivateKeyFile[] keyFiles) : this(host, DefaultPort, username, ProxyTypes.None, string.Empty, 0, string.Empty, string.Empty, keyFiles) { diff --git a/src/Renci.SshNet/PrivateKeyFile.cs b/src/Renci.SshNet/PrivateKeyFile.cs index 9f6d728bc..d42594583 100644 --- a/src/Renci.SshNet/PrivateKeyFile.cs +++ b/src/Renci.SshNet/PrivateKeyFile.cs @@ -20,9 +20,6 @@ namespace Renci.SshNet /// /// Represents private key information. /// - /// - /// - /// /// /// /// The following private keys are supported: diff --git a/src/Renci.SshNet/SshClient.cs b/src/Renci.SshNet/SshClient.cs index 753ab8f9f..2e1103553 100644 --- a/src/Renci.SshNet/SshClient.cs +++ b/src/Renci.SshNet/SshClient.cs @@ -44,12 +44,6 @@ public IEnumerable ForwardedPorts /// Initializes a new instance of the class. /// /// The connection info. - /// - /// - /// - /// - /// - /// /// is . public SshClient(ConnectionInfo connectionInfo) : this(connectionInfo, ownsConnectionInfo: false) @@ -80,9 +74,6 @@ public SshClient(string host, int port, string username, string password) /// Connection host. /// Authentication username. /// Authentication password. - /// - /// - /// /// is . /// is invalid, or is or contains only whitespace characters. public SshClient(string host, string username, string password) @@ -97,10 +88,6 @@ public SshClient(string host, string username, string password) /// Connection port. /// Authentication username. /// Authentication private key file(s) . - /// - /// - /// - /// /// is . /// is invalid, -or- is or contains only whitespace characters. /// is not within and . @@ -116,10 +103,6 @@ public SshClient(string host, int port, string username, params IPrivateKeySourc /// Connection host. /// Authentication username. /// Authentication private key file(s) . - /// - /// - /// - /// /// is . /// is invalid, -or- is or contains only whitespace characters. public SshClient(string host, string username, params IPrivateKeySource[] keyFiles) @@ -177,10 +160,6 @@ protected override void OnDisconnecting() /// Adds the forwarded port. /// /// The port. - /// - /// - /// - /// /// Forwarded port is already added to a different client. /// is . /// Client is not connected. @@ -265,10 +244,6 @@ public SshCommand CreateCommand(string commandText, Encoding encoding) /// The command text. /// Returns an instance of with execution results. /// This method internally uses asynchronous calls. - /// - /// - /// - /// /// CommandText property is empty. /// Invalid Operation - An existing channel was used to execute this command. /// Asynchronous operation is already in progress. diff --git a/src/Renci.SshNet/SshCommand.cs b/src/Renci.SshNet/SshCommand.cs index 5b93354f7..a7769ab2c 100644 --- a/src/Renci.SshNet/SshCommand.cs +++ b/src/Renci.SshNet/SshCommand.cs @@ -43,25 +43,16 @@ public class SshCommand : IDisposable /// /// The command timeout. /// - /// - /// - /// public TimeSpan CommandTimeout { get; set; } /// /// Gets the command exit status. /// - /// - /// - /// public int ExitStatus { get; private set; } /// /// Gets the output stream. /// - /// - /// - /// #pragma warning disable CA1859 // Use concrete types when possible for improved performance public Stream OutputStream { get; private set; } #pragma warning restore CA1859 // Use concrete types when possible for improved performance @@ -69,9 +60,6 @@ public class SshCommand : IDisposable /// /// Gets the extended output stream. /// - /// - /// - /// #pragma warning disable CA1859 // Use concrete types when possible for improved performance public Stream ExtendedOutputStream { get; private set; } #pragma warning restore CA1859 // Use concrete types when possible for improved performance @@ -79,9 +67,6 @@ public class SshCommand : IDisposable /// /// Gets the command execution result. /// - /// - /// - /// public string Result { get @@ -107,9 +92,6 @@ public string Result /// /// Gets the command execution error. /// - /// - /// - /// public string Error { get @@ -177,9 +159,6 @@ internal SshCommand(ISession session, string commandText, Encoding encoding) /// /// An that represents the asynchronous command execution, which could still be pending. /// - /// - /// - /// /// Asynchronous operation is already in progress. /// Invalid operation. /// CommandText property is empty. @@ -301,9 +280,6 @@ public IAsyncResult BeginExecute(string commandText, AsyncCallback callback, obj /// /// The reference to the pending asynchronous request to finish. /// Command execution result. - /// - /// - /// /// 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. /// is . public string EndExecute(IAsyncResult asyncResult) @@ -355,11 +331,6 @@ public void CancelAsync() /// /// Command execution result. /// - /// - /// - /// - /// - /// /// Client is not connected. /// Operation has timed out. public string Execute()