Skip to content

Commit c595348

Browse files
committed
Merge remote-tracking branch 'upstream/develop' into copilot/refactor-collection-assertions
# Conflicts: # test/Renci.SshNet.Tests/Classes/Sftp/Responses/SftpDataResponseTest.cs
2 parents 1970635 + 89ea230 commit c595348

38 files changed

+826
-595
lines changed

.gitattributes

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
*.cs text diff=csharp
44
*.xaml text
5-
*.sln eol=crlf
65
*.csproj eol=crlf
76
*.shproj eol=crlf
87
*.appxmanifest eol=crlf

.github/workflows/build.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
runs-on: ubuntu-24.04
1111
steps:
1212
- name: Checkout
13-
uses: actions/checkout@v5
13+
uses: actions/checkout@v6
1414
with:
1515
fetch-depth: 0 # needed for Nerdbank.GitVersioning
1616

@@ -57,15 +57,15 @@ jobs:
5757
runs-on: windows-2025
5858
steps:
5959
- name: Checkout
60-
uses: actions/checkout@v5
60+
uses: actions/checkout@v6
6161
with:
6262
fetch-depth: 0 # needed for Nerdbank.GitVersioning
6363

6464
- name: Setup .NET
6565
uses: actions/setup-dotnet@v5
6666

6767
- name: Build Solution
68-
run: dotnet build Renci.SshNet.sln
68+
run: dotnet build Renci.SshNet.slnx
6969

7070
- name: Publish AOT Compatibility Test App
7171
run: dotnet publish -r win-x64 /warnaserror test/Renci.SshNet.AotCompatibilityTestApp/
@@ -108,7 +108,7 @@ jobs:
108108
runs-on: windows-2025
109109
steps:
110110
- name: Checkout
111-
uses: actions/checkout@v5
111+
uses: actions/checkout@v6
112112
with:
113113
fetch-depth: 0 # needed for Nerdbank.GitVersioning
114114

@@ -150,7 +150,7 @@ jobs:
150150
runs-on: windows-2025
151151
steps:
152152
- name: Checkout
153-
uses: actions/checkout@v5
153+
uses: actions/checkout@v6
154154
with:
155155
fetch-depth: 0 # needed for Nerdbank.GitVersioning
156156

.github/workflows/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
runs-on: ubuntu-latest
2323
steps:
2424
- name: Checkout repository
25-
uses: actions/checkout@v5
25+
uses: actions/checkout@v6
2626

2727
- name: Setup Pages
2828
uses: actions/configure-pages@v5

Directory.Packages.props

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,24 @@
44
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
55
</PropertyGroup>
66
<ItemGroup>
7-
<PackageVersion Include="BenchmarkDotNet" Version="0.15.3" />
7+
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
88
<PackageVersion Include="BouncyCastle.Cryptography" Version="2.6.2" />
99
<PackageVersion Include="coverlet.collector" Version="6.0.4" />
1010
<PackageVersion Include="coverlet.msbuild" Version="6.0.4" />
11-
<PackageVersion Include="GitHubActionsTestLogger" Version="2.4.1" />
12-
<PackageVersion Include="Meziantou.Analyzer" Version="2.0.220" />
11+
<PackageVersion Include="GitHubActionsTestLogger" Version="3.0.1" />
12+
<PackageVersion Include="Meziantou.Analyzer" Version="2.0.264" />
1313
<!-- Should stay on LTS .NET releases. -->
14-
<PackageVersion Include="Microsoft.Bcl.Cryptography" Version="10.0.0" />
14+
<PackageVersion Include="Microsoft.Bcl.Cryptography" Version="10.0.1" />
1515
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3" />
16-
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="10.0.0" />
16+
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="10.0.1" />
1717
<PackageVersion Include="MSTest" Version="4.0.2" />
1818
<PackageVersion Include="Moq" Version="4.20.72" />
19-
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.7.115" />
19+
<PackageVersion Include="Nerdbank.GitVersioning" Version="3.9.50" />
2020
<PackageVersion Include="PolySharp" Version="1.15.0" />
21-
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.15.0.120848" />
21+
<PackageVersion Include="SonarAnalyzer.CSharp" Version="10.17.0.131074" />
2222
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
2323
<!-- Should stay on LTS .NET releases. -->
24-
<PackageVersion Include="System.Formats.Asn1" Version="8.0.2" />
25-
<PackageVersion Include="Testcontainers" Version="4.7.0" />
24+
<PackageVersion Include="System.Formats.Asn1" Version="10.0.1" />
25+
<PackageVersion Include="Testcontainers" Version="4.9.0" />
2626
</ItemGroup>
2727
</Project>

Renci.SshNet.sln

Lines changed: 0 additions & 267 deletions
This file was deleted.

Renci.SshNet.slnx

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<Solution>
2+
<Folder Name="/Solution Items/">
3+
<File Path=".editorconfig" />
4+
<File Path=".gitattributes" />
5+
<File Path=".gitignore" />
6+
<File Path="CODEOWNERS" />
7+
<File Path="CONTRIBUTING.md" />
8+
<File Path="Directory.Build.props" />
9+
<File Path="Directory.Packages.props" />
10+
<File Path="exclusion.dic" />
11+
<File Path="global.json" />
12+
<File Path="LICENSE" />
13+
<File Path="nuget.config" />
14+
<File Path="README.md" />
15+
<File Path="stylecop.json" />
16+
<File Path="THIRD-PARTY-NOTICES.TXT" />
17+
<File Path="version.json" />
18+
</Folder>
19+
<Folder Name="/Solution Items/.github/">
20+
<File Path=".github/dependabot.yml" />
21+
</Folder>
22+
<Folder Name="/Solution Items/.github/workflows/">
23+
<File Path=".github/workflows/build.yml" />
24+
<File Path=".github/workflows/docs.yml" />
25+
</Folder>
26+
<Folder Name="/Solution Items/images/" />
27+
<Folder Name="/Solution Items/images/logo/" />
28+
<Folder Name="/Solution Items/images/logo/ai/">
29+
<File Path="images/logo/ai/SS-NET-icon-white.ai" />
30+
<File Path="images/logo/ai/SS-NET-icon.ai" />
31+
<File Path="images/logo/ai/SS-NET-white.ai" />
32+
<File Path="images/logo/ai/SS-NET.ai" />
33+
</Folder>
34+
<Folder Name="/Solution Items/images/logo/png/">
35+
<File Path="images/logo/png/SS-NET-1280x640.png" />
36+
<File Path="images/logo/png/SS-NET-h50.png" />
37+
<File Path="images/logo/png/SS-NET-h500.png" />
38+
<File Path="images/logo/png/SS-NET-icon-h50.png" />
39+
<File Path="images/logo/png/SS-NET-icon-h500.png" />
40+
<File Path="images/logo/png/SS-NET-icon-white-h50.png" />
41+
<File Path="images/logo/png/SS-NET-icon-white-h500.png" />
42+
<File Path="images/logo/png/SS-NET-white-h50.png" />
43+
<File Path="images/logo/png/SS-NET-white-h500.png" />
44+
</Folder>
45+
<Folder Name="/Solution Items/images/logo/svg/">
46+
<File Path="images/logo/svg/SS-NET-icon-white.svg" />
47+
<File Path="images/logo/svg/SS-NET-icon.svg" />
48+
<File Path="images/logo/svg/SS-NET-white.svg" />
49+
<File Path="images/logo/svg/SS-NET.svg" />
50+
</Folder>
51+
<Folder Name="/Solution Items/src/" />
52+
<Folder Name="/Solution Items/src/References/">
53+
<File Path="src/References/How the SCP protocol works.pdf" />
54+
<File Path="src/References/X.690-0207.pdf" />
55+
<File Path="src/References/X.690-0207.txt" />
56+
</Folder>
57+
<Folder Name="/Solution Items/test/">
58+
<File Path="test/Directory.Build.props" />
59+
</Folder>
60+
<Project Path="src/Renci.SshNet/Renci.SshNet.csproj" />
61+
<Project Path="test/Renci.SshNet.AotCompatibilityTestApp/Renci.SshNet.AotCompatibilityTestApp.csproj" />
62+
<Project Path="test/Renci.SshNet.Benchmarks/Renci.SshNet.Benchmarks.csproj" />
63+
<Project Path="test/Renci.SshNet.IntegrationBenchmarks/Renci.SshNet.IntegrationBenchmarks.csproj" />
64+
<Project Path="test/Renci.SshNet.IntegrationTests/Renci.SshNet.IntegrationTests.csproj" />
65+
<Project Path="test/Renci.SshNet.Tests/Renci.SshNet.Tests.csproj" />
66+
<Project Path="test/Renci.SshNet.TestTools.OpenSSH/Renci.SshNet.TestTools.OpenSSH.csproj" />
67+
</Solution>

src/Renci.SshNet/Abstractions/CryptoAbstraction.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
using System;
2+
#if !NET
3+
using System.Runtime.CompilerServices;
4+
#endif
15
using System.Security.Cryptography;
26

37
using Org.BouncyCastle.Crypto.Prng;
@@ -10,5 +14,37 @@ internal static class CryptoAbstraction
1014
internal static readonly RandomNumberGenerator Randomizer = RandomNumberGenerator.Create();
1115

1216
internal static readonly SecureRandom SecureRandom = new SecureRandom(new CryptoApiRandomGenerator(Randomizer));
17+
18+
#if !NET
19+
[MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
20+
#endif
21+
public static bool FixedTimeEquals(ReadOnlySpan<byte> left, ReadOnlySpan<byte> right)
22+
{
23+
#if NET
24+
return CryptographicOperations.FixedTimeEquals(left, right);
25+
#else
26+
// https://github.com/dotnet/runtime/blob/1d1bf92fcf43aa6981804dc53c5174445069c9e4/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/CryptographicOperations.cs
27+
28+
// NoOptimization because we want this method to be exactly as non-short-circuiting
29+
// as written.
30+
//
31+
// NoInlining because the NoOptimization would get lost if the method got inlined.
32+
33+
if (left.Length != right.Length)
34+
{
35+
return false;
36+
}
37+
38+
var length = left.Length;
39+
var accum = 0;
40+
41+
for (var i = 0; i < length; i++)
42+
{
43+
accum |= left[i] - right[i];
44+
}
45+
46+
return accum == 0;
47+
#endif
48+
}
1349
}
1450
}

src/Renci.SshNet/Common/Extensions.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,22 @@ async Task<T> WaitCore()
417417
return await completedTask.ConfigureAwait(false);
418418
}
419419
}
420+
421+
extension(Array)
422+
{
423+
internal static int MaxLength
424+
{
425+
get { return 0X7FFFFFC7; }
426+
}
427+
}
428+
429+
extension(Task t)
430+
{
431+
internal bool IsCompletedSuccessfully
432+
{
433+
get { return t.Status == TaskStatus.RanToCompletion; }
434+
}
435+
}
420436
#endif
421437
}
422438
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#nullable enable
2+
using System;
3+
using System.Buffers;
4+
using System.Diagnostics;
5+
using System.Net;
6+
7+
namespace Renci.SshNet.Common
8+
{
9+
/// <summary>
10+
/// A type representing ownership of a rented, read-only buffer.
11+
/// </summary>
12+
internal sealed class ReadOnlyMemoryOwner : IMemoryOwner<byte>
13+
{
14+
private ArrayBuffer _buffer;
15+
16+
public ReadOnlyMemoryOwner(ArrayBuffer buffer)
17+
{
18+
_buffer = buffer;
19+
20+
AssertValid();
21+
}
22+
23+
[Conditional("DEBUG")]
24+
private void AssertValid()
25+
{
26+
Debug.Assert(
27+
_buffer.ActiveLength > 0 || _buffer.AvailableLength == 0,
28+
"If the buffer is empty, then it should have been returned to the pool.");
29+
}
30+
31+
public int Length
32+
{
33+
get
34+
{
35+
AssertValid();
36+
return _buffer.ActiveLength;
37+
}
38+
}
39+
40+
public bool IsEmpty
41+
{
42+
get
43+
{
44+
AssertValid();
45+
return _buffer.ActiveLength == 0;
46+
}
47+
}
48+
49+
public ReadOnlySpan<byte> Span
50+
{
51+
get
52+
{
53+
AssertValid();
54+
return _buffer.ActiveReadOnlySpan;
55+
}
56+
}
57+
58+
Memory<byte> IMemoryOwner<byte>.Memory
59+
{
60+
get
61+
{
62+
AssertValid();
63+
return _buffer.ActiveMemory;
64+
}
65+
}
66+
67+
public void Slice(int start)
68+
{
69+
AssertValid();
70+
71+
_buffer.Discard(start);
72+
73+
if (_buffer.ActiveLength == 0)
74+
{
75+
// Return the rented buffer as soon as it's no longer in use.
76+
_buffer.ClearAndReturnBuffer();
77+
}
78+
}
79+
80+
public void Dispose()
81+
{
82+
AssertValid();
83+
84+
_buffer.ClearAndReturnBuffer();
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)