diff --git a/.github/workflows/nuget.yml b/.github/workflows/nuget.yml new file mode 100644 index 0000000..68cf238 --- /dev/null +++ b/.github/workflows/nuget.yml @@ -0,0 +1,58 @@ +name: nuget + +on: + push: + branches: [main] + paths: + - "src/Empostor.Api/**" + - ".github/workflows/nuget.yml" + workflow_dispatch: + +jobs: + publish: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup .NET 8 + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + # Version scheme mirrors build.cake: -ci.. + # If that exact version already exists on nuget.org (workflow re-run), + # publishing is skipped by --skip-duplicate. + - name: Resolve version + id: ver + run: | + set -euo pipefail + PROJ=src/Empostor.Api/Empostor.Api.csproj + BASE=$(sed -n 's/.*\([^<]*\)<\/VersionPrefix>.*/\1/p' "$PROJ" | head -1) + N=$(( ${{ github.run_number }} + 500 )) + echo "suffix=ci.${N}" >> "$GITHUB_OUTPUT" + echo "version=${BASE}-ci.${N}" >> "$GITHUB_OUTPUT" + echo "Publishing version: ${BASE}-ci.${N}" + + - name: Pack + run: dotnet pack src/Empostor.Api/Empostor.Api.csproj -c Release -p:VersionSuffix=${{ steps.ver.outputs.suffix }} -p:GeneratePackageOnBuild=false -o artifacts --nologo + + - name: Push to nuget.org + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + run: | + set -euo pipefail + ls -la artifacts + if [ -z "$NUGET_API_KEY" ]; then + echo "::warning::NUGET_API_KEY secret is not set; skipping push." + exit 0 + fi + dotnet nuget push "artifacts/Empostor.Api.*.nupkg" \ + --api-key "$NUGET_API_KEY" \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate + dotnet nuget push "artifacts/Empostor.Api.*.snupkg" \ + --api-key "$NUGET_API_KEY" \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate || true diff --git a/docs/images/logo_100.png b/docs/images/logo_100.png index 08cd6f2..75bf79a 100644 Binary files a/docs/images/logo_100.png and b/docs/images/logo_100.png differ diff --git a/src/Empostor.Api/Empostor.Api.csproj b/src/Empostor.Api/Empostor.Api.csproj index 16ccb4a..c00288b 100644 --- a/src/Empostor.Api/Empostor.Api.csproj +++ b/src/Empostor.Api/Empostor.Api.csproj @@ -6,17 +6,20 @@ enable true snupkg + 2.0.0 Empostor.Api Empostor.Api AeonLucid An api library for Empostor, an Among Us private server. You need this package to write plugins for Empostor. Empostor.Api Among Us;Empostor;Empostor Plugin + GPL-3.0-only https://raw.githubusercontent.com/Empostor/Empostor/dev/docs/images/logo_100.png logo_100.png https://github.com/Empostor/Empostor git https://github.com/Empostor/Empostor + true true @@ -25,16 +28,13 @@ + - - - - - + diff --git a/src/Empostor.Api/packages.lock.json b/src/Empostor.Api/packages.lock.json index 9d991b4..9734f25 100644 --- a/src/Empostor.Api/packages.lock.json +++ b/src/Empostor.Api/packages.lock.json @@ -2,6 +2,19 @@ "version": 1, "dependencies": { "net8.0": { + "Empostor.Hazel": { + "type": "Direct", + "requested": "[1.0.2, )", + "resolved": "1.0.2", + "contentHash": "cblWCgvLcQ2xK6ztV04RVrghVEnJpCWe4N6G3LCNaJhuUq367a1/bbtQxUWAflqvgSvGwY3g3SClhh9eWTCBDA==", + "dependencies": { + "BouncyCastle.Cryptography": "2.6.1", + "Empostor.Hazel.Abstractions": "1.0.2", + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.6", + "Microsoft.Extensions.ObjectPool": "8.0.1", + "Serilog": "4.3.1" + } + }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Direct", "requested": "[2.2.0, )", @@ -48,6 +61,11 @@ "resolved": "2.6.1", "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" }, + "Empostor.Hazel.Abstractions": { + "type": "Transitive", + "resolved": "1.0.2", + "contentHash": "uJqGMASOGj+ELffmIMqubyvJ/FHjOXA1RtQdS38s1LRhP+Eu4zJMTTndr12+Q3vS0kHggFFyuExFmNxWyzWmig==" + }, "Microsoft.AspNetCore.Http.Features": { "type": "Transitive", "resolved": "2.2.0", @@ -108,8 +126,8 @@ }, "Serilog": { "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" + "resolved": "4.3.1", + "contentHash": "savYe7h5yRlkqBVOwP8cIRDOdqKiPmYCU4W87JH38sBmcKD5EBoXvQIw6bNEvZ/pTe1gsiye3VFCzBsoppGkXQ==" }, "StyleCop.Analyzers.Unstable": { "type": "Transitive", @@ -125,19 +143,6 @@ "type": "Transitive", "resolved": "4.5.0", "contentHash": "Xg4G4Indi4dqP1iuAiMSwpiWS54ZghzR644OtsRCm/m/lBMG8dUBhLVN7hLm8NNrNTR+iGbshCPTwrvxZPlm4g==" - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugin.Chat/packages.lock.json b/src/Empostor.Plugin.Chat/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugin.Chat/packages.lock.json +++ b/src/Empostor.Plugin.Chat/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugin.Code/packages.lock.json b/src/Empostor.Plugin.Code/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugin.Code/packages.lock.json +++ b/src/Empostor.Plugin.Code/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugin.Narrator/packages.lock.json b/src/Empostor.Plugin.Narrator/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugin.Narrator/packages.lock.json +++ b/src/Empostor.Plugin.Narrator/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.ChatFilter/packages.lock.json b/src/Empostor.Plugins.ChatFilter/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugins.ChatFilter/packages.lock.json +++ b/src/Empostor.Plugins.ChatFilter/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.DiscordWebhook/packages.lock.json b/src/Empostor.Plugins.DiscordWebhook/packages.lock.json index 889b108..dcce8c0 100644 --- a/src/Empostor.Plugins.DiscordWebhook/packages.lock.json +++ b/src/Empostor.Plugins.DiscordWebhook/packages.lock.json @@ -16,11 +16,6 @@ "Microsoft.Extensions.Options": "8.0.0" } }, - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -73,8 +68,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics": { "type": "Transitive", @@ -134,11 +129,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -165,11 +155,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -183,25 +168,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.Example/packages.lock.json b/src/Empostor.Plugins.Example/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugins.Example/packages.lock.json +++ b/src/Empostor.Plugins.Example/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.FixedCode/packages.lock.json b/src/Empostor.Plugins.FixedCode/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugins.FixedCode/packages.lock.json +++ b/src/Empostor.Plugins.FixedCode/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.FriendCodeValidator/packages.lock.json b/src/Empostor.Plugins.FriendCodeValidator/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugins.FriendCodeValidator/packages.lock.json +++ b/src/Empostor.Plugins.FriendCodeValidator/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.MapVote/packages.lock.json b/src/Empostor.Plugins.MapVote/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugins.MapVote/packages.lock.json +++ b/src/Empostor.Plugins.MapVote/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.Message/packages.lock.json b/src/Empostor.Plugins.Message/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugins.Message/packages.lock.json +++ b/src/Empostor.Plugins.Message/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.Monitor/packages.lock.json b/src/Empostor.Plugins.Monitor/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugins.Monitor/packages.lock.json +++ b/src/Empostor.Plugins.Monitor/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.PlayerChannel/packages.lock.json b/src/Empostor.Plugins.PlayerChannel/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugins.PlayerChannel/packages.lock.json +++ b/src/Empostor.Plugins.PlayerChannel/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.PlayerLog/packages.lock.json b/src/Empostor.Plugins.PlayerLog/packages.lock.json index 1ba9ee7..27674f3 100644 --- a/src/Empostor.Plugins.PlayerLog/packages.lock.json +++ b/src/Empostor.Plugins.PlayerLog/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -24,15 +19,6 @@ "Microsoft.Extensions.Primitives": "2.2.0" } }, - "Microsoft.Extensions.Configuration": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", - "Microsoft.Extensions.Primitives": "8.0.0" - } - }, "Microsoft.Extensions.Configuration.Abstractions": { "type": "Transitive", "resolved": "8.0.0", @@ -41,98 +27,10 @@ "Microsoft.Extensions.Primitives": "8.0.0" } }, - "Microsoft.Extensions.Configuration.Binder": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "mBMoXLsr5s1y2zOHWmKsE9veDcx8h1x/c3rz4baEdQKTeDcmQAPNbB54Pi/lhFO3K431eEq6PFbMgLaa6PHFfA==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "8.0.0" - } - }, - "Microsoft.Extensions.Configuration.CommandLine": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "NZuZMz3Q8Z780nKX3ifV1fE7lS+6pynDHK71OfU4OZ1ItgvDOhyOC7E6z+JMZrAj63zRpwbdldYFk499t3+1dQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "8.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "8.0.0" - } - }, - "Microsoft.Extensions.Configuration.EnvironmentVariables": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "plvZ0ZIpq+97gdPNNvhwvrEZ92kNml9hd1pe3idMA7svR0PztdzVLkoWLcRFgySYXUJc3kSM3Xw3mNFMo/bxRA==", - "dependencies": { - "Microsoft.Extensions.Configuration": "8.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "8.0.0" - } - }, - "Microsoft.Extensions.Configuration.FileExtensions": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", - "dependencies": { - "Microsoft.Extensions.Configuration": "8.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", - "Microsoft.Extensions.FileProviders.Physical": "8.0.0", - "Microsoft.Extensions.Primitives": "8.0.0" - } - }, - "Microsoft.Extensions.Configuration.Json": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", - "dependencies": { - "Microsoft.Extensions.Configuration": "8.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", - "System.Text.Json": "8.0.0" - } - }, - "Microsoft.Extensions.Configuration.UserSecrets": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "ihDHu2dJYQird9pl2CbdwuNDfvCZdOS0S7SPlNfhPt0B81UTT+yyZKz2pimFZGUp3AfuBRnqUCxB2SjsZKHVUw==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", - "Microsoft.Extensions.Configuration.Json": "8.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", - "Microsoft.Extensions.FileProviders.Physical": "8.0.0" - } - }, - "Microsoft.Extensions.DependencyInjection": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" - } - }, "Microsoft.Extensions.DependencyInjection.Abstractions": { - "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" - }, - "Microsoft.Extensions.DependencyModel": { "type": "Transitive", "resolved": "8.0.0", - "contentHash": "NSmDw3K0ozNDgShSIpsZcbFIzBX4w28nDag+TfaQujkXGazBm+lid5onlWoCBy4VsLxqnnKjEBbGSJVWJMf43g==", - "dependencies": { - "System.Text.Encodings.Web": "8.0.0", - "System.Text.Json": "8.0.0" - } - }, - "Microsoft.Extensions.Diagnostics": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "3PZp/YSkIXrF7QK7PfC1bkyRYwqOHpWFad8Qx+4wkuumAeXo1NHaxpS9LboNA9OvNSAu+QOVlXbMyoY+pHSqcw==", - "dependencies": { - "Microsoft.Extensions.Configuration": "8.0.0", - "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0" - } + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -152,50 +50,6 @@ "Microsoft.Extensions.Primitives": "8.0.0" } }, - "Microsoft.Extensions.FileProviders.Physical": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", - "dependencies": { - "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", - "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", - "Microsoft.Extensions.Primitives": "8.0.0" - } - }, - "Microsoft.Extensions.FileSystemGlobbing": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==" - }, - "Microsoft.Extensions.Hosting": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "ItYHpdqVp5/oFLT5QqbopnkKlyFG9EW/9nhM6/yfObeKt6Su0wkBio6AizgRHGNwhJuAtlE5VIjow5JOTrip6w==", - "dependencies": { - "Microsoft.Extensions.Configuration": "8.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", - "Microsoft.Extensions.Configuration.Binder": "8.0.0", - "Microsoft.Extensions.Configuration.CommandLine": "8.0.0", - "Microsoft.Extensions.Configuration.EnvironmentVariables": "8.0.0", - "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", - "Microsoft.Extensions.Configuration.Json": "8.0.0", - "Microsoft.Extensions.Configuration.UserSecrets": "8.0.0", - "Microsoft.Extensions.DependencyInjection": "8.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", - "Microsoft.Extensions.Diagnostics": "8.0.0", - "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", - "Microsoft.Extensions.FileProviders.Physical": "8.0.0", - "Microsoft.Extensions.Hosting.Abstractions": "8.0.0", - "Microsoft.Extensions.Logging": "8.0.0", - "Microsoft.Extensions.Logging.Abstractions": "8.0.0", - "Microsoft.Extensions.Logging.Configuration": "8.0.0", - "Microsoft.Extensions.Logging.Console": "8.0.0", - "Microsoft.Extensions.Logging.Debug": "8.0.0", - "Microsoft.Extensions.Logging.EventLog": "8.0.0", - "Microsoft.Extensions.Logging.EventSource": "8.0.0", - "Microsoft.Extensions.Options": "8.0.0" - } - }, "Microsoft.Extensions.Hosting.Abstractions": { "type": "Transitive", "resolved": "8.0.0", @@ -208,29 +62,6 @@ "Microsoft.Extensions.Logging.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.Http": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "cWz4caHwvx0emoYe7NkHPxII/KkTI8R/LC9qdqJqnKv2poTJ4e2qqPGQqvRoQ5kaSA4FU5IV3qFAuLuOhoqULQ==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", - "Microsoft.Extensions.Diagnostics": "8.0.0", - "Microsoft.Extensions.Logging": "8.0.0", - "Microsoft.Extensions.Logging.Abstractions": "8.0.0", - "Microsoft.Extensions.Options": "8.0.0" - } - }, - "Microsoft.Extensions.Logging": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection": "8.0.0", - "Microsoft.Extensions.Logging.Abstractions": "8.0.0", - "Microsoft.Extensions.Options": "8.0.0" - } - }, "Microsoft.Extensions.Logging.Abstractions": { "type": "Transitive", "resolved": "8.0.0", @@ -239,74 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.Logging.Configuration": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "ixXXV0G/12g6MXK65TLngYN9V5hQQRuV+fZi882WIoVJT7h5JvoYoxTEwCgdqwLjSneqh1O+66gM8sMr9z/rsQ==", - "dependencies": { - "Microsoft.Extensions.Configuration": "8.0.0", - "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", - "Microsoft.Extensions.Configuration.Binder": "8.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", - "Microsoft.Extensions.Logging": "8.0.0", - "Microsoft.Extensions.Logging.Abstractions": "8.0.0", - "Microsoft.Extensions.Options": "8.0.0", - "Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0" - } - }, - "Microsoft.Extensions.Logging.Console": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "e+48o7DztoYog+PY430lPxrM4mm3PbA6qucvQtUDDwVo4MO+ejMw7YGc/o2rnxbxj4isPxdfKFzTxvXMwAz83A==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", - "Microsoft.Extensions.Logging": "8.0.0", - "Microsoft.Extensions.Logging.Abstractions": "8.0.0", - "Microsoft.Extensions.Logging.Configuration": "8.0.0", - "Microsoft.Extensions.Options": "8.0.0", - "System.Text.Json": "8.0.0" - } - }, - "Microsoft.Extensions.Logging.Debug": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "dt0x21qBdudHLW/bjMJpkixv858RRr8eSomgVbU8qljOyfrfDGi1JQvpF9w8S7ziRPtRKisuWaOwFxJM82GxeA==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", - "Microsoft.Extensions.Logging": "8.0.0", - "Microsoft.Extensions.Logging.Abstractions": "8.0.0" - } - }, - "Microsoft.Extensions.Logging.EventLog": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "3X9D3sl7EmOu7vQp5MJrmIJBl5XSdOhZPYXUeFfYa6Nnm9+tok8x3t3IVPLhm7UJtPOU61ohFchw8rNm9tIYOQ==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", - "Microsoft.Extensions.Logging": "8.0.0", - "Microsoft.Extensions.Logging.Abstractions": "8.0.0", - "Microsoft.Extensions.Options": "8.0.0", - "System.Diagnostics.EventLog": "8.0.0" - } - }, - "Microsoft.Extensions.Logging.EventSource": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "oKcPMrw+luz2DUAKhwFXrmFikZWnyc8l2RKoQwqU3KIZZjcfoJE0zRHAnqATfhRZhtcbjl/QkiY2Xjxp0xu+6w==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", - "Microsoft.Extensions.Logging": "8.0.0", - "Microsoft.Extensions.Logging.Abstractions": "8.0.0", - "Microsoft.Extensions.Options": "8.0.0", - "Microsoft.Extensions.Primitives": "8.0.0", - "System.Text.Json": "8.0.0" - } - }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -316,179 +79,29 @@ "Microsoft.Extensions.Primitives": "8.0.0" } }, - "Microsoft.Extensions.Options.ConfigurationExtensions": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "0f4DMRqEd50zQh+UyJc+/HiBsZ3vhAQALgdkcQEalSH1L2isdC7Yj54M3cyo5e+BeO5fcBQ7Dxly8XiBBcvRgw==", - "dependencies": { - "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", - "Microsoft.Extensions.Configuration.Binder": "8.0.0", - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", - "Microsoft.Extensions.Options": "8.0.0", - "Microsoft.Extensions.Primitives": "8.0.0" - } - }, "Microsoft.Extensions.Primitives": { "type": "Transitive", "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Microsoft.IdentityModel.Abstractions": { - "type": "Transitive", - "resolved": "7.6.2", - "contentHash": "ULeyJwfYTMHOAArrBZorjPyM/BL5PFfwRzDtxlOxawO9vB/wVmHmbzZnOyHCOLJjel7XiVNmVnAs3H0jh4/9jQ==" - }, - "Microsoft.IdentityModel.JsonWebTokens": { - "type": "Transitive", - "resolved": "7.6.2", - "contentHash": "ySbY72MsWw7BnSZw0fCsmp/oMou8ntJkfuZUBcplV3ncXMzxcXCn3fK6Gg2YLnTT6F2G9JXl9zc2lwfVfGOWEA==", - "dependencies": { - "Microsoft.IdentityModel.Tokens": "7.6.2" - } - }, - "Microsoft.IdentityModel.Logging": { - "type": "Transitive", - "resolved": "7.6.2", - "contentHash": "0brV311MYxGz7Numa+pbVsxbz5tfe2nbAig1b5tQb3h/L1y5lkoPyOgD0qAfI0iX1njbwr8l9NdxIT1cDbzWKA==", - "dependencies": { - "Microsoft.IdentityModel.Abstractions": "7.6.2" - } - }, - "Microsoft.IdentityModel.Tokens": { - "type": "Transitive", - "resolved": "7.6.2", - "contentHash": "pLnhCq9UNKWkn83zutkObYuzA+sOzx6VZpPI8hB8gD/vAXVt14D0SJ0sKPftwufvAbYGSNRda1vw/IFLbkjxNg==", - "dependencies": { - "Microsoft.IdentityModel.Logging": "7.6.2" - } - }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, - "Serilog.Extensions.Hosting": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "db0OcbWeSCvYQkHWu6n0v40N4kKaTAXNjlM3BKvcbwvNzYphQFcBR+36eQ/7hMMwOkJvAyLC2a9/jNdUL5NjtQ==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", - "Microsoft.Extensions.Hosting.Abstractions": "8.0.0", - "Microsoft.Extensions.Logging.Abstractions": "8.0.0", - "Serilog": "3.1.1", - "Serilog.Extensions.Logging": "8.0.0" - } - }, - "Serilog.Extensions.Logging": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "YEAMWu1UnWgf1c1KP85l1SgXGfiVo0Rz6x08pCiPOIBt2Qe18tcZLvdBUuV5o1QHvrs8FAry9wTIhgBRtjIlEg==", - "dependencies": { - "Microsoft.Extensions.Logging": "8.0.0", - "Serilog": "3.1.1" - } - }, - "Serilog.Settings.Configuration": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "nR0iL5HwKj5v6ULo3/zpP8NMcq9E2pxYA6XKTSWCbugVs4YqPyvaqaKOY+OMpPivKp7zMEpax2UKHnDodbRB0Q==", - "dependencies": { - "Microsoft.Extensions.Configuration.Binder": "8.0.0", - "Microsoft.Extensions.DependencyModel": "8.0.0", - "Serilog": "3.1.1" - } - }, - "Serilog.Sinks.Console": { - "type": "Transitive", - "resolved": "5.0.1", - "contentHash": "6Jt8jl9y2ey8VV7nVEUAyjjyxjAQuvd5+qj4XYAT9CwcsvR70HHULGBeD+K2WCALFXf7CFsNQT4lON6qXcu2AA==", - "dependencies": { - "Serilog": "3.1.1" - } - }, - "Serilog.Sinks.File": { - "type": "Transitive", - "resolved": "6.0.0", - "contentHash": "lxjg89Y8gJMmFxVkbZ+qDgjl+T4yC5F7WSLTvA+5q0R04tfKVLRL/EHpYoJ/MEQd2EeCKDuylBIVnAYMotmh2A==", - "dependencies": { - "Serilog": "4.0.0" - } - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", "contentHash": "c9xLpVz6PL9lp/djOWtk5KPDZq3cSYpmXoJQY524EOtuFl5z9ZtsotpsyrDW40U1DRnQSYvcPKEUV0X//u6gkQ==" }, - "System.Diagnostics.EventLog": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "fdYxcRjQqTTacKId/2IECojlDSFvp7LP5N78+0z/xH7v/Tuw5ZAxu23Y6PTCRinqyu2ePx+Gn1098NC6jM6d+A==" - }, - "System.IdentityModel.Tokens.Jwt": { - "type": "Transitive", - "resolved": "7.6.2", - "contentHash": "dyvPIzxohovbECESKj9ep7yShujU5oN9dKYR3ivvoTM7nLANNrBC5jN9ysZfY5Hp/Xs0R1b79IsdHuu6D4xwow==", - "dependencies": { - "Microsoft.IdentityModel.JsonWebTokens": "7.6.2", - "Microsoft.IdentityModel.Tokens": "7.6.2" - } - }, "System.Text.Encodings.Web": { "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==" - }, - "System.Text.Json": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==", - "dependencies": { - "System.Text.Encodings.Web": "8.0.0" - } + "resolved": "4.5.0", + "contentHash": "Xg4G4Indi4dqP1iuAiMSwpiWS54ZghzR644OtsRCm/m/lBMG8dUBhLVN7hLm8NNrNTR+iGbshCPTwrvxZPlm4g==" }, "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "empostor.api.innersloth.generator": { - "type": "Project" - }, - "empostor.server": { - "type": "Project", - "dependencies": { - "Empostor.Api": "[2.0.0-dev, )", - "Empostor.Api.Innersloth.Generator": "[2.0.0-dev, )", - "Microsoft.Extensions.FileSystemGlobbing": "[8.0.0, )", - "Microsoft.Extensions.Hosting": "[8.0.0, )", - "Microsoft.Extensions.Http": "[8.0.0, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog.Extensions.Hosting": "[8.0.0, )", - "Serilog.Settings.Configuration": "[8.0.0, )", - "Serilog.Sinks.Console": "[5.0.1, )", - "Serilog.Sinks.File": "[6.0.0, )", - "System.IdentityModel.Tokens.Jwt": "[7.6.2, )" - } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.PlayerStats/packages.lock.json b/src/Empostor.Plugins.PlayerStats/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugins.PlayerStats/packages.lock.json +++ b/src/Empostor.Plugins.PlayerStats/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.Privacy/packages.lock.json b/src/Empostor.Plugins.Privacy/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugins.Privacy/packages.lock.json +++ b/src/Empostor.Plugins.Privacy/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.QqVerify/packages.lock.json b/src/Empostor.Plugins.QqVerify/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugins.QqVerify/packages.lock.json +++ b/src/Empostor.Plugins.QqVerify/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.Titles/packages.lock.json b/src/Empostor.Plugins.Titles/packages.lock.json index ac11d80..27674f3 100644 --- a/src/Empostor.Plugins.Titles/packages.lock.json +++ b/src/Empostor.Plugins.Titles/packages.lock.json @@ -2,11 +2,6 @@ "version": 1, "dependencies": { "net8.0": { - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -34,8 +29,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics.Abstractions": { "type": "Transitive", @@ -75,11 +70,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -94,11 +84,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -112,25 +97,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Plugins.Welcome/packages.lock.json b/src/Empostor.Plugins.Welcome/packages.lock.json index 889b108..dcce8c0 100644 --- a/src/Empostor.Plugins.Welcome/packages.lock.json +++ b/src/Empostor.Plugins.Welcome/packages.lock.json @@ -16,11 +16,6 @@ "Microsoft.Extensions.Options": "8.0.0" } }, - "BouncyCastle.Cryptography": { - "type": "Transitive", - "resolved": "2.6.1", - "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" - }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -73,8 +68,8 @@ }, "Microsoft.Extensions.DependencyInjection.Abstractions": { "type": "Transitive", - "resolved": "9.0.6", - "contentHash": "0Zn6nR/6g+90MxskZyOOMPQvnPnrrGu6bytPwkV+azDcTtCSuQ1+GJUrg8Klmnrjk1i6zMpw2lXijl+tw7Q3kA==" + "resolved": "8.0.0", + "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" }, "Microsoft.Extensions.Diagnostics": { "type": "Transitive", @@ -134,11 +129,6 @@ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" } }, - "Microsoft.Extensions.ObjectPool": { - "type": "Transitive", - "resolved": "8.0.1", - "contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA==" - }, "Microsoft.Extensions.Options": { "type": "Transitive", "resolved": "8.0.0", @@ -165,11 +155,6 @@ "resolved": "8.0.0", "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" }, - "Serilog": { - "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" - }, "System.Diagnostics.DiagnosticSource": { "type": "Transitive", "resolved": "8.0.0", @@ -183,25 +168,11 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } } } diff --git a/src/Empostor.Server/Empostor.Server.csproj b/src/Empostor.Server/Empostor.Server.csproj index 4f14fcc..95a918b 100644 --- a/src/Empostor.Server/Empostor.Server.csproj +++ b/src/Empostor.Server/Empostor.Server.csproj @@ -18,10 +18,9 @@ - - + diff --git a/src/Empostor.Server/packages.lock.json b/src/Empostor.Server/packages.lock.json index 9fb6c34..3ecab70 100644 --- a/src/Empostor.Server/packages.lock.json +++ b/src/Empostor.Server/packages.lock.json @@ -2,6 +2,19 @@ "version": 1, "dependencies": { "net8.0": { + "Empostor.Hazel": { + "type": "Direct", + "requested": "[1.0.2, )", + "resolved": "1.0.2", + "contentHash": "cblWCgvLcQ2xK6ztV04RVrghVEnJpCWe4N6G3LCNaJhuUq367a1/bbtQxUWAflqvgSvGwY3g3SClhh9eWTCBDA==", + "dependencies": { + "BouncyCastle.Cryptography": "2.6.1", + "Empostor.Hazel.Abstractions": "1.0.2", + "Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.6", + "Microsoft.Extensions.ObjectPool": "8.0.1", + "Serilog": "4.3.1" + } + }, "Microsoft.Extensions.FileSystemGlobbing": { "type": "Direct", "requested": "[8.0.0, )", @@ -121,6 +134,11 @@ "resolved": "2.6.1", "contentHash": "vZsG2YILhthgRqO+ZVgRff4ZFKKTl0v7kqaVBLCtRvpREhfBP33pcWrdA3PRYgWuFL1RxiUFvjMUHTdBZlJcoA==" }, + "Empostor.Hazel.Abstractions": { + "type": "Transitive", + "resolved": "1.0.2", + "contentHash": "uJqGMASOGj+ELffmIMqubyvJ/FHjOXA1RtQdS38s1LRhP+Eu4zJMTTndr12+Q3vS0kHggFFyuExFmNxWyzWmig==" + }, "Microsoft.AspNetCore.Http.Abstractions": { "type": "Transitive", "resolved": "2.2.0", @@ -426,8 +444,8 @@ }, "Serilog": { "type": "Transitive", - "resolved": "4.3.1-dev-02373", - "contentHash": "f0HNPaleOox5++8zqxAdi9afnUUkoznLOmd0ur/UnLbzl8bIaPyyBGOpbIJmC1kz2vHfkQ0fXh6KXMdlz7bcLQ==" + "resolved": "4.3.1", + "contentHash": "savYe7h5yRlkqBVOwP8cIRDOdqKiPmYCU4W87JH38sBmcKD5EBoXvQIw6bNEvZ/pTe1gsiye3VFCzBsoppGkXQ==" }, "Serilog.Extensions.Logging": { "type": "Transitive", @@ -464,11 +482,10 @@ "empostor.api": { "type": "Project", "dependencies": { + "Empostor.Hazel": "[1.0.2, )", "Microsoft.AspNetCore.Http.Abstractions": "[2.2.0, )", "Microsoft.Extensions.Hosting.Abstractions": "[8.0.0, )", - "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )", - "NextFast.Hazel": "[1.0.2-dev, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )" + "Microsoft.Extensions.Logging.Abstractions": "[8.0.0, )" } }, "empostor.api.innersloth.generator": { @@ -479,19 +496,6 @@ "dependencies": { "Empostor.Api": "[2.0.0-dev, )" } - }, - "NextFast.Hazel": { - "type": "Project", - "dependencies": { - "BouncyCastle.Cryptography": "[2.6.1, )", - "Microsoft.Extensions.DependencyInjection.Abstractions": "[9.0.6, )", - "Microsoft.Extensions.ObjectPool": "[8.0.1, )", - "NextFast.Hazel.Abstractions": "[1.0.2-dev, )", - "Serilog": "[4.3.1-dev-02373, )" - } - }, - "NextFast.Hazel.Abstractions": { - "type": "Project" } }, "net8.0/linux-arm": { diff --git a/src/Empostor.sln b/src/Empostor.sln index bc81fec..5bcb53d 100644 --- a/src/Empostor.sln +++ b/src/Empostor.sln @@ -15,12 +15,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Empostor.Plugins.Welcome", EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{E0009DCB-32A6-45C4-A06C-7F62D4091A29}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hazel", "Hazel", "{A42D36F0-B635-4BBD-9F96-97AA17B1574A}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Next.Hazel", "NextFast.Hazel-New\Next.Hazel\Next.Hazel.csproj", "{07B43A32-0E0C-589F-4796-C15DE906326F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Next.Hazel.Abstractions", "NextFast.Hazel-New\Next.Hazel.Abstractions\Next.Hazel.Abstractions.csproj", "{5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Empostor.Plugins.FixedCode", "Empostor.Plugins.FixedCode\Empostor.Plugins.FixedCode.csproj", "{C583BD2A-1468-99CA-4E3D-CBDA4D2EDB9F}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Empostor.Plugins.FriendCodeValidator", "Empostor.Plugins.FriendCodeValidator\Empostor.Plugins.FriendCodeValidator.csproj", "{70CD7AC9-1DE3-CD23-602A-EFD504B91450}" @@ -123,30 +117,6 @@ Global {AA000002-0000-0000-0000-000000000002}.Release|x64.Build.0 = Release|Any CPU {AA000002-0000-0000-0000-000000000002}.Release|x86.ActiveCfg = Release|Any CPU {AA000002-0000-0000-0000-000000000002}.Release|x86.Build.0 = Release|Any CPU - {07B43A32-0E0C-589F-4796-C15DE906326F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {07B43A32-0E0C-589F-4796-C15DE906326F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {07B43A32-0E0C-589F-4796-C15DE906326F}.Debug|x64.ActiveCfg = Debug|Any CPU - {07B43A32-0E0C-589F-4796-C15DE906326F}.Debug|x64.Build.0 = Debug|Any CPU - {07B43A32-0E0C-589F-4796-C15DE906326F}.Debug|x86.ActiveCfg = Debug|Any CPU - {07B43A32-0E0C-589F-4796-C15DE906326F}.Debug|x86.Build.0 = Debug|Any CPU - {07B43A32-0E0C-589F-4796-C15DE906326F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {07B43A32-0E0C-589F-4796-C15DE906326F}.Release|Any CPU.Build.0 = Release|Any CPU - {07B43A32-0E0C-589F-4796-C15DE906326F}.Release|x64.ActiveCfg = Release|Any CPU - {07B43A32-0E0C-589F-4796-C15DE906326F}.Release|x64.Build.0 = Release|Any CPU - {07B43A32-0E0C-589F-4796-C15DE906326F}.Release|x86.ActiveCfg = Release|Any CPU - {07B43A32-0E0C-589F-4796-C15DE906326F}.Release|x86.Build.0 = Release|Any CPU - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}.Debug|x64.ActiveCfg = Debug|Any CPU - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}.Debug|x64.Build.0 = Debug|Any CPU - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}.Debug|x86.ActiveCfg = Debug|Any CPU - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}.Debug|x86.Build.0 = Debug|Any CPU - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}.Release|Any CPU.Build.0 = Release|Any CPU - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}.Release|x64.ActiveCfg = Release|Any CPU - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}.Release|x64.Build.0 = Release|Any CPU - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}.Release|x86.ActiveCfg = Release|Any CPU - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A}.Release|x86.Build.0 = Release|Any CPU {C583BD2A-1468-99CA-4E3D-CBDA4D2EDB9F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C583BD2A-1468-99CA-4E3D-CBDA4D2EDB9F}.Debug|Any CPU.Build.0 = Debug|Any CPU {C583BD2A-1468-99CA-4E3D-CBDA4D2EDB9F}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -346,8 +316,6 @@ Global GlobalSection(NestedProjects) = preSolution {70F97BB7-12A1-4C7A-B2A5-B962D14B813E} = {E0009DCB-32A6-45C4-A06C-7F62D4091A29} {AA000002-0000-0000-0000-000000000002} = {E0009DCB-32A6-45C4-A06C-7F62D4091A29} - {07B43A32-0E0C-589F-4796-C15DE906326F} = {A42D36F0-B635-4BBD-9F96-97AA17B1574A} - {5F7A70A7-1FE9-0B48-FFC1-C0F88BE0547A} = {A42D36F0-B635-4BBD-9F96-97AA17B1574A} {C583BD2A-1468-99CA-4E3D-CBDA4D2EDB9F} = {E0009DCB-32A6-45C4-A06C-7F62D4091A29} {70CD7AC9-1DE3-CD23-602A-EFD504B91450} = {E0009DCB-32A6-45C4-A06C-7F62D4091A29} {3038597E-E1A1-2958-1CF7-C4203A85F424} = {E0009DCB-32A6-45C4-A06C-7F62D4091A29} diff --git a/src/NextFast.Hazel-New/.gitignore b/src/NextFast.Hazel-New/.gitignore deleted file mode 100644 index 38c1408..0000000 --- a/src/NextFast.Hazel-New/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/.vscode -/build -/.vs -/src/Empostor.Plugins.Debugger/Properties/launchSettings.json -/tools - -.local/ diff --git a/src/NextFast.Hazel-New/Directory.Build.props b/src/NextFast.Hazel-New/Directory.Build.props deleted file mode 100644 index b8a6980..0000000 --- a/src/NextFast.Hazel-New/Directory.Build.props +++ /dev/null @@ -1,15 +0,0 @@ - - - net8.0 - latest - Empostor,Next-Fast - MIT - https://github.com/Next-Fast/Empostor.Hazel - git - 1.0.2 - dev - MIT - true - snupkg - - \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Hazel.sln b/src/NextFast.Hazel-New/Hazel.sln deleted file mode 100644 index 8b7f0dc..0000000 --- a/src/NextFast.Hazel-New/Hazel.sln +++ /dev/null @@ -1,37 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30523.141 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Next.Hazel", "Next.Hazel\Next.Hazel.csproj", "{02CFBD30-D77D-400F-94B2-700F60EFDD7F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Next.Hazel.Abstractions", "Next.Hazel.Abstractions\Next.Hazel.Abstractions.csproj", "{51FD3233-44D5-43BC-A618-A381703EDAD3}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Empostor.Hazel.Tests", "Empostor.Hazel.Tests\Empostor.Hazel.Tests.csproj", "{6CC1050D-4142-454E-BA09-974DF77D2C10}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {02CFBD30-D77D-400F-94B2-700F60EFDD7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {02CFBD30-D77D-400F-94B2-700F60EFDD7F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {02CFBD30-D77D-400F-94B2-700F60EFDD7F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {02CFBD30-D77D-400F-94B2-700F60EFDD7F}.Release|Any CPU.Build.0 = Release|Any CPU - {51FD3233-44D5-43BC-A618-A381703EDAD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {51FD3233-44D5-43BC-A618-A381703EDAD3}.Debug|Any CPU.Build.0 = Debug|Any CPU - {51FD3233-44D5-43BC-A618-A381703EDAD3}.Release|Any CPU.ActiveCfg = Release|Any CPU - {51FD3233-44D5-43BC-A618-A381703EDAD3}.Release|Any CPU.Build.0 = Release|Any CPU - {6CC1050D-4142-454E-BA09-974DF77D2C10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6CC1050D-4142-454E-BA09-974DF77D2C10}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6CC1050D-4142-454E-BA09-974DF77D2C10}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6CC1050D-4142-454E-BA09-974DF77D2C10}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {8AC8C0A6-FB6B-4E63-9042-EDF10C6A51B8} - EndGlobalSection -EndGlobal diff --git a/src/NextFast.Hazel-New/LICENSE b/src/NextFast.Hazel-New/LICENSE deleted file mode 100644 index f3ad895..0000000 --- a/src/NextFast.Hazel-New/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2018 Innersloth LLC -Copyright (c) 2016-2017 DarkRift Networking - -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. diff --git a/src/NextFast.Hazel-New/Next.Hazel.Abstractions/IMessageReader.cs b/src/NextFast.Hazel-New/Next.Hazel.Abstractions/IMessageReader.cs deleted file mode 100644 index 0f78a77..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel.Abstractions/IMessageReader.cs +++ /dev/null @@ -1,75 +0,0 @@ -namespace Next.Hazel.Abstractions; - -public interface IMessageReader : IDisposable -{ - /// - /// Gets the tag of the message. - /// - byte Tag { get; } - - /// - /// Gets the buffer of the message. - /// - byte[]? Buffer { get; } - - /// - /// Gets the offset of our current in the entire . - /// - int Offset { get; } - - /// - /// Gets the current position of the reader. - /// - int Position { get; } - - /// - /// Gets the length of the buffer. - /// - int Length { get; } - - int BytesRemaining { get; } - - IMessageReader? Parent { get; } - - IMessageReader ReadMessage(); - - bool ReadBoolean(); - - sbyte ReadSByte(); - - byte ReadByte(); - - ushort ReadUInt16(); - - short ReadInt16(); - - uint ReadUInt32(); - - int ReadInt32(); - - ulong ReadUInt64(); - - long ReadInt64(); - - float ReadSingle(); - - string ReadString(int length); - - string ReadString(); - - ReadOnlyMemory ReadBytesAndSize(); - - ReadOnlyMemory ReadBytes(int length); - - int ReadPackedInt32(); - - uint ReadPackedUInt32(); - - void CopyTo(IMessageWriter writer); - - void Seek(int position); - - void RemoveMessage(IMessageReader message); - - IMessageReader Copy(int offset = 0); -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel.Abstractions/IMessageWriter.cs b/src/NextFast.Hazel-New/Next.Hazel.Abstractions/IMessageWriter.cs deleted file mode 100644 index 0406443..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel.Abstractions/IMessageWriter.cs +++ /dev/null @@ -1,137 +0,0 @@ -using System.Net; - -namespace Next.Hazel.Abstractions; - -/// -/// Base message writer. -/// -public interface IMessageWriter : IDisposable -{ - public byte[] Buffer { get; } - - public int Length { get; set; } - - public int Position { get; set; } - - public MessageType SendOption { get; } - - /// - /// Copies the contents of this writer into a new array. - /// - /// Whether to include message header in the array. - /// An array containing the data in the current writer. - byte[] ToByteArray(bool includeHeader); - - /// - /// Writes a boolean to the message. - /// - /// Value to write. - void Write(bool value); - - /// - /// Writes a sbyte to the message. - /// - /// Value to write. - void Write(sbyte value); - - /// - /// Writes a byte to the message. - /// - /// Value to write. - void Write(byte value); - - /// - /// Writes a short to the message. - /// - /// Value to write. - void Write(short value); - - /// - /// Writes an ushort to the message. - /// - /// Value to write. - void Write(ushort value); - - /// - /// Writes an uint to the message. - /// - /// Value to write. - void Write(uint value); - - /// - /// Writes an int to the message. - /// - /// Value to write. - void Write(int value); - - /// - /// Writes an ulong to the message. - /// - /// Value to write. - void Write(ulong value); - - /// - /// Writes an ulong to the message. - /// - /// Value to write. - void Write(long value); - - /// - /// Writes a float to the message. - /// - /// Value to write. - void Write(float value); - - /// - /// Writes a string to the message. - /// - /// Value to write. - void Write(string value); - - /// - /// Writes a to the message. - /// - /// Value to write. - void Write(IPAddress value); - - /// - /// Writes an packed int to the message. - /// - /// Value to write. - void WritePacked(int value); - - /// - /// Writes an packed uint to the message. - /// - /// Value to write. - void WritePacked(uint value); - - /// - /// Writes raw bytes to the message. - /// - /// Bytes to write. - void Write(ReadOnlyMemory data); - - void WriteBytesAndSize(byte[] bytes); - - void WriteBytesAndSize(byte[] bytes, int length); - - void WriteBytesAndSize(byte[] bytes, int offset, int length); - - /// - /// Starts a new message. - /// - /// Message flag header. - void StartMessage(byte typeFlag); - - /// - /// Mark the end of the message. - /// - void EndMessage(); - - /// - /// Clear the message writer. - /// - /// New type of the message. - void Clear(MessageType type); -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel.Abstractions/IMessageWriterProvider.cs b/src/NextFast.Hazel-New/Next.Hazel.Abstractions/IMessageWriterProvider.cs deleted file mode 100644 index ec7a4fe..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel.Abstractions/IMessageWriterProvider.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Next.Hazel.Abstractions; - -public interface IMessageWriterProvider -{ - /// - /// Retrieves a from the internal pool. - /// Make sure to call when you are done!. - /// - /// - /// Whether to send the message as or . - /// Reliable packets will ensure delivery while unreliable packets may be lost. - /// - /// A from the pool. - IMessageWriter Get(MessageType sendOption = MessageType.Unreliable); -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel.Abstractions/MessageType.cs b/src/NextFast.Hazel-New/Next.Hazel.Abstractions/MessageType.cs deleted file mode 100644 index 1c33fde..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel.Abstractions/MessageType.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace Next.Hazel.Abstractions; - -/// -/// Specifies how a message should be sent between connections. -/// -[Flags] -public enum MessageType : byte -{ - /// - /// Requests unreliable delivery with no fragmentation. - /// - /// - /// Sending data using unreliable delivery means that data is not guaranteed to arrive at it's destination nor is - /// it guaranteed to arrive only once. However, unreliable delivery can be faster than other methods and it - /// typically requires a smaller number of protocol bytes than other methods. There is also typically less - /// processing involved and less memory needed as packets are not stored once sent. - /// - Unreliable, - - /// - /// Requests data be sent reliably but with no fragmentation. - /// - /// - /// Sending data reliably means that data is guaranteed to arrive and to arrive only once. Reliable delivery - /// typically requires more processing, more memory (as packets need to be stored in case they need resending), - /// a larger number of protocol bytes and can be slower than unreliable delivery. - /// - Reliable -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel.Abstractions/Next.Hazel.Abstractions.csproj b/src/NextFast.Hazel-New/Next.Hazel.Abstractions/Next.Hazel.Abstractions.csproj deleted file mode 100644 index f72ce49..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel.Abstractions/Next.Hazel.Abstractions.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - enable - enable - true - Next.Hazel.Abstractions - Next.Hazel.Abstractions - true - NextFast.Hazel.Abstractions - - - diff --git a/src/NextFast.Hazel-New/Next.Hazel/ByteSpan.cs b/src/NextFast.Hazel-New/Next.Hazel/ByteSpan.cs deleted file mode 100644 index 355d430..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/ByteSpan.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System; - -namespace Next.Hazel; - -/// -/// This is a minimal implementation of `System.Span` in .NET 5.0 -/// -public struct ByteSpan -{ - private readonly byte[] array_; - - /// - /// Create a new span object containing an entire array - /// - public ByteSpan(byte[] array) - { - if (array == null) - { - array_ = null; - Offset = 0; - Length = 0; - } - else - { - array_ = array; - Offset = 0; - Length = array.Length; - } - } - - /// - /// Creates a new span object containing a subset of an array - /// - public ByteSpan(byte[] array, int offset, int length) - { - if (array == null) - { - if (offset != 0) throw new ArgumentException("Invalid offset", nameof(offset)); - if (length != 0) throw new ArgumentException("Invalid length", nameof(offset)); - - array_ = null; - Offset = 0; - Length = 0; - } - else - { - if (offset < 0 || offset > array.Length) throw new ArgumentException("Invalid offset", nameof(offset)); - if (length < 0) throw new ArgumentException($"Invalid length: {length}", nameof(length)); - if (offset + length > array.Length) - throw new ArgumentException( - $"Invalid length. Length: {length} Offset: {offset} Array size: {array.Length}", nameof(length)); - - array_ = array; - Offset = offset; - Length = length; - } - } - - /// - /// Returns the underlying array. - /// WARNING: This does not return the span, but the entire underlying storage block - /// - public byte[] GetUnderlyingArray() - { - return array_; - } - - /// - /// Returns the offset into the underlying array - /// - public int Offset { get; } - - /// - /// Returns the length of the current span - /// - public int Length { get; } - - /// - /// Gets the span element at the specified index - /// - public byte this[int index] - { - get - { - if (index < 0 || index >= Length) throw new IndexOutOfRangeException(); - - return array_[Offset + index]; - } - set - { - if (index < 0 || index >= Length) throw new IndexOutOfRangeException(); - - array_[Offset + index] = value; - } - } - - /// - /// Create a new span that is a subset of this span [offset, this.Length-offset) - /// - public ByteSpan Slice(int offset) - { - return Slice(offset, Length - offset); - } - - /// - /// Create a new span that is a subset of this span [offset, length) - /// - public ByteSpan Slice(int offset, int length) - { - return new ByteSpan(array_, Offset + offset, length); - } - - /// - /// Copies the contents of the span to an array - /// - public void CopyTo(byte[] array, int offset) - { - CopyTo(new ByteSpan(array, offset, array.Length - offset)); - } - - /// - /// Copies the contents of the span to another span - /// - public void CopyTo(ByteSpan destination) - { - if (destination.Length < Length) - throw new ArgumentException("Destination span is shorter than source", nameof(destination)); - - if (Length > 0) Buffer.BlockCopy(array_, Offset, destination.array_, destination.Offset, Length); - } - - /// - /// Create a new array with the contents of this span - /// - public byte[] ToArray() - { - var result = new byte[Length]; - CopyTo(result); - return result; - } - - /// - /// Implicit conversion from byte[] -> ByteSpan - /// - public static implicit operator ByteSpan(byte[] array) - { - return new ByteSpan(array); - } - - /// - /// Retuns an empty span object - /// - public static ByteSpan Empty => new(null); -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/ByteSpanExtensions.cs b/src/NextFast.Hazel-New/Next.Hazel/ByteSpanExtensions.cs deleted file mode 100644 index 2dd7f12..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/ByteSpanExtensions.cs +++ /dev/null @@ -1,126 +0,0 @@ -namespace Next.Hazel; - -/// -/// Extension functions for (en/de)coding integer values -/// -public static class ByteSpanBigEndianExtensions -{ - // Write a 16-bit integer in big-endian format to output[0..2) - public static void WriteBigEndian16(this ByteSpan output, ushort value, int offset = 0) - { - output[offset + 0] = (byte)(value >> 8); - output[offset + 1] = (byte)(value >> 0); - } - - // Write a 24-bit integer in big-endian format to output[0..3) - public static void WriteBigEndian24(this ByteSpan output, uint value, int offset = 0) - { - output[offset + 0] = (byte)(value >> 16); - output[offset + 1] = (byte)(value >> 8); - output[offset + 2] = (byte)(value >> 0); - } - - // Write a 32-bit integer in big-endian format to output[0..4) - public static void WriteBigEndian32(this ByteSpan output, uint value, int offset) - { - output[offset + 0] = (byte)(value >> 24); - output[offset + 1] = (byte)(value >> 16); - output[offset + 2] = (byte)(value >> 8); - output[offset + 3] = (byte)(value >> 0); - } - - // Write a 48-bit integer in big-endian format to output[0..6) - public static void WriteBigEndian48(this ByteSpan output, ulong value, int offset = 0) - { - output[offset + 0] = (byte)(value >> 40); - output[offset + 1] = (byte)(value >> 32); - output[offset + 2] = (byte)(value >> 24); - output[offset + 3] = (byte)(value >> 16); - output[offset + 4] = (byte)(value >> 8); - output[offset + 5] = (byte)(value >> 0); - } - - // Write a 64-bit integer in big-endian format to output[0..8) - public static void WriteBigEndian64(this ByteSpan output, ulong value, int offset = 0) - { - output[offset + 0] = (byte)(value >> 56); - output[offset + 1] = (byte)(value >> 48); - output[offset + 2] = (byte)(value >> 40); - output[offset + 3] = (byte)(value >> 32); - output[offset + 4] = (byte)(value >> 24); - output[offset + 5] = (byte)(value >> 16); - output[offset + 6] = (byte)(value >> 8); - output[offset + 7] = (byte)(value >> 0); - } - - // Read a 16-bit integer in big-endian format from input[0..2) - public static ushort ReadBigEndian16(this ByteSpan input, int offset = 0) - { - ushort value = 0; - value |= (ushort)(input[offset + 0] << 8); - value |= (ushort)(input[offset + 1] << 0); - return value; - } - - // Read a 24-bit integer in big-endian format from input[0..3) - public static uint ReadBigEndian24(this ByteSpan input, int offset = 0) - { - uint value = 0; - value |= (uint)input[offset + 0] << 16; - value |= (uint)input[offset + 1] << 8; - value |= (uint)input[offset + 2] << 0; - return value; - } - - // Read a 48-bit integer in big-endian format from input[0..3) - public static ulong ReadBigEndian48(this ByteSpan input, int offset = 0) - { - ulong value = 0; - value |= (ulong)input[offset + 0] << 40; - value |= (ulong)input[offset + 1] << 32; - value |= (ulong)input[offset + 2] << 24; - value |= (ulong)input[offset + 3] << 16; - value |= (ulong)input[offset + 4] << 8; - value |= (ulong)input[offset + 5] << 0; - return value; - } -} - -public static class ByteSpanLittleEndianExtensions -{ - // Read a 24-bit integer in little-endian format from input[0..3) - public static uint ReadLittleEndian24(this ByteSpan input, int offset = 0) - { - uint value = 0; - value |= input[offset + 0]; - value |= (uint)input[offset + 1] << 8; - value |= (uint)input[offset + 2] << 16; - return value; - } - - // Read a 24-bit integer in little-endian format from input[0..4) - public static uint ReadLittleEndian32(this ByteSpan input, int offset = 0) - { - uint value = 0; - value |= input[offset + 0]; - value |= (uint)input[offset + 1] << 8; - value |= (uint)input[offset + 2] << 16; - value |= (uint)input[offset + 3] << 24; - return value; - } - - /// - /// Reuse an existing span if there is enough space, - /// otherwise allocate new storage - /// - /// - /// Source span we should attempt to reuse - /// - /// Required size (bytes) - public static ByteSpan ReuseSpanIfPossible(this ByteSpan source, int requiredSize) - { - if (source.Length >= requiredSize) return source[..requiredSize]; - - return new byte[requiredSize]; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Connection.cs b/src/NextFast.Hazel-New/Next.Hazel/Connection.cs deleted file mode 100644 index 9a512c2..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Connection.cs +++ /dev/null @@ -1,240 +0,0 @@ -using System; -using System.Net; -using System.Threading.Tasks; -using Next.Hazel.Abstractions; -using Serilog; - -namespace Next.Hazel; - -/// -/// Base class for all connections. -/// -/// -/// -/// Connection is the base class for all connections that Hazel can make. It provides common functionality and a -/// standard interface to allow connections to be swapped easily. -/// -/// -/// Any class inheriting from Connection should provide the 3 standard guarantees that Hazel provides: -/// -/// -/// Thread Safe -/// -/// -/// Connection Orientated -/// -/// -/// Packet/Message Based -/// -/// -/// -/// -/// -public abstract class Connection : IDisposable -{ - private static readonly ILogger Logger = Log.ForContext(); - - protected ConnectionState _state; - - /// - /// Called when a message has been received. - /// - /// - /// - /// DataReceived is invoked everytime a message is received from the end point of this connection, the message - /// that was received can be found in the alongside other information from the - /// event. - /// - /// - /// - /// - /// - /// - public Func DataReceived; - - /// - /// Called when the end point disconnects or an error occurs. - /// - /// - /// - /// Disconnected is invoked when the connection is closed due to an exception occuring or because the remote - /// end point disconnected. If it was invoked due to an exception occuring then the exception is available - /// in the passed with the event. - /// - /// - /// - /// - /// - /// - public Func Disconnected; - - protected int testDropCount = 0; - public int TestDropRate = 0; - - public int TestLagMs = -1; - - /// - /// Constructor that initializes the ConnecitonStatistics object. - /// - /// - /// This constructor initialises with empty statistics and sets to - /// . - /// - protected Connection() - { - Statistics = new ConnectionStatistics(); - State = ConnectionState.NotConnected; - } - - /// - /// The remote end point of this Connection. - /// - /// - /// This is the end point that this connection is connected to (i.e. the other device). This returns an abstract - /// which can then be cast to an appropriate end point depending on the - /// connection type. - /// - public IPEndPoint EndPoint { get; protected set; } - - public IPMode IPMode { get; protected set; } - - /// - /// The traffic statistics about this Connection. - /// - /// - /// Contains statistics about the number of messages and bytes sent and received by this connection. - /// - public ConnectionStatistics Statistics { get; protected set; } - - /// - /// The state of this connection. - /// - /// - /// All implementers should be aware that when this is set to ConnectionState.Connected it will - /// release all threads that are blocked on . - /// - public ConnectionState State - { - get => _state; - - protected set - { - _state = value; - SetState(value); - } - } - - /// - /// Disposes of this NetworkConnection. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void SetState(ConnectionState state) - { - } - - /// The message to send. - /// - /// - /// - /// The sendOptions parameter is only a request to use those options and the actual method used to send the - /// data is up to the implementation. There are circumstances where this parameter may be ignored but in - /// general any implementer should aim to always follow the user's request. - /// - /// - public abstract ValueTask SendAsync(IMessageWriter msg); - - /// The bytes of the message to send. - /// The option specifying how the message should be sent. - /// - /// - /// - /// The sendOptions parameter is only a request to use those options and the actual method used to send the - /// data is up to the implementation. There are circumstances where this parameter may be ignored but in - /// general any implementer should aim to always follow the user's request. - /// - /// - public abstract ValueTask SendBytes(byte[] bytes, MessageType sendOption = MessageType.Unreliable); - - /// - /// Connects the connection to a server and begins listening. - /// This method blocks and may thrown if there is a problem connecting. - /// - /// The bytes of data to send in the handshake. - /// The number of milliseconds to wait before giving up on the connect attempt. - public abstract ValueTask ConnectAsync(byte[] bytes = null, int timeout = 5000); - - /// - /// Invokes the DataReceived event. - /// - /// The bytes received. - /// - /// - /// Invokes the event on this connection to alert subscribers a new message has been - /// received. The bytes and the send option that the message was sent with should be passed in to give to the - /// subscribers. - /// - protected async ValueTask InvokeDataReceived(MessageReader msg, MessageType messageType) - { - // Make a copy to avoid race condition between null check and invocation - var handler = DataReceived; - if (handler != null) - try - { - await handler(new DataReceivedEventArgs(this, msg, messageType)); - } - catch (Exception e) - { - Logger.Error(e, "Invoking data received failed"); - await Disconnect("Invoking data received failed"); - } - } - - /// - /// Invokes the Disconnected event. - /// - /// The exception, if any, that occurred to cause this. - /// Extra disconnect data - /// - /// Invokes the event to alert subscribres this connection has been disconnected either - /// by the end point or because an error occurred. If an error occurred the error should be passed in in order to - /// pass to the subscribers, otherwise null can be passed in. - /// - protected async ValueTask InvokeDisconnected(string e, MessageReader reader) - { - // Make a copy to avoid race condition between null check and invocation - var handler = Disconnected; - if (handler != null) - try - { - await handler(new DisconnectedEventArgs(e, reader)); - } - catch (Exception ex) - { - Logger.Error(ex, "Error in InvokeDisconnected"); - } - } - - /// - /// For times when you want to force the disconnect handler to fire as well as close it. - /// If you only want to close it, just use Dispose. - /// - public abstract ValueTask Disconnect(string reason, MessageWriter writer = null); - - /// - /// Disposes of this NetworkConnection. - /// - /// Are we currently disposing? - protected virtual void Dispose(bool disposing) - { - if (disposing) - { - DataReceived = null; - Disconnected = null; - } - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/ConnectionListener.cs b/src/NextFast.Hazel-New/Next.Hazel/ConnectionListener.cs deleted file mode 100644 index fb2fad1..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/ConnectionListener.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System; -using System.Threading.Tasks; -using Next.Hazel.Abstractions; -using Serilog; - -namespace Next.Hazel; - -/// -/// Base class for all connection listeners. -/// -/// -/// -/// ConnectionListeners are server side objects that listen for clients and create matching server side connections -/// for each client in a similar way to TCP does. These connections should be ready for communication immediately. -/// -/// -/// Each time a client connects the event will be invoked to alert all subscribers to -/// the new connection. A disconnected event is then present on the that is passed to the -/// subscribers. -/// -/// -/// -public abstract class ConnectionListener : IAsyncDisposable -{ - private static readonly ILogger Logger = Log.ForContext(); - - /// - /// Invoked when a new client connects. - /// - /// - /// - /// NewConnection is invoked each time a client connects to the listener. The - /// contains the new for communication with this - /// client. - /// - /// - /// Hazel may or may not store connections so it is your responsibility to keep track and properly Dispose of - /// connections to your server. - /// - /// - /// - /// - /// - /// - public Func NewConnection; - - /// - /// Call to dispose of the connection listener. - /// - public virtual ValueTask DisposeAsync() - { - NewConnection = null; - return ValueTask.CompletedTask; - } - - /// - /// Makes this connection listener begin listening for connections. - /// - /// - /// - /// This instructs the listener to begin listening for new clients connecting to the server. When a new client - /// connects the event will be invoked containing the connection to the new client. - /// - /// - /// - /// - /// - public abstract Task StartAsync(); - - /// - /// Invokes the NewConnection event with the supplied connection. - /// - /// The user sent bytes that were received as part of the handshake. - /// The connection to pass in the arguments. - /// - /// Implementers should call this to invoke the event before data is received so that - /// subscribers do not miss any data that may have been sent immediately after connecting. - /// - internal async Task InvokeNewConnection(IMessageReader msg, Connection connection) - { - // Make a copy to avoid race condition between null check and invocation - var handler = NewConnection; - if (handler != null) - try - { - await handler(new NewConnectionEventArgs(msg, connection)); - } - catch (Exception e) - { - Logger.Error(e, "Accepting connection failed"); - await connection.Disconnect("Accepting connection failed"); - } - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/ConnectionState.cs b/src/NextFast.Hazel-New/Next.Hazel/ConnectionState.cs deleted file mode 100644 index 21a47e9..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/ConnectionState.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Next.Hazel; - -/// -/// Represents the state a is currently in. -/// -public enum ConnectionState -{ - /// - /// The Connection has either not been established yet or has been disconnected. - /// - NotConnected, - - /// - /// The Connection is currently connecting to an endpoint. - /// - Connecting, - - /// - /// The Connection is connected and data can be transfered. - /// - Connected -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/ConnectionStatistics.cs b/src/NextFast.Hazel-New/Next.Hazel/ConnectionStatistics.cs deleted file mode 100644 index fbaa9cb..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/ConnectionStatistics.cs +++ /dev/null @@ -1,455 +0,0 @@ -using System.Threading; - -namespace Next.Hazel; - -/// -/// Holds statistics about the traffic through a . -/// -/// -public class ConnectionStatistics -{ - private const int ExpectedMTU = 1200; - - /// - /// The number of acknowledgement messages received. - /// - private int acknowledgementMessagesReceived; - - /// - /// The number of acknowledgement messages sent. - /// - private int acknowledgementMessagesSent; - - /// - /// The number of bytes of data received. - /// - private long dataBytesReceived; - - /// - /// The number of bytes of data sent. - /// - private long dataBytesSent; - - /// - /// The number of messages sent larger than 576 bytes. - /// - private int fragmentableMessagesSent; - - /// - /// The number of fragmented messages received. - /// - private int fragmentedMessagesReceived; - - /// - /// The number of fragmented messages sent. - /// - private int fragmentedMessagesSent; - - /// - /// The number of hello messages received. - /// - private int helloMessagesReceived; - - /// - /// The number of hello messages sent. - /// - private int helloMessagesSent; - - private int messagesResent; - - /// - /// The number of hello messages received. - /// - private int pingMessagesReceived; - - /// - /// The number of reliable messages received. - /// - private int reliableMessagesReceived; - - /// - /// The number of unreliable messages sent. - /// - private int reliableMessagesSent; - - /// - /// The number of bytes received in total. - /// - private long totalBytesReceived; - - /// - /// The number of bytes sent in total. - /// - private long totalBytesSent; - - /// - /// The number of unreliable messages received. - /// - private int unreliableMessagesReceived; - - /// - /// The number of unreliable messages sent. - /// - private int unreliableMessagesSent; - - /// - /// The total number of messages sent. - /// - public int MessagesSent => UnreliableMessagesSent + ReliableMessagesSent + FragmentedMessagesSent + - AcknowledgementMessagesSent + HelloMessagesSent; - - /// - /// The number of messages sent larger than 576 bytes. This is smaller than most default MTUs. - /// - /// - /// This is the number of unreliable messages that were sent from the , incremented - /// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - public int FragmentableMessagesSent => fragmentableMessagesSent; - - /// - /// The number of unreliable messages sent. - /// - /// - /// This is the number of unreliable messages that were sent from the , incremented - /// each time that LogUnreliableSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - public int UnreliableMessagesSent => unreliableMessagesSent; - - /// - /// The number of reliable messages sent. - /// - /// - /// This is the number of reliable messages that were sent from the , incremented - /// each time that LogReliableSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - public int ReliableMessagesSent => reliableMessagesSent; - - /// - /// The number of fragmented messages sent. - /// - /// - /// This is the number of fragmented messages that were sent from the , incremented - /// each time that LogFragmentedSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - public int FragmentedMessagesSent => fragmentedMessagesSent; - - /// - /// The number of acknowledgement messages sent. - /// - /// - /// This is the number of acknowledgements that were sent from the , incremented - /// each time that LogAcknowledgementSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - public int AcknowledgementMessagesSent => acknowledgementMessagesSent; - - /// - /// The number of hello messages sent. - /// - /// - /// This is the number of hello messages that were sent from the , incremented - /// each time that LogHelloSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - public int HelloMessagesSent => helloMessagesSent; - - /// - /// The number of bytes of data sent. - /// - /// - /// - /// This is the number of bytes of data (i.e. user bytes) that were sent from the , - /// accumulated each time that LogSend is called by the Connection. Messages that caused an error are not - /// counted and messages are only counted once all other operations in the send are complete. - /// - /// - /// For the number of bytes including protocol bytes see . - /// - /// - public long DataBytesSent => Interlocked.Read(ref dataBytesSent); - - /// - /// The number of bytes sent in total. - /// - /// - /// - /// This is the total number of bytes (the data bytes plus protocol bytes) that were sent from the - /// , accumulated each time that LogSend is called by the Connection. Messages that - /// caused an error are not counted and messages are only counted once all other operations in the send are - /// complete. - /// - /// - /// For the number of data bytes excluding protocol bytes see . - /// - /// - public long TotalBytesSent => Interlocked.Read(ref totalBytesSent); - - /// - /// The total number of messages received. - /// - public int MessagesReceived => UnreliableMessagesReceived + ReliableMessagesReceived + FragmentedMessagesReceived + - AcknowledgementMessagesReceived + helloMessagesReceived; - - /// - /// The number of unreliable messages received. - /// - /// - /// This is the number of unreliable messages that were received by the , incremented - /// each time that LogUnreliableReceive is called by the Connection. Messages are counted before the receive event is - /// invoked. - /// - public int UnreliableMessagesReceived => unreliableMessagesReceived; - - /// - /// The number of reliable messages received. - /// - /// - /// This is the number of reliable messages that were received by the , incremented - /// each time that LogReliableReceive is called by the Connection. Messages are counted before the receive event is - /// invoked. - /// - public int ReliableMessagesReceived => reliableMessagesReceived; - - /// - /// The number of fragmented messages received. - /// - /// - /// This is the number of fragmented messages that were received by the , incremented - /// each time that LogFragmentedReceive is called by the Connection. Messages are counted before the receive event is - /// invoked. - /// - public int FragmentedMessagesReceived => fragmentedMessagesReceived; - - /// - /// The number of acknowledgement messages received. - /// - /// - /// This is the number of acknowledgement messages that were received by the , incremented - /// each time that LogAcknowledgemntReceive is called by the Connection. Messages are counted before the receive event - /// is invoked. - /// - public int AcknowledgementMessagesReceived => acknowledgementMessagesReceived; - - /// - /// The number of ping messages received. - /// - /// - /// This is the number of hello messages that were received by the , incremented - /// each time that LogHelloReceive is called by the Connection. Messages are counted before the receive event is - /// invoked. - /// - public int PingMessagesReceived => pingMessagesReceived; - - /// - /// The number of hello messages received. - /// - /// - /// This is the number of hello messages that were received by the , incremented - /// each time that LogHelloReceive is called by the Connection. Messages are counted before the receive event is - /// invoked. - /// - public int HelloMessagesReceived => helloMessagesReceived; - - /// - /// The number of bytes of data received. - /// - /// - /// - /// This is the number of bytes of data (i.e. user bytes) that were received by the , - /// accumulated each time that LogReceive is called by the Connection. Messages are counted before the receive - /// event is invoked. - /// - /// - /// For the number of bytes including protocol bytes see . - /// - /// - public long DataBytesReceived => Interlocked.Read(ref dataBytesReceived); - - /// - /// The number of bytes received in total. - /// - /// - /// - /// This is the total number of bytes (the data bytes plus protocol bytes) that were received by the - /// , accumulated each time that LogReceive is called by the Connection. Messages are - /// counted before the receive event is invoked. - /// - /// - /// For the number of data bytes excluding protocol bytes see . - /// - /// - public long TotalBytesReceived => Interlocked.Read(ref totalBytesReceived); - - public int MessagesResent => messagesResent; - - /// - /// Logs the sending of an unreliable data packet in the statistics. - /// - /// The number of bytes of data sent. - /// The total number of bytes sent. - /// - /// This should be called after the data has been sent and should only be called for data that is sent sucessfully. - /// - internal void LogUnreliableSend(int dataLength, int totalLength) - { - Interlocked.Increment(ref unreliableMessagesSent); - Interlocked.Add(ref dataBytesSent, dataLength); - Interlocked.Add(ref totalBytesSent, totalLength); - - if (totalLength > ExpectedMTU) Interlocked.Increment(ref fragmentableMessagesSent); - } - - /// - /// Logs the sending of a reliable data packet in the statistics. - /// - /// The number of bytes of data sent. - /// The total number of bytes sent. - /// - /// This should be called after the data has been sent and should only be called for data that is sent sucessfully. - /// - internal void LogReliableSend(int dataLength, int totalLength) - { - Interlocked.Increment(ref reliableMessagesSent); - Interlocked.Add(ref dataBytesSent, dataLength); - Interlocked.Add(ref totalBytesSent, totalLength); - - if (totalLength > ExpectedMTU) Interlocked.Increment(ref fragmentableMessagesSent); - } - - /// - /// Logs the sending of a fragmented data packet in the statistics. - /// - /// The number of bytes of data sent. - /// The total number of bytes sent. - /// - /// This should be called after the data has been sent and should only be called for data that is sent sucessfully. - /// - internal void LogFragmentedSend(int dataLength, int totalLength) - { - Interlocked.Increment(ref fragmentedMessagesSent); - Interlocked.Add(ref dataBytesSent, dataLength); - Interlocked.Add(ref totalBytesSent, totalLength); - - if (totalLength > ExpectedMTU) Interlocked.Increment(ref fragmentableMessagesSent); - } - - /// - /// Logs the sending of a acknowledgement data packet in the statistics. - /// - /// The total number of bytes sent. - /// - /// This should be called after the data has been sent and should only be called for data that is sent sucessfully. - /// - internal void LogAcknowledgementSend(int totalLength) - { - Interlocked.Increment(ref acknowledgementMessagesSent); - Interlocked.Add(ref totalBytesSent, totalLength); - } - - /// - /// Logs the sending of a hellp data packet in the statistics. - /// - /// The total number of bytes sent. - /// - /// This should be called after the data has been sent and should only be called for data that is sent sucessfully. - /// - internal void LogHelloSend(int totalLength) - { - Interlocked.Increment(ref helloMessagesSent); - Interlocked.Add(ref totalBytesSent, totalLength); - } - - /// - /// Logs the receiving of an unreliable data packet in the statistics. - /// - /// The number of bytes of data received. - /// The total number of bytes received. - /// - /// This should be called before the received event is invoked so it is up to date for subscribers to that event. - /// - internal void LogUnreliableReceive(int dataLength, int totalLength) - { - Interlocked.Increment(ref unreliableMessagesReceived); - Interlocked.Add(ref dataBytesReceived, dataLength); - Interlocked.Add(ref totalBytesReceived, totalLength); - } - - /// - /// Logs the receiving of a reliable data packet in the statistics. - /// - /// The number of bytes of data received. - /// The total number of bytes received. - /// - /// This should be called before the received event is invoked so it is up to date for subscribers to that event. - /// - internal void LogReliableReceive(int dataLength, int totalLength) - { - Interlocked.Increment(ref reliableMessagesReceived); - Interlocked.Add(ref dataBytesReceived, dataLength); - Interlocked.Add(ref totalBytesReceived, totalLength); - } - - /// - /// Logs the receiving of a fragmented data packet in the statistics. - /// - /// The number of bytes of data received. - /// The total number of bytes received. - /// - /// This should be called before the received event is invoked so it is up to date for subscribers to that event. - /// - internal void LogFragmentedReceive(int dataLength, int totalLength) - { - Interlocked.Increment(ref fragmentedMessagesReceived); - Interlocked.Add(ref dataBytesReceived, dataLength); - Interlocked.Add(ref totalBytesReceived, totalLength); - } - - /// - /// Logs the receiving of an acknowledgement data packet in the statistics. - /// - /// The total number of bytes received. - /// - /// This should be called before the received event is invoked so it is up to date for subscribers to that event. - /// - internal void LogAcknowledgementReceive(int totalLength) - { - Interlocked.Increment(ref acknowledgementMessagesReceived); - Interlocked.Add(ref totalBytesReceived, totalLength); - } - - /// - /// Logs the receiving of a hello data packet in the statistics. - /// - /// The total number of bytes received. - /// - /// This should be called before the received event is invoked so it is up to date for subscribers to that event. - /// - internal void LogPingReceive(int totalLength) - { - Interlocked.Increment(ref pingMessagesReceived); - Interlocked.Add(ref totalBytesReceived, totalLength); - } - - /// - /// Logs the receiving of a hello data packet in the statistics. - /// - /// The total number of bytes received. - /// - /// This should be called before the received event is invoked so it is up to date for subscribers to that event. - /// - internal void LogHelloReceive(int totalLength) - { - Interlocked.Increment(ref helloMessagesReceived); - Interlocked.Add(ref totalBytesReceived, totalLength); - } - - internal void LogMessageResent() - { - Interlocked.Increment(ref messagesResent); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Crypto/AesGcm.cs b/src/NextFast.Hazel-New/Next.Hazel/Crypto/AesGcm.cs deleted file mode 100644 index 80fb6c1..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Crypto/AesGcm.cs +++ /dev/null @@ -1,325 +0,0 @@ -using System; -using System.Diagnostics; - -namespace Next.Hazel.Crypto; - -/// -/// Implementation of AEAD_AES128_GCM based on: -/// * RFC 5116 [1] -/// * NIST SP 800-38d [2] -/// [1] https://tools.ietf.org/html/rfc5116 -/// [2] https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf -/// Adapted from: https://gist.github.com/mendsley/777e6bd9ae7eddcb2b0c0fe18247dc60 -/// -public class Aes128Gcm : IDisposable -{ - public const int KeySize = 16; - public const int NonceSize = 12; - public const int CiphertextOverhead = TagSize; - - private const int TagSize = 16; - private readonly ByteSpan blockJ_; - private readonly ByteSpan blockS_; - private readonly ByteSpan blockScratch_; - private readonly ByteSpan blockV_; - private readonly ByteSpan blockZ_; - - private readonly IAes encryptor_; - - private readonly ByteSpan hashSubkey_; - - /// - /// Creates a new instance of an AEAD_AES128_GCM cipher - /// - /// Symmetric key - public Aes128Gcm(ByteSpan key) - { - if (key.Length != KeySize) throw new ArgumentException("Invalid key length", nameof(key)); - - // Create the AES block cipher - encryptor_ = CryptoProvider.CreateAes(key); - - // Allocate scratch space - ByteSpan scratchSpace = new byte[96]; - hashSubkey_ = scratchSpace[..16]; - blockJ_ = scratchSpace.Slice(16, 16); - blockS_ = scratchSpace.Slice(32, 16); - blockZ_ = scratchSpace.Slice(48, 16); - blockV_ = scratchSpace.Slice(64, 16); - blockScratch_ = scratchSpace.Slice(80, 16); - - // Create the GHASH subkey by encrypting the 0-block - encryptor_.EncryptBlock(hashSubkey_, hashSubkey_); - } - - /// - /// Release resources acquired by the cipher - /// - public void Dispose() - { - encryptor_.Dispose(); - } - - /// - /// Encryptes the specified plaintext and generates an authentication - /// tag for the provided additional data. Returns the byte array - /// containg both the ciphertext and authentication tag. - /// - /// - /// Array in which to encode the encrypted ciphertext and - /// authentication tag. This array must be large enough to hold - /// `plaintext.Lengh + CiphertextOverhead` bytes. - /// - /// Unique value for this message - /// Plaintext data to encrypt - /// - /// Additional data used to authenticate the message - /// - public void Seal(ByteSpan output, ByteSpan nonce, ByteSpan plaintext, ByteSpan associatedData) - { - if (nonce.Length != NonceSize) throw new ArgumentException("Invalid nonce size", nameof(nonce)); - if (output.Length < plaintext.Length + CiphertextOverhead) - throw new ArgumentException("Invalid output size", nameof(output)); - - // Create the initial counter block - nonce.CopyTo(blockJ_); - - // Encrypt the plaintext to output - GCTR(output, blockJ_, 2, plaintext); - - // Generate and append the authentication tag - var tagOffset = plaintext.Length; - GenerateAuthenticationTag(output[tagOffset..], output[..tagOffset], associatedData); - } - - /// - /// Validates the authentication tag against the provided additional - /// data, then decrypts the cipher text returning the original - /// plaintext. - /// - /// - /// The unique value used to seal this message - /// - /// - /// Combined ciphertext and authentication tag - /// - /// - /// Additional data used to authenticate the message - /// - /// - /// On successful validation and decryprion, Open writes the original - /// plaintext to output. Must contain enough space to hold - /// `ciphertext.Length - CiphertextOverhead` bytes. - /// - /// - /// True if the data was validated and successfully decrypted. - /// Otherwise, false. - /// - public bool Open(ByteSpan output, ByteSpan nonce, ByteSpan ciphertext, ByteSpan associatedData) - { - if (nonce.Length != NonceSize) throw new ArgumentException("Invalid nonce size", nameof(nonce)); - if (ciphertext.Length < CiphertextOverhead) - throw new ArgumentException("Invalid ciphertext size", nameof(ciphertext)); - - if (output.Length < ciphertext.Length - CiphertextOverhead) - throw new ArgumentException("Invalid output size", nameof(output)); - - // Split ciphertext into actual ciphertext and authentication - // tag components. - var authenticationTag = ciphertext[^TagSize..]; - ciphertext = ciphertext[..^TagSize]; - - // Create the initial counter block - nonce.CopyTo(blockJ_); - - // Verify the tags match - GenerateAuthenticationTag(blockScratch_, ciphertext, associatedData); - if (0 == Const.ConstantCompareSpans(blockScratch_, authenticationTag)) return false; - - // Decrypt the cipher text to output - GCTR(output, blockJ_, 2, ciphertext); - return true; - } - - // Generate the authentication tag for a ciphertext+associated data - private void GenerateAuthenticationTag(ByteSpan output, ByteSpan ciphertext, ByteSpan associatedData) - { - Debug.Assert(output.Length >= 16); - - // Hash `Associated data || Ciphertext || len(AssociatedD data) || len(Ciphertext)` - // into `blockS` - { - // Clear hash output block - SetSpanToZeros(blockS_); - - // Write associated data blocks to hash - var fullBlocks = associatedData.Length / 16; - GHASH(blockS_, associatedData, fullBlocks); - if (fullBlocks * 16 < associatedData.Length) - { - SetSpanToZeros(blockScratch_); - associatedData[(fullBlocks * 16)..].CopyTo(blockScratch_); - GHASH(blockS_, blockScratch_, 1); - } - - // Write ciphertext blocks to hash - fullBlocks = ciphertext.Length / 16; - GHASH(blockS_, ciphertext, fullBlocks); - if (fullBlocks * 16 < ciphertext.Length) - { - SetSpanToZeros(blockScratch_); - ciphertext[(fullBlocks * 16)..].CopyTo(blockScratch_); - GHASH(blockS_, blockScratch_, 1); - } - - // Write bit sizes to hash - var associatedDataLengthInBits = (ulong)(8 * associatedData.Length); - var ciphertextDataLengthInBits = (ulong)(8 * ciphertext.Length); - blockScratch_.WriteBigEndian64(associatedDataLengthInBits); - blockScratch_.WriteBigEndian64(ciphertextDataLengthInBits, 8); - - GHASH(blockS_, blockScratch_, 1); - } - - // Encrypt the tag. GCM requires this because `GASH` is not - // cryptographically secure. An attacker could derive our hash - // subkey `hashSubkey_` from an unencrypted tag. - GCTR(output, blockJ_, 1, blockS_); - } - - // Run the GCTR cipher - private void GCTR(ByteSpan output, ByteSpan counterBlock, uint counter, ByteSpan data) - { - Debug.Assert(counterBlock.Length == 16); - Debug.Assert(output.Length >= data.Length); - - // Loop through plaintext blocks - var writeIndex = 0; - var numBlocks = (data.Length + 15) / 16; - for (var ii = 0; ii != numBlocks; ++ii) - { - // Encode counter into block - // CB[1] = J0 - // CB[i] = inc[32](CB[i-1]) - counterBlock.WriteBigEndian32(counter, 12); - ++counter; - - // CIPH[k](CB[i]) - encryptor_.EncryptBlock(counterBlock[..16], blockScratch_); - - // Y[i] = X[i] xor CIPH[k](CB[i]) - for (var jj = 0; jj != 16 && writeIndex < data.Length; ++jj, ++writeIndex) - output[writeIndex] = (byte)(data[writeIndex] ^ blockScratch_[jj]); - } - } - - // Run the GHASH function - private void GHASH(ByteSpan output, ByteSpan data, int numBlocks) - { - Debug.Assert(output.Length == 16); - Debug.Assert(data.Length >= numBlocks * 16); - - var readIndex = 0; - for (var ii = 0; ii != numBlocks; ++ii) - { - for (var jj = 0; jj != 16; ++jj, ++readIndex) - // Y[ii-1] xor X[ii] - output[jj] ^= data[readIndex]; - - // Y[ii] = (Y[ii-1] xor X[ii]) · H - MultiplyGF128Elements(output, hashSubkey_, blockZ_, blockV_); - } - } - - // Multiply two Galois field elements `X` and `Y` together and store - // the result in `X` such that at the end of the function: - // X = X·Y - private static void MultiplyGF128Elements(ByteSpan X, ByteSpan Y, ByteSpan scratchZ, ByteSpan scratchV) - { - Debug.Assert(X.Length == 16); - Debug.Assert(Y.Length == 16); - Debug.Assert(scratchZ.Length == 16); - Debug.Assert(scratchV.Length == 16); - - // Galois (finite) fields represented by GF(p) define a set of - // closed algebraic operations. For AES128_GCM we'll be dealing - // with the GF(2^128) field. - // - // We treat each incoming 16 byte block as a polynomial in field - // and define multiplication between two polynomials as the - // polynomial product reduced by (mod) the field polynomial: - // 1 + x + x^2 + x^7 + x^128 - // - // Field polynomials are represented by a 128 bit string. Bit n is - // the coefficient of the x^n term. We use little-endian bit - // ordering (not to be confused with byte ordering) for these - // coefficients. E.g. X[0] & 0x00000001 represents the 7th bit in - // the bit string defined by X, _not_ the 0th bit. - // - - // What follows is a modified version of the "peasant's algorithm" - // to multiply two numbers: - // - // Z contains the accumulated product - // V is a copy of Y (so we can modify it via shifting). - // - // We calculate Z = X·V as follows - // We loop through each of the 128 bits in X maintaining the - // following loop invariant: X·V + Z = the final product - // - // On each iteration `ii`: - // - // If the `ii`th bit of `X` is set, add the add the polynomial - // in `V` to `X`: `X[n] = X[n] ^ V[n]` - // - // Double V (Shift one bit right since we're storing little - // endian bit). This has the effect of multiplying V by the - // polynomial `x`. We track the unrepresentable coefficient - // of `x^128` by storing the most significant bit before the - // shift `V[15] >> 7` as `carry` - // - // Check if we've overflowed our multiplication. If overflow - // occurred, there will be a non-zero coefficient for the - // `x^128` term in the step above `carry` - // - // If we have overflowed, our polynomial is exactly of degree - // 129 (since we're only multiplying by `x`). We reduce the - // polynomial back into degree 128 by adding our field's - // irreducible polynomial: 1 + x + x^2 + x^7 + x^128. This - // reduction cancels out the x^128 term (x^128 + x^128 in GF(2) - // is zero). Therefore this modulo can be achieved by simply - // adding the irreducible polynomial to the new value of `V`. The - // irreducible polynomial is represented by the bit string: - // `11100001` followed by 120 `0`s. We can add this value to `V` - // by: `V[0] = V[0] ^ 0xE1`. - SetSpanToZeros(scratchZ); - X.CopyTo(scratchV); - - for (var ii = 0; ii != 128; ++ii) - { - var bitIndex = 7 - ii % 8; - if ((Y[ii / 8] & (1 << bitIndex)) != 0) - for (var jj = 0; jj != 16; ++jj) - scratchZ[jj] ^= scratchV[jj]; - - var carry = false; - for (var jj = 0; jj != 16; ++jj) - { - var newCarry = (scratchV[jj] & 0x01) != 0; - scratchV[jj] >>= 1; - if (carry) scratchV[jj] |= 0x80; - carry = newCarry; - } - - if (carry) scratchV[0] ^= 0xE1; - } - - scratchZ.CopyTo(X); - } - - // Set the contents of a span to all zero - private static void SetSpanToZeros(ByteSpan span) - { - for (int ii = 0, nn = span.Length; ii != nn; ++ii) span[ii] = 0; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Crypto/Const.cs b/src/NextFast.Hazel-New/Next.Hazel/Crypto/Const.cs deleted file mode 100644 index 90a2ae1..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Crypto/Const.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Diagnostics; - -namespace Next.Hazel.Crypto; - -public static class Const -{ - /// - /// Compare two bytes for equality. - /// This takes care to always use a constant amount of time to prevent - /// leaking information through side-channel attacks. - /// This is aceived by collapsing the xor bits down into a single bit. - /// Ported from: - /// https://github.com/mendsley/tiny/blob/master/include/tiny/crypto/constant.h - /// - /// - /// Returns `1` is the two bytes or equivalent. Otherwise, returns `0` - /// - public static byte ConstantCompareByte(byte a, byte b) - { - var result = (byte)~(a ^ b); - - // collapse bits down to the LSB - result &= (byte)(result >> 4); - result &= (byte)(result >> 2); - result &= (byte)(result >> 1); - - return result; - } - - /// - /// Compare two equal length spans for equality. - /// This takes care to always use a constant amount of time to prevent - /// leaking information through side-channel attacks. - /// Ported from: - /// https://github.com/mendsley/tiny/blob/master/include/tiny/crypto/constant.h - /// - /// - /// Returns `1` if the spans are equivalent. Others, returns `0`. - /// - public static byte ConstantCompareSpans(ByteSpan a, ByteSpan b) - { - Debug.Assert(a.Length == b.Length); - - byte value = 0; - for (int ii = 0, nn = a.Length; ii != nn; ++ii) value |= (byte)(a[ii] ^ b[ii]); - - return ConstantCompareByte(value, 0); - } - - /// - /// Compare a span against an all zero span - /// This takes care to always use a constant amount of time to prevent - /// leaking information through side-channel attacks. - /// Ported from: - /// https://github.com/mendsley/tiny/blob/master/include/tiny/crypto/constant.h - /// - /// - /// Returns `1` if the spans is all zeros. Others, returns `0`. - /// - public static byte ConstantCompareZeroSpan(ByteSpan a) - { - byte value = 0; - for (int ii = 0, nn = a.Length; ii != nn; ++ii) value |= (byte)(a[ii] ^ 0); - - return ConstantCompareByte(value, 0); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Crypto/CryptoProvider.cs b/src/NextFast.Hazel-New/Next.Hazel/Crypto/CryptoProvider.cs deleted file mode 100644 index c80abfc..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Crypto/CryptoProvider.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace Next.Hazel.Crypto; - -public static class CryptoProvider -{ - public delegate IAes CreateAesOverrideDelegate(ByteSpan key); - - /// - /// Override the default AES creation function - /// - public static CreateAesOverrideDelegate OverrideCreateAes = null; - - /// - /// Create a new AES cipher - /// - /// Encrtyption key - public static IAes CreateAes(ByteSpan key) - { - if (OverrideCreateAes != null) - { - var result = OverrideCreateAes(key); - if (null != result) return result; - } - - return new DefaultAes(key); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Crypto/DefaultAes.cs b/src/NextFast.Hazel-New/Next.Hazel/Crypto/DefaultAes.cs deleted file mode 100644 index c300f50..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Crypto/DefaultAes.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Security.Cryptography; - -namespace Next.Hazel.Crypto; - -/// -/// AES provider using the default System.Security.Cryptography implementation -/// -public class DefaultAes : IAes -{ - private readonly ICryptoTransform encryptor_; - - /// - /// Create a new default instance of the AES block cipher - /// - /// Encryption key - public DefaultAes(ByteSpan key) - { - // Create the AES block cipher - using (var aes = Aes.Create()) - { - aes.KeySize = key.Length * 8; - aes.BlockSize = aes.KeySize; - aes.Mode = CipherMode.ECB; - aes.Padding = PaddingMode.Zeros; - aes.Key = key.ToArray(); - - encryptor_ = aes.CreateEncryptor(); - } - } - - /// - public void Dispose() - { - encryptor_.Dispose(); - } - - /// - public int EncryptBlock(ByteSpan inputSpan, ByteSpan outputSpan) - { - if (inputSpan.Length != outputSpan.Length) - throw new ArgumentException( - $"ouputSpan length ({outputSpan.Length}) does not match inputSpan length ({inputSpan.Length})", - nameof(outputSpan)); - - return encryptor_.TransformBlock(inputSpan.GetUnderlyingArray(), inputSpan.Offset, inputSpan.Length, - outputSpan.GetUnderlyingArray(), outputSpan.Offset); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Crypto/IAes.cs b/src/NextFast.Hazel-New/Next.Hazel/Crypto/IAes.cs deleted file mode 100644 index da544a5..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Crypto/IAes.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; - -namespace Next.Hazel.Crypto; - -/// -/// AES encryption interface -/// -public interface IAes : IDisposable -{ - /// - /// Encrypts the specified region of the input byte array and copies - /// the resulting transform to the specified region of the output - /// array. - /// - /// The input for which to encrypt - /// - /// The otput to which to write the encrypted data. This span can - /// overlap with `inputSpan`. - /// - /// The number of bytes written - int EncryptBlock(ByteSpan inputSpan, ByteSpan outputSpan); -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Crypto/Sha256Stream.cs b/src/NextFast.Hazel-New/Next.Hazel/Crypto/Sha256Stream.cs deleted file mode 100644 index 693f993..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Crypto/Sha256Stream.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Security.Cryptography; - -namespace Next.Hazel.Crypto; - -/// -/// Streams data into a SHA256 digest -/// -public class Sha256Stream : IDisposable -{ - /// - /// Size of the SHA256 digest in bytes - /// - public const int DigestSize = 32; - - private SHA256 hash = SHA256.Create(); - - /// - /// Create a new instance of a SHA256 stream - /// - public Sha256Stream() - { - } - - /// - /// Release resources associated with the stream - /// - public void Dispose() - { - hash?.Dispose(); - hash = null; - - GC.SuppressFinalize(this); - } - - /// - /// Reset the stream to its initial state - /// - public void Reset() - { - hash?.Dispose(); - hash = SHA256.Create(); - } - - /// - /// Add data to the stream - /// - public void AddData(ByteSpan data) - { - while (data.Length > 0) - { - var offset = hash.TransformBlock(data.GetUnderlyingArray(), data.Offset, data.Length, null, 0); - data = data[offset..]; - } - } - - /// - /// Calculate the final hash of the stream data - /// - /// - /// Target span to which the hash will be written - /// - public void CalculateHash(ByteSpan output) - { - if (output.Length != DigestSize) - throw new ArgumentException($"Expected a span of {DigestSize} bytes. Got a span of {output.Length} bytes", - nameof(output)); - - hash.TransformFinalBlock(EmptyArray.Value, 0, 0); - new ByteSpan(hash.Hash).CopyTo(output); - } - - private struct EmptyArray - { - public static readonly byte[] Value = new byte[0]; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Crypto/SpanCryptoExtensions.cs b/src/NextFast.Hazel-New/Next.Hazel/Crypto/SpanCryptoExtensions.cs deleted file mode 100644 index d68621c..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Crypto/SpanCryptoExtensions.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Security.Cryptography; - -namespace Next.Hazel.Crypto; - -public static class SpanCryptoExtensions -{ - /// - /// Clear a span's contents to zero - /// - public static void SecureClear(this ByteSpan span) - { - if (span.Length > 0) Array.Clear(span.GetUnderlyingArray(), span.Offset, span.Length); - } - - /// - /// Fill a byte span with random data - /// - /// - /// Entropy source - public static void FillWithRandom(this ByteSpan span, RandomNumberGenerator random) - { - if (span.Offset == 0 && span.Length == span.GetUnderlyingArray().Length) - { - random.GetBytes(span.GetUnderlyingArray()); - return; - } - - var temp = new byte[span.Length]; - random.GetBytes(temp); - new ByteSpan(temp).CopyTo(span); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Crypto/X25519.cs b/src/NextFast.Hazel-New/Next.Hazel/Crypto/X25519.cs deleted file mode 100644 index 12fe184..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Crypto/X25519.cs +++ /dev/null @@ -1,810 +0,0 @@ -using System; -using System.Diagnostics; - -namespace Next.Hazel.Crypto; - -/// -/// The x25519 key agreement algorithm -/// -public static class X25519 -{ - public const int KeySize = 32; - - private static readonly byte[] BasePoint = - { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - /// - /// Performs the core x25519 function: Multiplying an EC point by a scalar value - /// - public static bool Func(ByteSpan output, ByteSpan scalar, ByteSpan point) - { - InternalFunc(output, scalar, point); - if (Const.ConstantCompareZeroSpan(output) == 1) return false; - - return true; - } - - /// - /// Multiplies the base x25519 point by the provided scalar value - /// - public static void Func(ByteSpan output, ByteSpan scalar) - { - InternalFunc(output, scalar, BasePoint); - } - - // The FieldElement code below is ported from the original - // public domain reference implemtation of X25519 - // by D. J. Bernstien - // - // See: https://cr.yp.to/ecdh.html - - private static void InternalFunc(ByteSpan output, ByteSpan scalar, ByteSpan point) - { - if (output.Length != KeySize) throw new ArgumentException("Invalid output size", nameof(output)); - - if (scalar.Length != KeySize) throw new ArgumentException("Invalid scalar size", nameof(scalar)); - - if (point.Length != KeySize) throw new ArgumentException("Invalid point size", nameof(point)); - - // copy the scalar so we can properly mask it - ByteSpan maskedScalar = new byte[32]; - scalar.CopyTo(maskedScalar); - maskedScalar[0] &= 248; - maskedScalar[31] &= 127; - maskedScalar[31] |= 64; - - var x1 = FieldElement.FromBytes(point); - var x2 = FieldElement.One(); - var x3 = x1; - var z2 = FieldElement.Zero(); - var z3 = FieldElement.One(); - - var tmp0 = new FieldElement(); - var tmp1 = new FieldElement(); - - var swap = 0; - for (var pos = 254; pos >= 0; --pos) - { - var b = maskedScalar[pos / 8] >> (pos % 8); - b &= 1; - swap ^= b; - - FieldElement.ConditionalSwap(ref x2, ref x3, swap); - FieldElement.ConditionalSwap(ref z2, ref z3, swap); - swap = b; - - FieldElement.Sub(ref tmp0, ref x3, ref z3); - FieldElement.Sub(ref tmp1, ref x2, ref z2); - FieldElement.Add(ref x2, ref x2, ref z2); - FieldElement.Add(ref z2, ref x3, ref z3); - FieldElement.Multiply(ref z3, ref tmp0, ref x2); - FieldElement.Multiply(ref z2, ref z2, ref tmp1); - FieldElement.Square(ref tmp0, ref tmp1); - FieldElement.Square(ref tmp1, ref x2); - FieldElement.Add(ref x3, ref z3, ref z2); - FieldElement.Sub(ref z2, ref z3, ref z2); - FieldElement.Multiply(ref x2, ref tmp1, ref tmp0); - FieldElement.Sub(ref tmp1, ref tmp1, ref tmp0); - FieldElement.Square(ref z2, ref z2); - FieldElement.Multiply121666(ref z3, ref tmp1); - FieldElement.Square(ref x3, ref x3); - FieldElement.Add(ref tmp0, ref tmp0, ref z3); - FieldElement.Multiply(ref z3, ref x1, ref z2); - FieldElement.Multiply(ref z2, ref tmp1, ref tmp0); - } - - FieldElement.ConditionalSwap(ref x2, ref x3, swap); - FieldElement.ConditionalSwap(ref z2, ref z3, swap); - - FieldElement.Invert(ref z2, ref z2); - FieldElement.Multiply(ref x2, ref x2, ref z2); - x2.CopyTo(output); - } - - /// - /// Element in the GF(2^255 - 19) field - /// - public partial struct FieldElement - { - public int x0, x1, x2, x3, x4; - public int x5, x6, x7, x8, x9; - } - - - /// - /// Mathematical operators over GF(2^255 - 19) - /// - partial struct FieldElement - { - /// - /// Convert a byte array to a field element - /// - public static FieldElement FromBytes(ByteSpan bytes) - { - Debug.Assert(bytes.Length >= KeySize); - - var tmp0 = (long)bytes.ReadLittleEndian32(); - var tmp1 = (long)bytes.ReadLittleEndian24(4) << 6; - var tmp2 = (long)bytes.ReadLittleEndian24(7) << 5; - var tmp3 = (long)bytes.ReadLittleEndian24(10) << 3; - var tmp4 = (long)bytes.ReadLittleEndian24(13) << 2; - var tmp5 = (long)bytes.ReadLittleEndian32(16); - var tmp6 = (long)bytes.ReadLittleEndian24(20) << 7; - var tmp7 = (long)bytes.ReadLittleEndian24(23) << 5; - var tmp8 = (long)bytes.ReadLittleEndian24(26) << 4; - var tmp9 = (long)(bytes.ReadLittleEndian24(29) & 0x007FFFFF) << 2; - - var carry9 = (tmp9 + (1L << 24)) >> 25; - tmp0 += carry9 * 19; - tmp9 -= carry9 << 25; - var carry1 = (tmp1 + (1L << 24)) >> 25; - tmp2 += carry1; - tmp1 -= carry1 << 25; - var carry3 = (tmp3 + (1L << 24)) >> 25; - tmp4 += carry3; - tmp3 -= carry3 << 25; - var carry5 = (tmp5 + (1L << 24)) >> 25; - tmp6 += carry5; - tmp5 -= carry5 << 25; - var carry7 = (tmp7 + (1L << 24)) >> 25; - tmp8 += carry7; - tmp7 -= carry7 << 25; - - var carry0 = (tmp0 + (1L << 25)) >> 26; - tmp1 += carry0; - tmp0 -= carry0 << 26; - var carry2 = (tmp2 + (1L << 25)) >> 26; - tmp3 += carry2; - tmp2 -= carry2 << 26; - var carry4 = (tmp4 + (1L << 25)) >> 26; - tmp5 += carry4; - tmp4 -= carry4 << 26; - var carry6 = (tmp6 + (1L << 25)) >> 26; - tmp7 += carry6; - tmp6 -= carry6 << 26; - var carry8 = (tmp8 + (1L << 25)) >> 26; - tmp9 += carry8; - tmp8 -= carry8 << 26; - - return new FieldElement - { - x0 = (int)tmp0, - x1 = (int)tmp1, - x2 = (int)tmp2, - x3 = (int)tmp3, - x4 = (int)tmp4, - x5 = (int)tmp5, - x6 = (int)tmp6, - x7 = (int)tmp7, - x8 = (int)tmp8, - x9 = (int)tmp9 - }; - } - - /// - /// Convert the field element to a byte array - /// - public void CopyTo(ByteSpan output) - { - Debug.Assert(output.Length >= 32); - - var q = (19 * x9 + (1L << 24)) >> 25; - q = (x0 + q) >> 26; - q = (x1 + q) >> 25; - q = (x2 + q) >> 26; - q = (x3 + q) >> 25; - q = (x4 + q) >> 26; - q = (x5 + q) >> 25; - q = (x6 + q) >> 26; - q = (x7 + q) >> 25; - q = (x8 + q) >> 26; - q = (x9 + q) >> 25; - - x0 = (int)(x0 + 19L * q); - - var carry0 = x0 >> 26; - x1 = x1 + carry0; - x0 = x0 - (carry0 << 26); - var carry1 = x1 >> 25; - x2 = x2 + carry1; - x1 = x1 - (carry1 << 25); - var carry2 = x2 >> 26; - x3 = x3 + carry2; - x2 = x2 - (carry2 << 26); - var carry3 = x3 >> 25; - x4 = x4 + carry3; - x3 = x3 - (carry3 << 25); - var carry4 = x4 >> 26; - x5 = x5 + carry4; - x4 = x4 - (carry4 << 26); - var carry5 = x5 >> 25; - x6 = x6 + carry5; - x5 = x5 - (carry5 << 25); - var carry6 = x6 >> 26; - x7 = x7 + carry6; - x6 = x6 - (carry6 << 26); - var carry7 = x7 >> 25; - x8 = x8 + carry7; - x7 = x7 - (carry7 << 25); - var carry8 = x8 >> 26; - x9 = x9 + carry8; - x8 = x8 - (carry8 << 26); - var carry9 = x9 >> 25; - x9 = x9 - (carry9 << 25); - - output[0] = (byte)(x0 >> 0); - output[1] = (byte)(x0 >> 8); - output[2] = (byte)(x0 >> 16); - output[3] = (byte)((x0 >> 24) | (x1 << 2)); - output[4] = (byte)(x1 >> 6); - output[5] = (byte)(x1 >> 14); - output[6] = (byte)((x1 >> 22) | (x2 << 3)); - output[7] = (byte)(x2 >> 5); - output[8] = (byte)(x2 >> 13); - output[9] = (byte)((x2 >> 21) | (x3 << 5)); - output[10] = (byte)(x3 >> 3); - output[11] = (byte)(x3 >> 11); - output[12] = (byte)((x3 >> 19) | (x4 << 6)); - output[13] = (byte)(x4 >> 2); - output[14] = (byte)(x4 >> 10); - output[15] = (byte)(x4 >> 18); - output[16] = (byte)(x5 >> 0); - output[17] = (byte)(x5 >> 8); - output[18] = (byte)(x5 >> 16); - output[19] = (byte)((x5 >> 24) | (x6 << 1)); - output[20] = (byte)(x6 >> 7); - output[21] = (byte)(x6 >> 15); - output[22] = (byte)((x6 >> 23) | (x7 << 3)); - output[23] = (byte)(x7 >> 5); - output[24] = (byte)(x7 >> 13); - output[25] = (byte)((x7 >> 21) | (x8 << 4)); - output[26] = (byte)(x8 >> 4); - output[27] = (byte)(x8 >> 12); - output[28] = (byte)((x8 >> 20) | (x9 << 6)); - output[29] = (byte)(x9 >> 2); - output[30] = (byte)(x9 >> 10); - output[31] = (byte)(x9 >> 18); - } - - /// - /// Set the field element to `0` - /// - public static FieldElement Zero() - { - return new FieldElement(); - } - - /// - /// Set the field element to `1` - /// - public static FieldElement One() - { - var result = Zero(); - result.x0 = 1; - return result; - } - - /// - /// Add two field elements - /// - public static void Add(ref FieldElement output, ref FieldElement a, ref FieldElement b) - { - output.x0 = a.x0 + b.x0; - output.x1 = a.x1 + b.x1; - output.x2 = a.x2 + b.x2; - output.x3 = a.x3 + b.x3; - output.x4 = a.x4 + b.x4; - output.x5 = a.x5 + b.x5; - output.x6 = a.x6 + b.x6; - output.x7 = a.x7 + b.x7; - output.x8 = a.x8 + b.x8; - output.x9 = a.x9 + b.x9; - } - - /// - /// Subtract two field elements - /// - public static void Sub(ref FieldElement output, ref FieldElement a, ref FieldElement b) - { - output.x0 = a.x0 - b.x0; - output.x1 = a.x1 - b.x1; - output.x2 = a.x2 - b.x2; - output.x3 = a.x3 - b.x3; - output.x4 = a.x4 - b.x4; - output.x5 = a.x5 - b.x5; - output.x6 = a.x6 - b.x6; - output.x7 = a.x7 - b.x7; - output.x8 = a.x8 - b.x8; - output.x9 = a.x9 - b.x9; - } - - /// - /// Multiply two field elements - /// - public static void Multiply(ref FieldElement output, ref FieldElement a, ref FieldElement b) - { - var b1_19 = 19 * b.x1; - var b2_19 = 19 * b.x2; - var b3_19 = 19 * b.x3; - var b4_19 = 19 * b.x4; - var b5_19 = 19 * b.x5; - var b6_19 = 19 * b.x6; - var b7_19 = 19 * b.x7; - var b8_19 = 19 * b.x8; - var b9_19 = 19 * b.x9; - - var a1_2 = 2 * a.x1; - var a3_2 = 2 * a.x3; - var a5_2 = 2 * a.x5; - var a7_2 = 2 * a.x7; - var a9_2 = 2 * a.x9; - - var a0b0 = a.x0 * (long)b.x0; - var a0b1 = a.x0 * (long)b.x1; - var a0b2 = a.x0 * (long)b.x2; - var a0b3 = a.x0 * (long)b.x3; - var a0b4 = a.x0 * (long)b.x4; - var a0b5 = a.x0 * (long)b.x5; - var a0b6 = a.x0 * (long)b.x6; - var a0b7 = a.x0 * (long)b.x7; - var a0b8 = a.x0 * (long)b.x8; - var a0b9 = a.x0 * (long)b.x9; - var a1b0 = a.x1 * (long)b.x0; - var a1b1_2 = a1_2 * (long)b.x1; - var a1b2 = a.x1 * (long)b.x2; - var a1b3_2 = a1_2 * (long)b.x3; - var a1b4 = a.x1 * (long)b.x4; - var a1b5_2 = a1_2 * (long)b.x5; - var a1b6 = a.x1 * (long)b.x6; - var a1b7_2 = a1_2 * (long)b.x7; - var a1b8 = a.x1 * (long)b.x8; - var a1b9_38 = a1_2 * (long)b9_19; - var a2b0 = a.x2 * (long)b.x0; - var a2b1 = a.x2 * (long)b.x1; - var a2b2 = a.x2 * (long)b.x2; - var a2b3 = a.x2 * (long)b.x3; - var a2b4 = a.x2 * (long)b.x4; - var a2b5 = a.x2 * (long)b.x5; - var a2b6 = a.x2 * (long)b.x6; - var a2b7 = a.x2 * (long)b.x7; - var a2b8_19 = a.x2 * (long)b8_19; - var a2b9_19 = a.x2 * (long)b9_19; - var a3b0 = a.x3 * (long)b.x0; - var a3b1_2 = a3_2 * (long)b.x1; - var a3b2 = a.x3 * (long)b.x2; - var a3b3_2 = a3_2 * (long)b.x3; - var a3b4 = a.x3 * (long)b.x4; - var a3b5_2 = a3_2 * (long)b.x5; - var a3b6 = a.x3 * (long)b.x6; - var a3b7_38 = a3_2 * (long)b7_19; - var a3b8_19 = a.x3 * (long)b8_19; - var a3b9_38 = a3_2 * (long)b9_19; - var a4b0 = a.x4 * (long)b.x0; - var a4b1 = a.x4 * (long)b.x1; - var a4b2 = a.x4 * (long)b.x2; - var a4b3 = a.x4 * (long)b.x3; - var a4b4 = a.x4 * (long)b.x4; - var a4b5 = a.x4 * (long)b.x5; - var a4b6_19 = a.x4 * (long)b6_19; - var a4b7_19 = a.x4 * (long)b7_19; - var a4b8_19 = a.x4 * (long)b8_19; - var a4b9_19 = a.x4 * (long)b9_19; - var a5b0 = a.x5 * (long)b.x0; - var a5b1_2 = a5_2 * (long)b.x1; - var a5b2 = a.x5 * (long)b.x2; - var a5b3_2 = a5_2 * (long)b.x3; - var a5b4 = a.x5 * (long)b.x4; - var a5b5_38 = a5_2 * (long)b5_19; - var a5b6_19 = a.x5 * (long)b6_19; - var a5b7_38 = a5_2 * (long)b7_19; - var a5b8_19 = a.x5 * (long)b8_19; - var a5b9_38 = a5_2 * (long)b9_19; - var a6b0 = a.x6 * (long)b.x0; - var a6b1 = a.x6 * (long)b.x1; - var a6b2 = a.x6 * (long)b.x2; - var a6b3 = a.x6 * (long)b.x3; - var a6b4_19 = a.x6 * (long)b4_19; - var a6b5_19 = a.x6 * (long)b5_19; - var a6b6_19 = a.x6 * (long)b6_19; - var a6b7_19 = a.x6 * (long)b7_19; - var a6b8_19 = a.x6 * (long)b8_19; - var a6b9_19 = a.x6 * (long)b9_19; - var a7b0 = a.x7 * (long)b.x0; - var a7b1_2 = a7_2 * (long)b.x1; - var a7b2 = a.x7 * (long)b.x2; - var a7b3_38 = a7_2 * (long)b3_19; - var a7b4_19 = a.x7 * (long)b4_19; - var a7b5_38 = a7_2 * (long)b5_19; - var a7b6_19 = a.x7 * (long)b6_19; - var a7b7_38 = a7_2 * (long)b7_19; - var a7b8_19 = a.x7 * (long)b8_19; - var a7b9_38 = a7_2 * (long)b9_19; - var a8b0 = a.x8 * (long)b.x0; - var a8b1 = a.x8 * (long)b.x1; - var a8b2_19 = a.x8 * (long)b2_19; - var a8b3_19 = a.x8 * (long)b3_19; - var a8b4_19 = a.x8 * (long)b4_19; - var a8b5_19 = a.x8 * (long)b5_19; - var a8b6_19 = a.x8 * (long)b6_19; - var a8b7_19 = a.x8 * (long)b7_19; - var a8b8_19 = a.x8 * (long)b8_19; - var a8b9_19 = a.x8 * (long)b9_19; - var a9b0 = a.x9 * (long)b.x0; - var a9b1_38 = a9_2 * (long)b1_19; - var a9b2_19 = a.x9 * (long)b2_19; - var a9b3_38 = a9_2 * (long)b3_19; - var a9b4_19 = a.x9 * (long)b4_19; - var a9b5_38 = a9_2 * (long)b5_19; - var a9b6_19 = a.x9 * (long)b6_19; - var a9b7_38 = a9_2 * (long)b7_19; - var a9b8_19 = a.x9 * (long)b8_19; - var a9b9_38 = a9_2 * (long)b9_19; - - var h0 = a0b0 + a1b9_38 + a2b8_19 + a3b7_38 + a4b6_19 + a5b5_38 + a6b4_19 + a7b3_38 + a8b2_19 + a9b1_38; - var h1 = a0b1 + a1b0 + a2b9_19 + a3b8_19 + a4b7_19 + a5b6_19 + a6b5_19 + a7b4_19 + a8b3_19 + a9b2_19; - var h2 = a0b2 + a1b1_2 + a2b0 + a3b9_38 + a4b8_19 + a5b7_38 + a6b6_19 + a7b5_38 + a8b4_19 + a9b3_38; - var h3 = a0b3 + a1b2 + a2b1 + a3b0 + a4b9_19 + a5b8_19 + a6b7_19 + a7b6_19 + a8b5_19 + a9b4_19; - var h4 = a0b4 + a1b3_2 + a2b2 + a3b1_2 + a4b0 + a5b9_38 + a6b8_19 + a7b7_38 + a8b6_19 + a9b5_38; - var h5 = a0b5 + a1b4 + a2b3 + a3b2 + a4b1 + a5b0 + a6b9_19 + a7b8_19 + a8b7_19 + a9b6_19; - var h6 = a0b6 + a1b5_2 + a2b4 + a3b3_2 + a4b2 + a5b1_2 + a6b0 + a7b9_38 + a8b8_19 + a9b7_38; - var h7 = a0b7 + a1b6 + a2b5 + a3b4 + a4b3 + a5b2 + a6b1 + a7b0 + a8b9_19 + a9b8_19; - var h8 = a0b8 + a1b7_2 + a2b6 + a3b5_2 + a4b4 + a5b3_2 + a6b2 + a7b1_2 + a8b0 + a9b9_38; - var h9 = a0b9 + a1b8 + a2b7 + a3b6 + a4b5 + a5b4 + a6b3 + a7b2 + a8b1 + a9b0; - - var carry0 = (h0 + (1L << 25)) >> 26; - h1 += carry0; - h0 -= carry0 << 26; - var carry4 = (h4 + (1L << 25)) >> 26; - h5 += carry4; - h4 -= carry4 << 26; - - var carry1 = (h1 + (1L << 24)) >> 25; - h2 += carry1; - h1 -= carry1 << 25; - var carry5 = (h5 + (1L << 24)) >> 25; - h6 += carry5; - h5 -= carry5 << 25; - - var carry2 = (h2 + (1L << 25)) >> 26; - h3 += carry2; - h2 -= carry2 << 26; - var carry6 = (h6 + (1L << 25)) >> 26; - h7 += carry6; - h6 -= carry6 << 26; - - var carry3 = (h3 + (1L << 24)) >> 25; - h4 += carry3; - h3 -= carry3 << 25; - var carry7 = (h7 + (1L << 24)) >> 25; - h8 += carry7; - h7 -= carry7 << 25; - - carry4 = (h4 + (1L << 25)) >> 26; - h5 += carry4; - h4 -= carry4 << 26; - var carry8 = (h8 + (1L << 25)) >> 26; - h9 += carry8; - h8 -= carry8 << 26; - - var carry9 = (h9 + (1L << 24)) >> 25; - h0 += carry9 * 19; - h9 -= carry9 << 25; - - carry0 = (h0 + (1L << 25)) >> 26; - h1 += carry0; - h0 -= carry0 << 26; - - output.x0 = (int)h0; - output.x1 = (int)h1; - output.x2 = (int)h2; - output.x3 = (int)h3; - output.x4 = (int)h4; - output.x5 = (int)h5; - output.x6 = (int)h6; - output.x7 = (int)h7; - output.x8 = (int)h8; - output.x9 = (int)h9; - } - - /// - /// Square a field element - /// - public static void Square(ref FieldElement output, ref FieldElement a) - { - var a0_2 = a.x0 * 2; - var a1_2 = a.x1 * 2; - var a2_2 = a.x2 * 2; - var a3_2 = a.x3 * 2; - var a4_2 = a.x4 * 2; - var a5_2 = a.x5 * 2; - var a6_2 = a.x6 * 2; - var a7_2 = a.x7 * 2; - - var a5_38 = a.x5 * 38; - var a6_19 = a.x6 * 19; - var a7_38 = a.x7 * 38; - var a8_19 = a.x8 * 19; - var a9_38 = a.x9 * 38; - - var a0a0 = a.x0 * (long)a.x0; - var a0a1_2 = a0_2 * (long)a.x1; - var a0a2_2 = a0_2 * (long)a.x2; - var a0a3_2 = a0_2 * (long)a.x3; - var a0a4_2 = a0_2 * (long)a.x4; - var a0a5_2 = a0_2 * (long)a.x5; - var a0a6_2 = a0_2 * (long)a.x6; - var a0a7_2 = a0_2 * (long)a.x7; - var a0a8_2 = a0_2 * (long)a.x8; - var a0a9_2 = a0_2 * (long)a.x9; - var a1a1_2 = a1_2 * (long)a.x1; - var a1a2_2 = a1_2 * (long)a.x2; - var a1a3_4 = a1_2 * (long)a3_2; - var a1a4_2 = a1_2 * (long)a.x4; - var a1a5_4 = a1_2 * (long)a5_2; - var a1a6_2 = a1_2 * (long)a.x6; - var a1a7_4 = a1_2 * (long)a7_2; - var a1a8_2 = a1_2 * (long)a.x8; - var a1a9_76 = a1_2 * (long)a9_38; - var a2a2 = a.x2 * (long)a.x2; - var a2a3_2 = a2_2 * (long)a.x3; - var a2a4_2 = a2_2 * (long)a.x4; - var a2a5_2 = a2_2 * (long)a.x5; - var a2a6_2 = a2_2 * (long)a.x6; - var a2a7_2 = a2_2 * (long)a.x7; - var a2a8_38 = a2_2 * (long)a8_19; - var a2a9_38 = a.x2 * (long)a9_38; - var a3a3_2 = a3_2 * (long)a.x3; - var a3a4_2 = a3_2 * (long)a.x4; - var a3a5_4 = a3_2 * (long)a5_2; - var a3a6_2 = a3_2 * (long)a.x6; - var a3a7_76 = a3_2 * (long)a7_38; - var a3a8_38 = a3_2 * (long)a8_19; - var a3a9_76 = a3_2 * (long)a9_38; - var a4a4 = a.x4 * (long)a.x4; - var a4a5_2 = a4_2 * (long)a.x5; - var a4a6_38 = a4_2 * (long)a6_19; - var a4a7_38 = a.x4 * (long)a7_38; - var a4a8_38 = a4_2 * (long)a8_19; - var a4a9_38 = a.x4 * (long)a9_38; - var a5a5_38 = a.x5 * (long)a5_38; - var a5a6_38 = a5_2 * (long)a6_19; - var a5a7_76 = a5_2 * (long)a7_38; - var a5a8_38 = a5_2 * (long)a8_19; - var a5a9_76 = a5_2 * (long)a9_38; - var a6a6_19 = a.x6 * (long)a6_19; - var a6a7_38 = a.x6 * (long)a7_38; - var a6a8_38 = a6_2 * (long)a8_19; - var a6a9_38 = a.x6 * (long)a9_38; - var a7a7_38 = a.x7 * (long)a7_38; - var a7a8_38 = a7_2 * (long)a8_19; - var a7a9_76 = a7_2 * (long)a9_38; - var a8a8_19 = a.x8 * (long)a8_19; - var a8a9_38 = a.x8 * (long)a9_38; - var a9a9_38 = a.x9 * (long)a9_38; - - var h0 = a0a0 + a1a9_76 + a2a8_38 + a3a7_76 + a4a6_38 + a5a5_38; - var h1 = a0a1_2 + a2a9_38 + a3a8_38 + a4a7_38 + a5a6_38; - var h2 = a0a2_2 + a1a1_2 + a3a9_76 + a4a8_38 + a5a7_76 + a6a6_19; - var h3 = a0a3_2 + a1a2_2 + a4a9_38 + a5a8_38 + a6a7_38; - var h4 = a0a4_2 + a1a3_4 + a2a2 + a5a9_76 + a6a8_38 + a7a7_38; - var h5 = a0a5_2 + a1a4_2 + a2a3_2 + a6a9_38 + a7a8_38; - var h6 = a0a6_2 + a1a5_4 + a2a4_2 + a3a3_2 + a7a9_76 + a8a8_19; - var h7 = a0a7_2 + a1a6_2 + a2a5_2 + a3a4_2 + a8a9_38; - var h8 = a0a8_2 + a1a7_4 + a2a6_2 + a3a5_4 + a4a4 + a9a9_38; - var h9 = a0a9_2 + a1a8_2 + a2a7_2 + a3a6_2 + a4a5_2; - - var carry0 = (h0 + (1L << 25)) >> 26; - h1 += carry0; - h0 -= carry0 << 26; - var carry4 = (h4 + (1L << 25)) >> 26; - h5 += carry4; - h4 -= carry4 << 26; - - var carry1 = (h1 + (1L << 24)) >> 25; - h2 += carry1; - h1 -= carry1 << 25; - var carry5 = (h5 + (1L << 24)) >> 25; - h6 += carry5; - h5 -= carry5 << 25; - - var carry2 = (h2 + (1L << 25)) >> 26; - h3 += carry2; - h2 -= carry2 << 26; - var carry6 = (h6 + (1L << 25)) >> 26; - h7 += carry6; - h6 -= carry6 << 26; - - var carry3 = (h3 + (1L << 24)) >> 25; - h4 += carry3; - h3 -= carry3 << 25; - var carry7 = (h7 + (1L << 24)) >> 25; - h8 += carry7; - h7 -= carry7 << 25; - - carry4 = (h4 + (1L << 25)) >> 26; - h5 += carry4; - h4 -= carry4 << 26; - var carry8 = (h8 + (1L << 25)) >> 26; - h9 += carry8; - h8 -= carry8 << 26; - - var carry9 = (h9 + (1L << 24)) >> 25; - h0 += carry9 * 19; - h9 -= carry9 << 25; - - carry0 = (h0 + (1L << 25)) >> 26; - h1 += carry0; - h0 -= carry0 << 26; - - output.x0 = (int)h0; - output.x1 = (int)h1; - output.x2 = (int)h2; - output.x3 = (int)h3; - output.x4 = (int)h4; - output.x5 = (int)h5; - output.x6 = (int)h6; - output.x7 = (int)h7; - output.x8 = (int)h8; - output.x9 = (int)h9; - } - - /// - /// Multiplay a field element by 121666 - /// - public static void Multiply121666(ref FieldElement output, ref FieldElement a) - { - var h0 = a.x0 * 121666L; - var h1 = a.x1 * 121666L; - var h2 = a.x2 * 121666L; - var h3 = a.x3 * 121666L; - var h4 = a.x4 * 121666L; - var h5 = a.x5 * 121666L; - var h6 = a.x6 * 121666L; - var h7 = a.x7 * 121666L; - var h8 = a.x8 * 121666L; - var h9 = a.x9 * 121666L; - - var carry9 = (h9 + (1L << 24)) >> 25; - h0 += carry9 * 19; - h9 -= carry9 << 25; - var carry1 = (h1 + (1L << 24)) >> 25; - h2 += carry1; - h1 -= carry1 << 25; - var carry3 = (h3 + (1L << 24)) >> 25; - h4 += carry3; - h3 -= carry3 << 25; - var carry5 = (h5 + (1L << 24)) >> 25; - h6 += carry5; - h5 -= carry5 << 25; - var carry7 = (h7 + (1L << 24)) >> 25; - h8 += carry7; - h7 -= carry7 << 25; - - var carry0 = (h0 + (1L << 25)) >> 26; - h1 += carry0; - h0 -= carry0 << 26; - var carry2 = (h2 + (1L << 25)) >> 26; - h3 += carry2; - h2 -= carry2 << 26; - var carry4 = (h4 + (1L << 25)) >> 26; - h5 += carry4; - h4 -= carry4 << 26; - var carry6 = (h6 + (1L << 25)) >> 26; - h7 += carry6; - h6 -= carry6 << 26; - var carry8 = (h8 + (1L << 25)) >> 26; - h9 += carry8; - h8 -= carry8 << 26; - - output.x0 = (int)h0; - output.x1 = (int)h1; - output.x2 = (int)h2; - output.x3 = (int)h3; - output.x4 = (int)h4; - output.x5 = (int)h5; - output.x6 = (int)h6; - output.x7 = (int)h7; - output.x8 = (int)h8; - output.x9 = (int)h9; - } - - /// - /// Invert a field element - /// - public static void Invert(ref FieldElement output, ref FieldElement a) - { - var t0 = new FieldElement(); - Square(ref t0, ref a); - - var t1 = new FieldElement(); - Square(ref t1, ref t0); - Square(ref t1, ref t1); - - var t2 = new FieldElement(); - Multiply(ref t1, ref a, ref t1); - Multiply(ref t0, ref t0, ref t1); - Square(ref t2, ref t0); - //Square(ref t2, ref t2); - - Multiply(ref t1, ref t1, ref t2); - Square(ref t2, ref t1); - for (var ii = 1; ii < 5; ++ii) Square(ref t2, ref t2); - - Multiply(ref t1, ref t2, ref t1); - Square(ref t2, ref t1); - for (var ii = 1; ii < 10; ++ii) Square(ref t2, ref t2); - - var t3 = new FieldElement(); - Multiply(ref t2, ref t2, ref t1); - Square(ref t3, ref t2); - for (var ii = 1; ii < 20; ++ii) Square(ref t3, ref t3); - - Multiply(ref t2, ref t3, ref t2); - Square(ref t2, ref t2); - for (var ii = 1; ii < 10; ++ii) Square(ref t2, ref t2); - - Multiply(ref t1, ref t2, ref t1); - Square(ref t2, ref t1); - for (var ii = 1; ii < 50; ++ii) Square(ref t2, ref t2); - - Multiply(ref t2, ref t2, ref t1); - Square(ref t3, ref t2); - for (var ii = 1; ii < 100; ++ii) Square(ref t3, ref t3); - - Multiply(ref t2, ref t3, ref t2); - Square(ref t2, ref t2); - for (var ii = 1; ii < 50; ++ii) Square(ref t2, ref t2); - - Multiply(ref t1, ref t2, ref t1); - Square(ref t1, ref t1); - for (var ii = 1; ii < 5; ++ii) Square(ref t1, ref t1); - - Multiply(ref output, ref t1, ref t0); - } - - /// - /// Swaps `a` and `b` if `swap` is 1 - /// - public static void ConditionalSwap(ref FieldElement a, ref FieldElement b, int swap) - { - Debug.Assert(swap == 0 || swap == 1); - swap = -swap; - - var temp = new FieldElement - { - x0 = swap & (a.x0 ^ b.x0), - x1 = swap & (a.x1 ^ b.x1), - x2 = swap & (a.x2 ^ b.x2), - x3 = swap & (a.x3 ^ b.x3), - x4 = swap & (a.x4 ^ b.x4), - x5 = swap & (a.x5 ^ b.x5), - x6 = swap & (a.x6 ^ b.x6), - x7 = swap & (a.x7 ^ b.x7), - x8 = swap & (a.x8 ^ b.x8), - x9 = swap & (a.x9 ^ b.x9) - }; - - a.x0 ^= temp.x0; - a.x1 ^= temp.x1; - a.x2 ^= temp.x2; - a.x3 ^= temp.x3; - a.x4 ^= temp.x4; - a.x5 ^= temp.x5; - a.x6 ^= temp.x6; - a.x7 ^= temp.x7; - a.x8 ^= temp.x8; - a.x9 ^= temp.x9; - - b.x0 ^= temp.x0; - b.x1 ^= temp.x1; - b.x2 ^= temp.x2; - b.x3 ^= temp.x3; - b.x4 ^= temp.x4; - b.x5 ^= temp.x5; - b.x6 ^= temp.x6; - b.x7 ^= temp.x7; - b.x8 ^= temp.x8; - b.x9 ^= temp.x9; - } - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/DataReceivedEventArgs.cs b/src/NextFast.Hazel-New/Next.Hazel/DataReceivedEventArgs.cs deleted file mode 100644 index 4e80f08..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/DataReceivedEventArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Next.Hazel.Abstractions; - -namespace Next.Hazel; - -public struct DataReceivedEventArgs(Connection sender, IMessageReader msg, MessageType type) -{ - public readonly Connection Sender = sender; - - /// - /// The bytes received from the client. - /// - public readonly IMessageReader Message = msg; - - - public readonly MessageType Type = type; -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/DisconnectedEventArgs.cs b/src/NextFast.Hazel-New/Next.Hazel/DisconnectedEventArgs.cs deleted file mode 100644 index cceb0e0..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/DisconnectedEventArgs.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; - -namespace Next.Hazel; - -public class DisconnectedEventArgs : EventArgs -{ - /// - /// Optional data sent with a disconnect message. May be null. - /// You must not recycle this. If you need the message outside of a callback, you should copy it. - /// - public readonly MessageReader Message; - - /// - /// Optional disconnect reason. May be null. - /// - public readonly string Reason; - - public DisconnectedEventArgs(string reason, MessageReader message) - { - Reason = reason; - Message = message; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/AesGcmRecordProtection.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/AesGcmRecordProtection.cs deleted file mode 100644 index c6c995c..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/AesGcmRecordProtection.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System.Diagnostics; -using Next.Hazel.Crypto; - -namespace Next.Hazel.Dtls; - -/// -/// *_AES_128_GCM_* cipher suite -/// -public class Aes128GcmRecordProtection : IRecordProtection -{ - private const int ImplicitNonceSize = 4; - private const int ExplicitNonceSize = 8; - private readonly Aes128Gcm clientWriteCipher; - private readonly ByteSpan clientWriteIV; - - private readonly Aes128Gcm serverWriteCipher; - - private readonly ByteSpan serverWriteIV; - - /// - /// Create a new instance of the AES128_GCM record protection - /// - /// Shared secret - /// Server random data - /// Client random data - public Aes128GcmRecordProtection(ByteSpan masterSecret, ByteSpan serverRandom, ByteSpan clientRandom) - { - ByteSpan combinedRandom = new byte[serverRandom.Length + clientRandom.Length]; - serverRandom.CopyTo(combinedRandom); - clientRandom.CopyTo(combinedRandom[serverRandom.Length..]); - - // Expand master_secret to encryption keys - const int ExpandedSize = 0 - + 0 // mac_key_length - + 0 // mac_key_length - + Aes128Gcm.KeySize // enc_key_length - + Aes128Gcm.KeySize // enc_key_length - + ImplicitNonceSize // fixed_iv_length - + ImplicitNonceSize // fixed_iv_length - ; - - ByteSpan expandedKey = new byte[ExpandedSize]; - PrfSha256.ExpandSecret(expandedKey, masterSecret, PrfLabel.KEY_EXPANSION, combinedRandom); - - var clientWriteKey = expandedKey[..Aes128Gcm.KeySize]; - var serverWriteKey = expandedKey.Slice(Aes128Gcm.KeySize, Aes128Gcm.KeySize); - clientWriteIV = expandedKey.Slice(2 * Aes128Gcm.KeySize, ImplicitNonceSize); - serverWriteIV = expandedKey.Slice(2 * Aes128Gcm.KeySize + ImplicitNonceSize, ImplicitNonceSize); - - serverWriteCipher = new Aes128Gcm(serverWriteKey); - clientWriteCipher = new Aes128Gcm(clientWriteKey); - } - - /// - public void Dispose() - { - serverWriteCipher.Dispose(); - clientWriteCipher.Dispose(); - } - - /// - public int GetEncryptedSize(int dataSize) - { - return GetEncryptedSizeImpl(dataSize); - } - - /// - public int GetDecryptedSize(int dataSize) - { - return GetDecryptedSizeImpl(dataSize); - } - - /// - public void EncryptServerPlaintext(ByteSpan output, ByteSpan input, ref Record record) - { - EncryptPlaintext(output, input, ref record, serverWriteCipher, serverWriteIV); - } - - /// - public void EncryptClientPlaintext(ByteSpan output, ByteSpan input, ref Record record) - { - EncryptPlaintext(output, input, ref record, clientWriteCipher, clientWriteIV); - } - - /// - public bool DecryptCiphertextFromServer(ByteSpan output, ByteSpan input, ref Record record) - { - return DecryptCiphertext(output, input, ref record, serverWriteCipher, serverWriteIV); - } - - /// - public bool DecryptCiphertextFromClient(ByteSpan output, ByteSpan input, ref Record record) - { - return DecryptCiphertext(output, input, ref record, clientWriteCipher, clientWriteIV); - } - - - private static int GetEncryptedSizeImpl(int dataSize) - { - return dataSize + Aes128Gcm.CiphertextOverhead; - } - - private static int GetDecryptedSizeImpl(int dataSize) - { - return dataSize - Aes128Gcm.CiphertextOverhead; - } - - private static void EncryptPlaintext(ByteSpan output, ByteSpan input, ref Record record, Aes128Gcm cipher, - ByteSpan writeIV) - { - Debug.Assert(output.Length >= GetEncryptedSizeImpl(input.Length)); - - // Build GCM nonce (authenticated data) - ByteSpan nonce = new byte[ImplicitNonceSize + ExplicitNonceSize]; - writeIV.CopyTo(nonce); - nonce.WriteBigEndian16(record.Epoch, ImplicitNonceSize); - nonce.WriteBigEndian48(record.SequenceNumber, ImplicitNonceSize + 2); - - // Serialize record as additional data - var plaintextRecord = record; - plaintextRecord.Length = (ushort)input.Length; - ByteSpan associatedData = new byte[Record.Size]; - plaintextRecord.Encode(associatedData); - - cipher.Seal(output, nonce, input, associatedData); - } - - private static bool DecryptCiphertext(ByteSpan output, ByteSpan input, ref Record record, Aes128Gcm cipher, - ByteSpan writeIV) - { - Debug.Assert(output.Length >= GetDecryptedSizeImpl(input.Length)); - - // Build GCM nonce (authenticated data) - ByteSpan nonce = new byte[ImplicitNonceSize + ExplicitNonceSize]; - writeIV.CopyTo(nonce); - nonce.WriteBigEndian16(record.Epoch, ImplicitNonceSize); - nonce.WriteBigEndian48(record.SequenceNumber, ImplicitNonceSize + 2); - - // Serialize record as additional data - var plaintextRecord = record; - plaintextRecord.Length = (ushort)GetDecryptedSizeImpl(input.Length); - ByteSpan associatedData = new byte[Record.Size]; - plaintextRecord.Encode(associatedData); - - return cipher.Open(output, nonce, input, associatedData); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/ConnectionId.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/ConnectionId.cs deleted file mode 100644 index 8549e96..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/ConnectionId.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Net; - -namespace Next.Hazel.Dtls; - -public struct ConnectionId : IEquatable -{ - public IPEndPoint EndPoint; - public int Serial; - - public static ConnectionId Create(IPEndPoint endPoint, int serial) - { - return new ConnectionId - { - EndPoint = endPoint, - Serial = serial - }; - } - - public bool Equals(ConnectionId other) - { - return Serial == other.Serial - && EndPoint.Equals(other.EndPoint) - ; - } - - public override bool Equals(object obj) - { - if (obj is ConnectionId) return Equals((ConnectionId)obj); - - return false; - } - - public override int GetHashCode() - { - return EndPoint.GetHashCode(); - } - - public static bool operator ==(ConnectionId left, ConnectionId right) - { - return left.Equals(right); - } - - public static bool operator !=(ConnectionId left, ConnectionId right) - { - return !(left == right); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/DtlsConnectionListener.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/DtlsConnectionListener.cs deleted file mode 100644 index 023b8ac..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/DtlsConnectionListener.cs +++ /dev/null @@ -1,1405 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Net; -using System.Net.Sockets; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.ObjectPool; -using Next.Hazel.Crypto; -using Next.Hazel.Dtls.Handshake; -using Next.Hazel.Dtls.Handshake.Constant; -using Next.Hazel.Udp; -using Serilog; -using Random = Next.Hazel.Dtls.Handshake.Constant.Random; - -namespace Next.Hazel.Dtls; - -/// -/// Listens for new UDP-DTLS connections and creates UdpConnections for them. -/// -/// -public class DtlsConnectionListener : UdpConnectionListener -{ - private const int MaxDatagramSize = 1200; - - private const int MaxCertFragmentSizeV0 = 1200; - - // Min MTU - UDP+IP header - 1 (for good measure. :)) - private const int MaxCertFragmentSizeV1 = 576 - 32 - 1; - private static readonly ILogger Logger = Log.ForContext(); - private static readonly TimeSpan CookieHmacRotationTimeout = TimeSpan.FromHours(1.0); - - // Private key component of certificate's public key - private readonly List encodedCertificates = []; - /*private ByteSpan encodedCertificate;*/ - - private readonly ConcurrentDictionary existingPeers = new(); - private RSA certificatePrivateKey; - - private int connectionSerial_unsafe; - - // HMAC key to validate ClientHello cookie - private HMAC currentCookieHmac; - private uint encodedCertificatesTotalSize; - private DateTime nextCookieHmacRotation; - private HMAC previousCookieHmac; - - private RandomNumberGenerator random; - - /// - /// Create a new instance of the DTLS listener - /// - /// - /// - /// - public DtlsConnectionListener(IPEndPoint endPoint, ObjectPool readerPool, - IPMode ipMode = IPMode.IPv4) - : base(endPoint, readerPool, ipMode) - { - random = RandomNumberGenerator.Create(); - - currentCookieHmac = CreateNewCookieHMAC(); - previousCookieHmac = CreateNewCookieHMAC(); - nextCookieHmacRotation = DateTime.UtcNow + CookieHmacRotationTimeout; - } - - public int PeerCount => existingPeers.Count; - - internal async ValueTask SendData(ByteSpan span, IPEndPoint endPoint) - { - var array = span.ToArray(); - await base.SendData(array, array.Length, endPoint); - } - - internal override async ValueTask SendData(byte[] bytes, int length, IPEndPoint remoteEndPoint) - { - var span = new ByteSpan(bytes); - - if (!existingPeers.TryGetValue(remoteEndPoint, out var peer)) - { - Logger.Warning("Peer not found"); - // Drop messages if we don't know how to send them - return; - } - - await peer.Semaphore.WaitAsync(); - { - // If we're negotiating a new epoch, queue data - if (peer.Epoch == 0 || peer.NextEpoch.State != HandshakeState.ExpectingHello) - { - ByteSpan copyOfSpan = new byte[span.Length]; - span.CopyTo(copyOfSpan); - - peer.QueuedApplicationDataMessage.Add(copyOfSpan); - return; - } - - // Send any queued application data now - for (int ii = 0, nn = peer.QueuedApplicationDataMessage.Count; ii != nn; ++ii) - { - var queuedSpan = peer.QueuedApplicationDataMessage[ii]; - - var outgoingRecord = new Record - { - ContentType = ContentType.ApplicationData, - Epoch = peer.Epoch, - SequenceNumber = peer.CurrentEpoch.NextOutgoingSequence, - Length = (ushort)peer.CurrentEpoch.RecordProtection.GetEncryptedSize(queuedSpan.Length) - }; - ++peer.CurrentEpoch.NextOutgoingSequence; - - // Encode the record to wire format - ByteSpan packet = new byte[Record.Size + outgoingRecord.Length]; - var writer = packet; - outgoingRecord.Encode(writer); - writer = writer[Record.Size..]; - queuedSpan.CopyTo(writer); - - // Protect the record - peer.CurrentEpoch.RecordProtection.EncryptServerPlaintext( - packet.Slice(Record.Size, outgoingRecord.Length) - , packet.Slice(Record.Size, queuedSpan.Length) - , ref outgoingRecord); - - await SendData(packet, remoteEndPoint); - } - - peer.QueuedApplicationDataMessage.Clear(); - - { - var outgoingRecord = new Record - { - ContentType = ContentType.ApplicationData, - Epoch = peer.Epoch, - SequenceNumber = peer.CurrentEpoch.NextOutgoingSequence, - Length = (ushort)peer.CurrentEpoch.RecordProtection.GetEncryptedSize(span.Length) - }; - ++peer.CurrentEpoch.NextOutgoingSequence; - - // Encode the record to wire format - ByteSpan packet = new byte[Record.Size + outgoingRecord.Length]; - var writer = packet; - outgoingRecord.Encode(writer); - writer = writer[Record.Size..]; - span.CopyTo(writer); - - // Protect the record - peer.CurrentEpoch.RecordProtection.EncryptServerPlaintext( - packet.Slice(Record.Size, outgoingRecord.Length) - , packet.Slice(Record.Size, span.Length) - , ref outgoingRecord - ); - - await SendData(packet, remoteEndPoint); - } - } - peer.Semaphore.Release(); - } - - /// - public override async ValueTask DisposeAsync() - { - await base.DisposeAsync(); - - random?.Dispose(); - random = null; - - currentCookieHmac?.Dispose(); - previousCookieHmac?.Dispose(); - currentCookieHmac = null; - previousCookieHmac = null; - - foreach (var pair in existingPeers) pair.Value.Dispose(); - - existingPeers.Clear(); - } - - /// - /// Set the certificate key pair for the listener - /// - /// Certificate for the server - public void SetCertificate(X509Certificate2 certificate) - { - if (!certificate.HasPrivateKey) - throw new ArgumentException("Certificate must have a private key attached", nameof(certificate)); - - var privateKey = certificate.GetRSAPrivateKey(); - if (privateKey == null) - throw new ArgumentException("Certificate must be signed by an RSA key", nameof(certificate)); - - certificatePrivateKey?.Dispose(); - certificatePrivateKey = privateKey; - - // Pre-fragment the certificate data - var certificateData = Certificate.Encode(certificate); - encodedCertificatesTotalSize = (uint)certificateData.Length; - - // The first certificate data needs to leave room for - // * Record header - // * ServerHello header - // * ServerHello payload - // * Certificate header - var padding = Record.Size + Handshake.Handshake.Size + ServerHello.MinSize + Handshake.Handshake.Size; - encodedCertificates.Add(certificateData[..Math.Min(certificateData.Length, MaxDatagramSize - padding)]); - certificateData = certificateData[Math.Min(certificateData.Length, MaxDatagramSize - padding)..]; - - // Subsequent certificate data needs to leave room for - // * Record header - // * Certificate header - padding = Record.Size + Handshake.Handshake.Size; - while (certificateData.Length > 0) - { - encodedCertificates.Add(certificateData[..Math.Min(certificateData.Length, MaxDatagramSize - padding)]); - certificateData = certificateData[Math.Min(certificateData.Length, MaxDatagramSize - padding)..]; - } - /*encodedCertificate = Certificate.Encode(certificate);*/ - } - - /// - /// Handle an incoming datagram from the network. - /// This is primarily a wrapper around ProcessIncomingMessage - /// to ensure `reader.Recycle()` is always called - /// - protected override ValueTask ProcessData(UdpReceiveResult data) - { - var message = new ByteSpan(data.Buffer); - return ProcessIncomingMessage(message, data.RemoteEndPoint); - } - - /// - /// Handle an incoming datagram from the network - /// - private async ValueTask ProcessIncomingMessage(ByteSpan message, IPEndPoint peerAddress) - { - if (!existingPeers.TryGetValue(peerAddress, out var peer)) - { - await HandleNonPeerRecord(message, peerAddress); - return; - } - - await peer.Semaphore.WaitAsync(); - { - // Each incoming packet may contain multiple DTLS - // records - while (message.Length > 0) - { - if (!Record.Parse(out var record, peer.ProtocolVersion, message)) - { - Logger.Error($"Dropping malformed record from `{peerAddress}`"); - return; - } - - message = message[Record.Size..]; - - if (message.Length < record.Length) - { - Logger.Error( - $"Dropping malformed record from `{peerAddress}` Length({record.Length}) AvailableBytes({message.Length})"); - return; - } - - var recordPayload = message[..record.Length]; - message = message[record.Length..]; - - // Early-out and drop ApplicationData records - if (record.ContentType == ContentType.ApplicationData && !peer.CanHandleApplicationData) - { - Logger.Information($"Dropping ApplicationData record from `{peerAddress}` Cannot process yet"); - continue; - } - - // Drop records from a different epoch - if (record.Epoch != peer.Epoch) - { - // Handle existing client negotiating a new connection - if (record is { Epoch: 0, ContentType: ContentType.Handshake }) - { - var handshakePayload = recordPayload; - - if (!Handshake.Handshake.Parse(out var handshake, recordPayload)) - { - Logger.Error($"Dropping malformed re-negotiation Handshake from `{peerAddress}`"); - continue; - } - - handshakePayload = handshakePayload[Handshake.Handshake.Size..]; - - if (handshake.FragmentOffset != 0 || handshake.Length != handshake.FragmentLength) - { - Logger.Error($"Dropping fragmented re-negotiation Handshake from `{peerAddress}`"); - continue; - } - - if (handshake.MessageType != HandshakeType.ClientHello) - { - Logger.Error($"Dropping non-ClientHello re-negotiation Handshake from `{peerAddress}`"); - continue; - } - - if (handshakePayload.Length < handshake.Length) - Logger.Error( - $"Dropping malformed re-negotiation Handshake from `{peerAddress}`: Length({handshake.Length}) AvailableBytes({handshakePayload.Length})"); - - if (!await HandleClientHello(peer, peerAddress, record, handshake, recordPayload, - handshakePayload)) return; - continue; - } - - Logger.Error( - $"Dropping bad-epoch record from `{peerAddress}` RecordEpoch({record.Epoch}) CurrentEpoch({peer.Epoch})"); - continue; - } - - // Prevent replay attacks by dropping records - // we've already processed - var windowIndex = (int)(peer.CurrentEpoch.NextExpectedSequence - record.SequenceNumber - 1); - var windowMask = 1ul << windowIndex; - if (record.SequenceNumber < peer.CurrentEpoch.NextExpectedSequence) - { - if (windowIndex >= 64) - { - Logger.Information( - $"Dropping too-old record from `{peerAddress}` Sequence({record.SequenceNumber}) Expected({peer.CurrentEpoch.NextExpectedSequence})"); - continue; - } - - if ((peer.CurrentEpoch.PreviousSequenceWindowBitmask & windowMask) != 0) - { - Logger.Information($"Dropping duplicate record from `{peerAddress}`"); - continue; - } - } - - // Validate record authenticity - var decryptedSize = peer.CurrentEpoch.RecordProtection.GetDecryptedSize(recordPayload.Length); - if (decryptedSize < 0) - { - Logger.Information( - $"Dropping malformed record: Length {recordPayload.Length} Decrypted length: {decryptedSize}"); - continue; - } - - var decryptedPayload = recordPayload.ReuseSpanIfPossible(decryptedSize); - - if (!peer.CurrentEpoch.RecordProtection.DecryptCiphertextFromClient(decryptedPayload, recordPayload, - ref record)) - { - Logger.Error($"Dropping non-authentic record from `{peerAddress}`"); - return; - } - - recordPayload = decryptedPayload; - - // Update our squence number bookeeping - if (record.SequenceNumber >= peer.CurrentEpoch.NextExpectedSequence) - { - var windowShift = (int)(record.SequenceNumber + 1 - peer.CurrentEpoch.NextExpectedSequence); - peer.CurrentEpoch.PreviousSequenceWindowBitmask <<= windowShift; - peer.CurrentEpoch.NextExpectedSequence = record.SequenceNumber + 1; - } - else - { - peer.CurrentEpoch.PreviousSequenceWindowBitmask |= windowMask; - } - - switch (record.ContentType) - { - case ContentType.ChangeCipherSpec: - if (peer.NextEpoch.State != HandshakeState.ExpectingChangeCipherSpec) - { - Logger.Error( - $"Dropping unexpected ChangeChiperSpec record from `{peerAddress}` State({peer.NextEpoch.State})"); - break; - } - - if (peer.NextEpoch.RecordProtection == null) - { - Debug.Assert(false, - "How did we receive a ChangeCipherSpec message without a pending record protection instance?"); - } - - if (!ChangeCipherSpec.Parse(recordPayload)) - { - Logger.Error($"Dropping malformed ChangeCipherSpec message from `{peerAddress}`"); - break; - } - - // Migrate to the next epoch - peer.Epoch = peer.NextEpoch.Epoch; - peer.CanHandleApplicationData = false; // Need a Finished message - peer.CurrentEpoch.NextOutgoingSequenceForPreviousEpoch = peer.CurrentEpoch.NextOutgoingSequence; - peer.CurrentEpoch.PreviousRecordProtection?.Dispose(); - peer.CurrentEpoch.PreviousRecordProtection = peer.CurrentEpoch.RecordProtection; - peer.CurrentEpoch.RecordProtection = peer.NextEpoch.RecordProtection; - peer.CurrentEpoch.NextOutgoingSequence = 1; - peer.CurrentEpoch.NextExpectedSequence = 1; - peer.CurrentEpoch.PreviousSequenceWindowBitmask = 0; - peer.NextEpoch.ClientVerification.CopyTo(peer.CurrentEpoch.ExpectedClientFinishedVerification); - peer.NextEpoch.ServerVerification.CopyTo(peer.CurrentEpoch.ServerFinishedVerification); - - peer.NextEpoch.State = HandshakeState.ExpectingHello; - peer.NextEpoch.Handshake?.Dispose(); - peer.NextEpoch.Handshake = null; - peer.NextEpoch.NextOutgoingSequence = 1; - peer.NextEpoch.RecordProtection = null; - peer.NextEpoch.VerificationStream.Reset(); - peer.NextEpoch.ClientVerification.SecureClear(); - peer.NextEpoch.ServerVerification.SecureClear(); - break; - - case ContentType.Alert: - Logger.Error($"Dropping unsupported Alert record from `{peerAddress}`"); - break; - - case ContentType.Handshake: - if (!await ProcessHandshake(peer, peerAddress, record, recordPayload)) return; - - break; - - case ContentType.ApplicationData: - // Forward data to the application - await base.ProcessData(new UdpReceiveResult(recordPayload.ToArray(), peerAddress)); - break; - } - } - } - peer.Semaphore.Release(); - } - - /// - /// Process an incoming Handshake protocol message - /// - /// Originating peer - /// Peer's network address - /// Parent record - /// Record payload - /// - /// True if further processing of the underlying datagram - /// should be continues. Otherwise, false. - /// - private async ValueTask ProcessHandshake(PeerData peer, IPEndPoint peerAddress, Record record, - ByteSpan message) - { - // Each record may have multiple handshake payloads - while (message.Length > 0) - { - var originalMessage = message; - - if (!Handshake.Handshake.Parse(out var handshake, message)) - { - Logger.Error($"Dropping malformed Handshake message from `{peerAddress}`"); - return false; - } - - message = message[Handshake.Handshake.Size..]; - - if (message.Length < handshake.Length) - { - Logger.Error($"Dropping malformed Handshake message from `{peerAddress}`"); - return false; - } - - var payload = message[..message.Length]; - message = message[(int)handshake.Length..]; - originalMessage = originalMessage[..(Handshake.Handshake.Size + (int)handshake.Length)]; - - // We do not support fragmented handshake messages - // from the client - if (handshake.FragmentOffset != 0 || handshake.FragmentLength != handshake.Length) - { - Logger.Error( - $"Dropping fragmented Handshake message from `{peerAddress}` Offset({handshake.FragmentOffset}) FragmentLength({handshake.FragmentLength}) Length({handshake.Length})"); - continue; - } - - switch (handshake.MessageType) - { - case HandshakeType.ClientHello: - if (!await HandleClientHello(peer, peerAddress, record, handshake, originalMessage, payload)) - return false; - break; - - case HandshakeType.ClientKeyExchange: - if (peer.NextEpoch.State != HandshakeState.ExpectingClientKeyExchange) - { - Logger.Error( - $"Dropping unexpected ClientKeyExchange message form `{peerAddress}` State({peer.NextEpoch.State})"); - continue; - } - - if (handshake.MessageSequence != 5) - { - Logger.Error( - $"Dropping bad-sequence ClientKeyExchange message from `{peerAddress}` MessageSequence({handshake.MessageSequence})"); - continue; - } - - ByteSpan sharedSecret = new byte[peer.NextEpoch.Handshake.SharedKeySize()]; - if (!peer.NextEpoch.Handshake.VerifyClientMessageAndGenerateSharedKey(sharedSecret, payload)) - { - Logger.Error($"Dropping malformed ClientKeyExchange message from `{peerAddress}`"); - return false; - } - - // Record incoming ClientKeyExchange message - // to verification stream - peer.NextEpoch.VerificationStream.AddData(originalMessage); - - ByteSpan randomSeed = new byte[2 * Random.Size]; - peer.NextEpoch.ClientRandom.CopyTo(randomSeed); - peer.NextEpoch.ServerRandom.CopyTo(randomSeed[Random.Size..]); - - const int MasterSecretSize = 48; - ByteSpan masterSecret = new byte[MasterSecretSize]; - PrfSha256.ExpandSecret( - masterSecret - , sharedSecret - , PrfLabel.MASTER_SECRET - , randomSeed - ); - - // Create the record protection for the upcoming epoch - switch (peer.NextEpoch.SelectedCipherSuite) - { - case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: - peer.NextEpoch.RecordProtection = new Aes128GcmRecordProtection( - masterSecret - , peer.NextEpoch.ServerRandom - , peer.NextEpoch.ClientRandom); - break; - - default: - Debug.Assert(false, - $"How did we agree to a cipher suite {peer.NextEpoch.SelectedCipherSuite} we can't create?"); - return false; - } - - // Generate verification signatures - ByteSpan handshakeStreamHash = new byte[Sha256Stream.DigestSize]; - peer.NextEpoch.VerificationStream.CalculateHash(handshakeStreamHash); - - PrfSha256.ExpandSecret( - peer.NextEpoch.ClientVerification - , masterSecret - , PrfLabel.CLIENT_FINISHED - , handshakeStreamHash - ); - PrfSha256.ExpandSecret( - peer.NextEpoch.ServerVerification - , masterSecret - , PrfLabel.SERVER_FINISHED - , handshakeStreamHash - ); - - - // Update handshake state - masterSecret.SecureClear(); - peer.NextEpoch.State = HandshakeState.ExpectingChangeCipherSpec; - break; - - case HandshakeType.Finished: - // Unlike other handshake messages, this is - // for the current epoch - not the next epoch - - // Cannot process a Finished message for - // epoch 0 - if (peer.Epoch == 0) - { - Logger.Error($"Dropping Finished message for 0-epoch from `{peerAddress}`"); - continue; - } - // Cannot process a Finished message when we - // are negotiating the next epoch - - if (peer.NextEpoch.State != HandshakeState.ExpectingHello) - { - Logger.Error($"Dropping Finished message while negotiating new epoch from `{peerAddress}`"); - continue; - } - // Cannot process a Finished message without - // verify data - - if (peer.CurrentEpoch.ExpectedClientFinishedVerification.Length != Finished.Size || - peer.CurrentEpoch.ServerFinishedVerification.Length != Finished.Size) - { - Debug.Assert(false, "How do we have an established non-zero epoch without verify data?"); - - return false; - } - // Cannot process a Finished message without - // record protection for the previous epoch - - if (peer.CurrentEpoch.PreviousRecordProtection == null) - { - Debug.Assert(false, - "How do we have an established non-zero epoch with record protection for the previous epoch?"); - - return false; - } - - // Verify message sequence - if (handshake.MessageSequence != 6) - { - Logger.Error( - $"Dropping bad-sequence Finished message from `{peerAddress}` MessageSequence({handshake.MessageSequence})"); - continue; - } - - // Verify the client has the correct - // handshake sequence - if (payload.Length != Finished.Size) - { - Logger.Error($"Dropping malformed Finished message from `{peerAddress}`"); - return false; - } - - if (1 != Const.ConstantCompareSpans(payload, peer.CurrentEpoch.ExpectedClientFinishedVerification)) - { - Logger.Error($"Dropping non-verified Finished Handshake from `{peerAddress}`"); - - // Abort the connection here - // - // The client is either broken, or - // doen not agree on our epoch settings. - // - // Either way, there is not a feasible - // way to progress the connection. - // base.MarkConnectionAsStale(peer.ConnectionId); - existingPeers.TryRemove(peerAddress, out _); - return false; - } - - // Describe our ChangeCipherSpec+Finished - var outgoingHandshake = new Handshake.Handshake - { - MessageType = HandshakeType.Finished, - Length = Finished.Size, - MessageSequence = 7, - FragmentOffset = 0 - }; - outgoingHandshake.FragmentLength = outgoingHandshake.Length; - - var changeCipherSpecRecord = new Record - { - ContentType = ContentType.ChangeCipherSpec, - Epoch = (ushort)(peer.Epoch - 1), - SequenceNumber = peer.CurrentEpoch.NextOutgoingSequenceForPreviousEpoch, - Length = (ushort)peer.CurrentEpoch.PreviousRecordProtection.GetEncryptedSize(ChangeCipherSpec - .Size) - }; - ++peer.CurrentEpoch.NextOutgoingSequenceForPreviousEpoch; - - var plaintextFinishedPayloadSize = Handshake.Handshake.Size + (int)outgoingHandshake.Length; - var finishedRecord = new Record - { - ContentType = ContentType.Handshake, - Epoch = peer.Epoch, - SequenceNumber = peer.CurrentEpoch.NextOutgoingSequence, - Length = (ushort)peer.CurrentEpoch.RecordProtection.GetEncryptedSize( - plaintextFinishedPayloadSize) - }; - ++peer.CurrentEpoch.NextOutgoingSequence; - - // Encode the flight into wire format - ByteSpan packet = new byte[Record.Size + changeCipherSpecRecord.Length + Record.Size + - finishedRecord.Length]; - var writer = packet; - changeCipherSpecRecord.Encode(writer); - writer = writer[Record.Size..]; - ChangeCipherSpec.Encode(writer); - - var startOfFinishedRecord = packet[(Record.Size + changeCipherSpecRecord.Length)..]; - writer = startOfFinishedRecord; - finishedRecord.Encode(writer); - writer = writer[Record.Size..]; - outgoingHandshake.Encode(writer); - writer = writer[Handshake.Handshake.Size..]; - peer.CurrentEpoch.ServerFinishedVerification.CopyTo(writer); - - // Protect the ChangeChipherSpec record - peer.CurrentEpoch.PreviousRecordProtection.EncryptServerPlaintext( - packet.Slice(Record.Size, changeCipherSpecRecord.Length) - , packet.Slice(Record.Size, ChangeCipherSpec.Size) - , ref changeCipherSpecRecord - ); - - // Protect the Finished Handshake record - peer.CurrentEpoch.RecordProtection.EncryptServerPlaintext( - startOfFinishedRecord.Slice(Record.Size, finishedRecord.Length) - , startOfFinishedRecord.Slice(Record.Size, plaintextFinishedPayloadSize) - , ref finishedRecord - ); - - // Current epoch can now handle application data - peer.CanHandleApplicationData = true; - - await SendData(packet, peerAddress); - break; - - // Drop messages that we do not support - case HandshakeType.CertificateVerify: - Logger.Error( - $"Dropping unsupported Handshake message from `{peerAddress}` MessageType({handshake.MessageType})"); - continue; - - // Drop messages that originate from the server - case HandshakeType.HelloRequest: - case HandshakeType.ServerHello: - case HandshakeType.HelloVerifyRequest: - case HandshakeType.Certificate: - case HandshakeType.ServerKeyExchange: - case HandshakeType.CertificateRequest: - case HandshakeType.ServerHelloDone: - Logger.Error( - $"Dropping server Handshake message from `{peerAddress}` MessageType({handshake.MessageType})"); - continue; - } - } - - return true; - } - - /// - /// Handle a ClientHello message for a peer - /// - /// Originating peer - /// Peer address - /// Parent record - /// Parent Handshake header - /// - /// Handshake payload - private async ValueTask HandleClientHello(PeerData peer, IPEndPoint peerAddress, Record record, - Handshake.Handshake handshake, ByteSpan originalMessage, ByteSpan payload) - { - // Verify message sequence - if (handshake.MessageSequence != 0) - { - Logger.Error( - $"Dropping bad-sequence ClientHello from `{peerAddress}` MessageSequence({handshake.MessageSequence})`"); - return true; - } - - // Make sure we can handle a ClientHello message - if (peer.NextEpoch.State != HandshakeState.ExpectingHello && - peer.NextEpoch.State != HandshakeState.ExpectingClientKeyExchange) - // Always handle ClientHello for epoch 0 - if (record.Epoch != 0) - { - Logger.Error($"Dropping ClientHello from `{peer}` Not expecting ClientHello"); - return true; - } - - if (!ClientHello.Parse(out var clientHello, peer.ProtocolVersion, payload)) - { - Logger.Error($"Dropping malformed ClientHello Handshake message from `{peerAddress}`"); - return false; - } - - // Find an acceptable cipher suite we can use - const CipherSuite selectedCipherSuite = CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256; - if (!clientHello.ContainsCipherSuite(CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) || - !clientHello.ContainsCurve(NamedCurve.x25519)) - { - Logger.Error($"Dropping ClientHello from `{peerAddress}` No compatible cipher suite"); - return false; - } - - // If this message was not signed by us, - // request a signed message before doing anything else - if (!HelloVerifyRequest.VerifyCookie(clientHello.Cookie, peerAddress, currentCookieHmac)) - if (!HelloVerifyRequest.VerifyCookie(clientHello.Cookie, peerAddress, previousCookieHmac)) - { - ulong outgoingSequence = 1; - IRecordProtection recordProtection = NullRecordProtection.Instance; - if (record.Epoch != 0) - { - outgoingSequence = peer.CurrentEpoch.NextExpectedSequence; - ++peer.CurrentEpoch.NextOutgoingSequenceForPreviousEpoch; - - recordProtection = peer.CurrentEpoch.RecordProtection; - } - - await SendHelloVerifyRequest(peerAddress, outgoingSequence, record.Epoch, recordProtection, peer.ProtocolVersion); - return true; - } - - // Client is initiating a brand new connection. We need - // to destroy the existing connection and establish a - // new session. - if (record.Epoch == 0 && peer.Epoch != 0) - { - var oldConnectionId = peer.ConnectionId; - peer.ResetPeer(AllocateConnectionId(peerAddress), record.SequenceNumber + 1); - - // Inform the parent layer that the existing - // connection should be abandoned. - // base.MarkConnectionAsStale(oldConnectionId); - } - - // Determine if this is an original message, or a retransmission - var recordMessagesForVerifyData = false; - Logger.Verbose("Determine if this is an original message, or a retransmission"); - if (peer.NextEpoch.State == HandshakeState.ExpectingHello) - { - // Create our handhake cipher suite - IHandshakeCipherSuite handshakeCipherSuite; - if (clientHello.ContainsCurve(NamedCurve.x25519)) - { - handshakeCipherSuite = new X25519EcdheRsaSha256(random); - } - else - { - Logger.Error( - $"Dropping ClientHello from `{peerAddress}` Could not create TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 cipher suite"); - return false; - } - - peer.Session = clientHello.SessionInfo; - - // Update the state of our epoch transition - peer.NextEpoch.Epoch = (ushort)(record.Epoch + 1); - peer.NextEpoch.State = HandshakeState.ExpectingClientKeyExchange; - peer.NextEpoch.SelectedCipherSuite = selectedCipherSuite; - peer.NextEpoch.Handshake = handshakeCipherSuite; - clientHello.Random.CopyTo(peer.NextEpoch.ClientRandom); - peer.NextEpoch.ServerRandom.FillWithRandom(random); - recordMessagesForVerifyData = true; - - // Copy the original ClientHello - // handshake to our verification stream - peer.NextEpoch.VerificationStream.AddData( - originalMessage[..(Handshake.Handshake.Size + (int)handshake.Length)] - ); - } - - // The initial record flight from the server - // contains the following Handshake messages: - // * ServerHello - // * Certificate - // * ServerKeyExchange - // * ServerHelloDone - // - // The Certificate message is almost always - // too large to fit into a single datagram, - // so it is pre-fragmented - // (see `SetCertificates`). Therefore, we - // need to send multiple record packets for - // this flight. - // - // The first record contains the ServerHello - // handshake message, as well as the first - // portion of the Certificate message. - // - // We then send a record packet until the - // entire Certificate message has been sent - // to the client. - // - // The final record packet contains the - // ServerKeyExchange and the ServerHelloDone - // messages. - - // Describe first record of the flight - Logger.Verbose("SeverHello"); - var serverHello = new ServerHello - { - ServerProtocolVersion = peer.ProtocolVersion, - Random = peer.NextEpoch.ServerRandom, - CipherSuite = selectedCipherSuite - }; - - var serverHelloHandshake = new Handshake.Handshake - { - MessageType = HandshakeType.ServerHello, - Length = ServerHello.MinSize, - MessageSequence = 1, - FragmentOffset = 0 - }; - serverHelloHandshake.FragmentLength = serverHelloHandshake.Length; - - var maxCertFragmentSize = peer.Session.Version == 0 ? MaxCertFragmentSizeV0 : MaxCertFragmentSizeV1; - - /*var certificateData = encodedCertificate; - var initialCertPadding = Record.Size + Handshake.Handshake.Size + serverHello.Size + Handshake.Handshake.Size; - var certInitialFragmentSize = Math.Min(certificateData.Length, maxCertFragmentSize - initialCertPadding); - - Logger.Verbose("certificateHandshake");*/ - var certificateHandshake = new Handshake.Handshake - { - MessageType = HandshakeType.Certificate, - Length = encodedCertificatesTotalSize, - /*Length = (uint)certificateData.Length,*/ - MessageSequence = 2, - FragmentOffset = 0, - /*FragmentLength = (uint)certInitialFragmentSize*/ - FragmentLength = (uint)encodedCertificates[0].Length - }; - - var initialRecordPayloadSize = 0 - + Handshake.Handshake.Size + serverHello.Size - + Handshake.Handshake.Size + (int)certificateHandshake.FragmentLength - ; - var initialRecord = new Record - { - ContentType = ContentType.Handshake, - ProtocolVersion = peer.ProtocolVersion, - Epoch = peer.Epoch, - SequenceNumber = peer.CurrentEpoch.NextOutgoingSequence, - Length = (ushort)peer.CurrentEpoch.RecordProtection.GetEncryptedSize(initialRecordPayloadSize) - }; - ++peer.CurrentEpoch.NextOutgoingSequence; - - // Convert initial record of the flight to - // wire format - Logger.Verbose("Convert initial record of the flight to"); - ByteSpan packet = new byte[Record.Size + initialRecord.Length]; - var writer = packet; - initialRecord.Encode(writer); - writer = writer[Record.Size..]; - serverHelloHandshake.Encode(writer); - writer = writer[Handshake.Handshake.Size..]; - serverHello.Encode(writer); - writer = writer[ServerHello.MinSize..]; - certificateHandshake.Encode(writer); - writer = writer[Handshake.Handshake.Size..]; - encodedCertificates[0].CopyTo(writer); - /*certificateData[..certInitialFragmentSize].CopyTo(writer); - certificateData = certificateData[certInitialFragmentSize..];*/ - - // Protect initial record of the flight - peer.CurrentEpoch.RecordProtection.EncryptServerPlaintext( - packet.Slice(Record.Size, initialRecord.Length) - , packet.Slice(Record.Size, initialRecordPayloadSize) - , ref initialRecord - ); - - await SendData(packet, peerAddress); - - // Record record payload for verification - Logger.Verbose("Record record payload for verification"); - if (recordMessagesForVerifyData) - { - var fullCeritficateHandshake = certificateHandshake; - fullCeritficateHandshake.FragmentLength = fullCeritficateHandshake.Length; - - packet = new byte[Handshake.Handshake.Size + ServerHello.MinSize + Handshake.Handshake.Size]; - writer = packet; - serverHelloHandshake.Encode(writer); - writer = writer[Handshake.Handshake.Size..]; - serverHello.Encode(writer); - writer = writer[ServerHello.MinSize..]; - certificateHandshake.Encode(writer); - writer.Slice(Handshake.Handshake.Size); - - peer.NextEpoch.VerificationStream.AddData(packet); - /*peer.NextEpoch.VerificationStream.AddData(certificateData);*/ - foreach (var span in encodedCertificates) peer.NextEpoch.VerificationStream.AddData(span); - } - - // Process additional certificate records - Logger.Verbose("Process additional certificate records"); - /*const int CertPadding = Record.Size + Handshake.Handshake.Size; - while (certificateData.Length > 0) - { - var certFragmentSize = Math.Min(certificateData.Length, maxCertFragmentSize - CertPadding); - - certificateHandshake.FragmentOffset += certificateHandshake.FragmentLength; - certificateHandshake.FragmentLength = (uint)certFragmentSize; - - var additionalRecordPayloadSize = Handshake.Handshake.Size + (int)certificateHandshake.FragmentLength; - var additionalRecord = new Record - { - ContentType = ContentType.Handshake, - ProtocolVersion = peer.ProtocolVersion, - Epoch = peer.Epoch, - SequenceNumber = peer.CurrentEpoch.NextOutgoingSequence, - Length = (ushort)peer.CurrentEpoch.RecordProtection.GetEncryptedSize(additionalRecordPayloadSize) - }; - ++peer.CurrentEpoch.NextOutgoingSequence; - - // Convert record to wire format - packet = new byte[Record.Size + additionalRecord.Length]; - writer = packet; - additionalRecord.Encode(writer); - writer = writer[Record.Size..]; - certificateHandshake.Encode(writer); - writer = writer[Handshake.Handshake.Size..]; - certificateData[..certFragmentSize].CopyTo(writer); - certificateData = certificateData[certFragmentSize..]; - - // Protect record - peer.CurrentEpoch.RecordProtection.EncryptServerPlaintext( - packet.Slice(Record.Size, additionalRecord.Length), - packet.Slice(Record.Size, additionalRecordPayloadSize), - ref additionalRecord - ); - - await SendData(packet, peerAddress); - }*/ - for (int ii = 1, nn = encodedCertificates.Count; ii != nn; ++ii) - { - certificateHandshake.FragmentOffset += certificateHandshake.FragmentLength; - certificateHandshake.FragmentLength = (uint)encodedCertificates[ii].Length; - - var additionalRecordPayloadSize = Handshake.Handshake.Size + (int)certificateHandshake.FragmentLength; - var additionalRecord = new Record - { - ContentType = ContentType.Handshake, - Epoch = peer.Epoch, - SequenceNumber = peer.CurrentEpoch.NextOutgoingSequence, - Length = (ushort)peer.CurrentEpoch.RecordProtection.GetEncryptedSize(additionalRecordPayloadSize) - }; - ++peer.CurrentEpoch.NextOutgoingSequence; - - // Convert record to wire format - packet = new byte[Record.Size + additionalRecord.Length]; - writer = packet; - additionalRecord.Encode(writer); - writer = writer[Record.Size..]; - certificateHandshake.Encode(writer); - writer = writer[Handshake.Handshake.Size..]; - encodedCertificates[ii].CopyTo(writer); - - // Protect record - peer.CurrentEpoch.RecordProtection.EncryptServerPlaintext( - packet.Slice(Record.Size, additionalRecord.Length) - , packet.Slice(Record.Size, additionalRecordPayloadSize) - , ref additionalRecord - ); - - await SendData(packet, peerAddress); - } - - // Describe final record of the flight - var serverKeyExchangeHandshake = new Handshake.Handshake - { - MessageType = HandshakeType.ServerKeyExchange, - Length = (uint)peer.NextEpoch.Handshake.CalculateServerMessageSize(certificatePrivateKey), - MessageSequence = 3, - FragmentOffset = 0 - }; - serverKeyExchangeHandshake.FragmentLength = serverKeyExchangeHandshake.Length; - - var serverHelloDoneHandshake = new Handshake.Handshake - { - MessageType = HandshakeType.ServerHelloDone, - Length = 0, - MessageSequence = 4, - FragmentOffset = 0, - FragmentLength = 0 - }; - - var finalRecordPayloadSize = 0 - + Handshake.Handshake.Size + (int)serverKeyExchangeHandshake.Length - + Handshake.Handshake.Size + (int)serverHelloDoneHandshake.Length - ; - var finalRecord = new Record - { - ContentType = ContentType.Handshake, - Epoch = peer.Epoch, - SequenceNumber = peer.CurrentEpoch.NextOutgoingSequence, - Length = (ushort)peer.CurrentEpoch.RecordProtection.GetEncryptedSize(finalRecordPayloadSize) - }; - ++peer.CurrentEpoch.NextOutgoingSequence; - Logger.Verbose("finalRecordPayload"); - - // Convert final record of the flight to wire - // format - packet = new byte[Record.Size + finalRecord.Length]; - writer = packet; - finalRecord.Encode(writer); - writer = writer[Record.Size..]; - serverKeyExchangeHandshake.Encode(writer); - writer = writer[Handshake.Handshake.Size..]; - peer.NextEpoch.Handshake.EncodeServerKeyExchangeMessage(writer, certificatePrivateKey); - writer = writer[(int)serverKeyExchangeHandshake.Length..]; - serverHelloDoneHandshake.Encode(writer); - Logger.Verbose("Convert final record of the flight to wire"); - - // Record record payload for verification - if (recordMessagesForVerifyData) - peer.NextEpoch.VerificationStream.AddData( - packet.Slice( - packet.Offset + Record.Size - , finalRecordPayloadSize - ) - ); - - // Protect final record of the flight - peer.CurrentEpoch.RecordProtection.EncryptServerPlaintext( - packet.Slice(Record.Size, finalRecord.Length) - , packet.Slice(Record.Size, finalRecordPayloadSize) - , ref finalRecord - ); - - await SendData(packet, peerAddress); - - return true; - } - - /// - /// Handle an incoming packet that is not tied to an existing peer - /// - /// Incoming datagram - /// Originating address - private async ValueTask HandleNonPeerRecord(ByteSpan message, IPEndPoint peerAddress) - { - if (!Record.Parse(out var record, null, message)) - { - Logger.Error($"Dropping malformed record from non-peer `{peerAddress}`"); - return; - } - - message = message[Record.Size..]; - - // The protocol only supports receiving a single record - // from a non-peer. - if (record.Length != message.Length) - if (message.Length < record.Length) - { - Logger.Information( - $"Dropping bad record from non-peer `{peerAddress}`. Msg length {message.Length} < {record.Length}"); - return; - } - - // We only accept zero-epoch records from non-peers - if (record.Epoch != 0) return; - - // We only accept Handshake protocol messages from non-peers - if (record.ContentType != ContentType.Handshake) - { - Logger.Error($"Dropping non-handhsake message from non-peer `{peerAddress}`"); - return; - } - - var originalMessage = message; - - if (!Handshake.Handshake.Parse(out var handshake, message)) - { - Logger.Error($"Dropping malformed handshake message from non-peer `{peerAddress}`"); - return; - } - - // We only accept ClientHello messages from non-peers - if (handshake.MessageType != HandshakeType.ClientHello) - { - Logger.Error($"Dropping non-ClientHello ({handshake.MessageType}) message from non-peer `{peerAddress}`"); - return; - } - - message = message[Handshake.Handshake.Size..]; - - if (!ClientHello.Parse(out var clientHello, null, message)) - { - Logger.Error($"Dropping malformed ClientHello message from non-peer `{peerAddress}`"); - return; - } - - // If this ClientHello is not signed by us, request the - // client send us a signed message - if (!HelloVerifyRequest.VerifyCookie(clientHello.Cookie, peerAddress, currentCookieHmac)) - if (!HelloVerifyRequest.VerifyCookie(clientHello.Cookie, peerAddress, previousCookieHmac)) - { - await SendHelloVerifyRequest(peerAddress, 1, 0, NullRecordProtection.Instance, clientHello.ClientProtocolVersion); - return; - } - - // Allocate state for the new peer and register it - var peer = new PeerData(clientHello.ClientProtocolVersion); - peer.ResetPeer(AllocateConnectionId(peerAddress), record.SequenceNumber + 1); - - existingPeers[peerAddress] = peer; - - await peer.Semaphore.WaitAsync(); - { - await ProcessHandshake(peer, peerAddress, record, originalMessage); - } - peer.Semaphore.Release(); - } - - //Send a HelloVerifyRequest handshake message to a peer - private ValueTask SendHelloVerifyRequest(IPEndPoint peerAddress, ulong recordSequence, ushort epoch, - IRecordProtection recordProtection, ProtocolVersion protocolVersion) - { - // Do we need to rotate the HMAC key? - var now = DateTime.UtcNow; - if (now > nextCookieHmacRotation) - { - previousCookieHmac.Dispose(); - previousCookieHmac = currentCookieHmac; - currentCookieHmac = CreateNewCookieHMAC(); - nextCookieHmacRotation = now + CookieHmacRotationTimeout; - } - - var handshake = new Handshake.Handshake - { - MessageType = HandshakeType.HelloVerifyRequest, - Length = HelloVerifyRequest.Size, - MessageSequence = 0, - FragmentOffset = 0 - }; - handshake.FragmentLength = handshake.Length; - - var plaintextPayloadSize = Handshake.Handshake.Size + (int)handshake.Length; - - var record = new Record - { - ContentType = ContentType.Handshake, - ProtocolVersion = protocolVersion, - Epoch = epoch, - SequenceNumber = recordSequence, - Length = (ushort)recordProtection.GetEncryptedSize(plaintextPayloadSize) - }; - - // Encode record to wire format - ByteSpan packet = new byte[Record.Size + record.Length]; - var writer = packet; - record.Encode(writer); - writer = writer[Record.Size..]; - handshake.Encode(writer); - writer = writer[Handshake.Handshake.Size..]; - HelloVerifyRequest.Encode(writer, peerAddress, currentCookieHmac, protocolVersion); - - // Protect record payload - recordProtection.EncryptServerPlaintext( - packet.Slice(Record.Size, record.Length) - , packet.Slice(Record.Size, plaintextPayloadSize) - , ref record - ); - - return SendData(packet, peerAddress); - } - - // public override ValueTask DisconnectOldConnections(TimeSpan maxAge, MessageWriter disconnectMessage) - // { - // DateTime now = DateTime.UtcNow; - // foreach (KeyValuePair kvp in this.existingPeers) - // { - // PeerData peer = kvp.Value; - // lock (peer) - // { - // if (peer.Epoch == 0 || peer.NextEpoch.State != HandshakeState.ExpectingHello) - // { - // TimeSpan negotiationAge = now - peer.StartOfNegotiation; - // if (negotiationAge > maxAge) - // { - // base.MarkConnectionAsStale(peer.ConnectionId); - // } - // } - // } - // } - // - // return base.DisconnectOldConnections(maxAge, disconnectMessage); - // } - - internal void RemovePeerRecord(ConnectionId connectionId) - { - existingPeers.TryRemove(connectionId.EndPoint, out _); - } - - /// - /// Allocate a new connection id - /// - private ConnectionId AllocateConnectionId(IPEndPoint endPoint) - { - var rawSerialId = Interlocked.Increment(ref connectionSerial_unsafe); - return ConnectionId.Create(endPoint, rawSerialId); - } - - /// - /// Create a new cookie HMAC signer - /// - private static HMAC CreateNewCookieHMAC() - { - return new HMACSHA1(); - } - - /// - /// Current state of handshake sequence - /// - private enum HandshakeState - { - ExpectingHello, - ExpectingClientKeyExchange, - ExpectingChangeCipherSpec, - ExpectingFinish - } - - /// - /// State to manage the current epoch `N` - /// - private struct CurrentEpoch - { - public ulong NextOutgoingSequence; - - public ulong NextExpectedSequence; - public ulong PreviousSequenceWindowBitmask; - - public IRecordProtection RecordProtection; - public IRecordProtection PreviousRecordProtection; - - // Need to keep these around so we can re-transmit our - // last handshake record flight - public ByteSpan ExpectedClientFinishedVerification; - public ByteSpan ServerFinishedVerification; - public ulong NextOutgoingSequenceForPreviousEpoch; - } - - /// - /// State to manage the transition from the current - /// epoch `N` to epoch `N+1` - /// - private struct NextEpoch - { - public ushort Epoch; - - public HandshakeState State; - public CipherSuite SelectedCipherSuite; - - public ulong NextOutgoingSequence; - - public IHandshakeCipherSuite Handshake; - public IRecordProtection RecordProtection; - - public ByteSpan ClientRandom; - public ByteSpan ServerRandom; - - public Sha256Stream VerificationStream; - - public ByteSpan ClientVerification; - public ByteSpan ServerVerification; - } - - /// - /// Per-peer state - /// - private sealed class PeerData : IDisposable - { - public readonly ProtocolVersion ProtocolVersion; - public readonly List QueuedApplicationDataMessage = []; - - public readonly SemaphoreSlim Semaphore = new(1, 1); - public bool CanHandleApplicationData; - - public ConnectionId ConnectionId; - public CurrentEpoch CurrentEpoch; - public ushort Epoch; - public NextEpoch NextEpoch; - - public HazelDtlsSessionInfo Session; - - public DateTime StartOfNegotiation; - - public PeerData(ProtocolVersion protocolVersion) - { - ProtocolVersion = protocolVersion; - ByteSpan block = new byte[2 * Finished.Size]; - CurrentEpoch.ServerFinishedVerification = block[..Finished.Size]; - CurrentEpoch.ExpectedClientFinishedVerification = block.Slice(Finished.Size, Finished.Size); - - ResetPeer(ConnectionId.Create(new IPEndPoint(0, 0), 0), 1); - } - - public void Dispose() - { - CurrentEpoch.RecordProtection?.Dispose(); - CurrentEpoch.PreviousRecordProtection?.Dispose(); - NextEpoch.RecordProtection?.Dispose(); - NextEpoch.Handshake?.Dispose(); - NextEpoch.VerificationStream?.Dispose(); - } - - public void ResetPeer(ConnectionId connectionId, ulong nextExpectedSequenceNumber) - { - Dispose(); - - Epoch = 0; - CanHandleApplicationData = false; - QueuedApplicationDataMessage.Clear(); - - CurrentEpoch.NextOutgoingSequence = 2; // Account for our ClientHelloVerify - CurrentEpoch.NextExpectedSequence = nextExpectedSequenceNumber; - CurrentEpoch.PreviousSequenceWindowBitmask = 0; - CurrentEpoch.RecordProtection = NullRecordProtection.Instance; - CurrentEpoch.PreviousRecordProtection = null; - CurrentEpoch.ServerFinishedVerification.SecureClear(); - CurrentEpoch.ExpectedClientFinishedVerification.SecureClear(); - - NextEpoch.State = HandshakeState.ExpectingHello; - NextEpoch.RecordProtection = null; - NextEpoch.Handshake = null; - NextEpoch.ClientRandom = new byte[Random.Size]; - NextEpoch.ServerRandom = new byte[Random.Size]; - NextEpoch.VerificationStream = new Sha256Stream(); - NextEpoch.ClientVerification = new byte[Finished.Size]; - NextEpoch.ServerVerification = new byte[Finished.Size]; - - ConnectionId = connectionId; - - StartOfNegotiation = DateTime.UtcNow; - } - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Certificate.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Certificate.cs deleted file mode 100644 index 277284e..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Certificate.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Security.Cryptography.X509Certificates; - -namespace Next.Hazel.Dtls.Handshake; - -/// -/// Encode/decode Handshake Certificate message -/// -public struct Certificate -{ - /// - /// Encode a certificate to wire formate - /// - public static ByteSpan Encode(X509Certificate2 certificate) - { - ByteSpan certData = certificate.GetRawCertData(); - var totalSize = certData.Length + 3 + 3; - - ByteSpan result = new byte[totalSize]; - - var writer = result; - writer.WriteBigEndian24((uint)certData.Length + 3); - writer = writer[3..]; - writer.WriteBigEndian24((uint)certData.Length); - writer = writer[3..]; - - certData.CopyTo(writer); - return result; - } - - /// - /// Parse a Handshake Certificate payload from wire format - /// - /// True if we successfully decode the Certificate message. Otherwise false - public static bool Parse(out X509Certificate2 certificate, ByteSpan span) - { - certificate = null; - if (span.Length < 6) return false; - - var totalSize = span.ReadBigEndian24(); - span = span[3..]; - - if (span.Length < totalSize) return false; - - var certificateSize = span.ReadBigEndian24(); - span = span[3..]; - if (span.Length < certificateSize) return false; - - var rawData = new byte[certificateSize]; - span.CopyTo(rawData, 0); - try - { -#if NET8_0 || NET6_0 - certificate = new X509Certificate2(rawData); -#else - certificate = X509CertificateLoader.LoadCertificate(rawData); -#endif - } - catch (Exception) - { - return false; - } - - return true; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/ClientHello.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/ClientHello.cs deleted file mode 100644 index f2800dd..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/ClientHello.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System.Diagnostics; -using Next.Hazel.Dtls.Handshake.Constant; - -namespace Next.Hazel.Dtls.Handshake; - -/// -/// Encode/decode ClientHello Handshake message -/// -public struct ClientHello -{ - public ProtocolVersion ClientProtocolVersion; - public HazelDtlsSessionInfo SessionInfo; - public ByteSpan Random; - public ByteSpan Cookie; - public ByteSpan CipherSuites; - public ByteSpan SupportedCurves; - - public const int MinSize = 0 - + 2 // client_version - + Constant.Random.Size // random - + 1 // session_id (size) - + 1 // cookie (size) - + 2 // cipher_suites (size) - + 1 // compression_methods (size) - + 1 // compression_method[0] (NULL) - + 2 // extensions size - + 0 // NamedCurveList extensions[0] - + 2 // extensions[0].extension_type - + 2 // extensions[0].extension_data (length) - + 2 // extensions[0].named_curve_list (size) - ; - - /// - /// Calculate the size in bytes required for the ClientHello payload - /// - /// - public int CalculateSize() - { - return MinSize - + SessionInfo.PayloadSize - + Cookie.Length - + CipherSuites.Length - + SupportedCurves.Length - ; - } - - /// - /// Parse a Handshake ClientHello payload from wire format - /// - /// True if we successfully decode the ClientHello message. Otherwise false - public static bool Parse(out ClientHello result, ProtocolVersion? expectedProtocolVersion, ByteSpan span) - { - result = new ClientHello(); - if (span.Length < MinSize) return false; - - result.ClientProtocolVersion = (ProtocolVersion)span.ReadBigEndian16(); - if (expectedProtocolVersion.HasValue && result.ClientProtocolVersion != expectedProtocolVersion.Value) - return false; - span = span[2..]; - - result.Random = span[..Constant.Random.Size]; - span = span[Constant.Random.Size..]; - - if (!HazelDtlsSessionInfo.Parse(out result.SessionInfo, span)) return false; - - span = span[result.SessionInfo.FullSize..]; - - var cookieSize = span[0]; - if (span.Length < 1 + cookieSize) return false; - result.Cookie = span.Slice(1, cookieSize); - span = span[(1 + cookieSize)..]; - - var cipherSuiteSize = span.ReadBigEndian16(); - if (span.Length < 2 + cipherSuiteSize) return false; - - if (cipherSuiteSize % 2 != 0) return false; - result.CipherSuites = span.Slice(2, cipherSuiteSize); - span = span[(2 + cipherSuiteSize)..]; - - int compressionMethodsSize = span[0]; - var foundNullCompressionMethod = false; - for (var ii = 0; ii != compressionMethodsSize; ++ii) - if (span[1 + ii] == (byte)CompressionMethod.Null) - { - foundNullCompressionMethod = true; - break; - } - - if (!foundNullCompressionMethod - || span.Length < 1 + compressionMethodsSize) - return false; - - span = span[(1 + compressionMethodsSize)..]; - - switch (span.Length) - { - // Parse extensions - case <= 0: - return true; - case < 2: - return false; - } - - var extensionsSize = span.ReadBigEndian16(); - span = span[2..]; - if (span.Length != extensionsSize) return false; - - while (span.Length > 0) - { - // Parse extension header - if (span.Length < 4) return false; - - var extensionType = (ExtensionType)span.ReadBigEndian16(); - var extensionLength = span.ReadBigEndian16(2); - - if (span.Length < 4 + extensionLength) return false; - - var extensionData = span.Slice(4, extensionLength); - span = span[(4 + extensionLength)..]; - result.ParseExtension(extensionType, extensionData); - } - - return true; - } - - /// - /// Decode a ClientHello extension - /// - /// Extension type - /// Extension data - private void ParseExtension(ExtensionType extensionType, ByteSpan extensionData) - { - switch (extensionType) - { - case ExtensionType.EllipticCurves: - if (extensionData.Length % 2 != 0) break; - - if (extensionData.Length < 2) break; - - var namedCurveSize = extensionData.ReadBigEndian16(); - if (namedCurveSize % 2 != 0) break; - - SupportedCurves = extensionData.Slice(2, namedCurveSize); - break; - } - } - - /// - /// Determines if the ClientHello message advertises support - /// for the specified cipher suite - /// - public bool ContainsCipherSuite(CipherSuite cipherSuite) - { - var iterator = CipherSuites; - while (iterator.Length >= 2) - { - if (iterator.ReadBigEndian16() == (ushort)cipherSuite) return true; - - iterator = iterator[2..]; - } - - return false; - } - - /// - /// Determines if the ClientHello message advertises support - /// for the specified curve - /// - public bool ContainsCurve(NamedCurve curve) - { - var iterator = SupportedCurves; - while (iterator.Length >= 2) - { - if (iterator.ReadBigEndian16() == (ushort)curve) return true; - - iterator = iterator[2..]; - } - - return false; - } - - /// - /// Encode Handshake ClientHello payload to wire format - /// - public void Encode(ByteSpan span) - { - span.WriteBigEndian16((ushort)ProtocolVersion.DTLS1_2); - span = span[2..]; - - Debug.Assert(Random.Length == Constant.Random.Size); - Random.CopyTo(span); - span = span[Constant.Random.Size..]; - - - SessionInfo.Encode(span); - span = span[SessionInfo.FullSize..]; - - span[0] = (byte)Cookie.Length; - Cookie.CopyTo(span[1..]); - span = span[(1 + Cookie.Length)..]; - - span.WriteBigEndian16((ushort)CipherSuites.Length); - CipherSuites.CopyTo(span[2..]); - span = span[(2 + CipherSuites.Length)..]; - - span[0] = 1; - span[1] = (byte)CompressionMethod.Null; - span = span[2..]; - - // Extensions size - span.WriteBigEndian16((ushort)(6 + SupportedCurves.Length)); - span = span[2..]; - - // Supported curves extension - span.WriteBigEndian16((ushort)ExtensionType.EllipticCurves); - span.WriteBigEndian16((ushort)(2 + SupportedCurves.Length), 2); - span.WriteBigEndian16((ushort)SupportedCurves.Length, 4); - SupportedCurves.CopyTo(span[6..]); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/CipherSuite.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/CipherSuite.cs deleted file mode 100644 index af324ba..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/CipherSuite.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Next.Hazel.Dtls.Handshake.Constant; - -/// -/// List of cipher suites -/// -public enum CipherSuite -{ - TLS_NULL_WITH_NULL_NULL = 0x0000, - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/CompressionMethod.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/CompressionMethod.cs deleted file mode 100644 index 6596c0f..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/CompressionMethod.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Next.Hazel.Dtls.Handshake.Constant; - -/// -/// List of compression methods -/// -public enum CompressionMethod : byte -{ - Null = 0 -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/ECCurveType.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/ECCurveType.cs deleted file mode 100644 index db5f0aa..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/ECCurveType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Next.Hazel.Dtls.Handshake.Constant; - -/// -/// Elliptic curve type -/// -public enum ECCurveType : byte -{ - NamedCurve = 3 -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/ExtensionType.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/ExtensionType.cs deleted file mode 100644 index 77da2a0..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/ExtensionType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Next.Hazel.Dtls.Handshake.Constant; - -/// -/// Extension type -/// -public enum ExtensionType : ushort -{ - EllipticCurves = 10 -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/Finished.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/Finished.cs deleted file mode 100644 index 3f9491d..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/Finished.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Next.Hazel.Dtls.Handshake.Constant; - -/// -/// Encode/decode Handshake Finished message -/// -public struct Finished -{ - public const int Size = 12; -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/HandshakeType.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/HandshakeType.cs deleted file mode 100644 index 0f3f1fc..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/HandshakeType.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Next.Hazel.Dtls.Handshake.Constant; - -/// -/// Handshake message type -/// -public enum HandshakeType : byte -{ - HelloRequest = 0, - ClientHello = 1, - ServerHello = 2, - HelloVerifyRequest = 3, - Certificate = 11, - ServerKeyExchange = 12, - CertificateRequest = 13, - ServerHelloDone = 14, - CertificateVerify = 15, - ClientKeyExchange = 16, - Finished = 20 -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/HashAlgorithm.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/HashAlgorithm.cs deleted file mode 100644 index ce1f4c6..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/HashAlgorithm.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Next.Hazel.Dtls.Handshake.Constant; - -/// -/// Hash algorithms -/// -public enum HashAlgorithm : byte -{ - None = 0, - Sha256 = 4 -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/NamedCurve.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/NamedCurve.cs deleted file mode 100644 index fa2bcb2..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/NamedCurve.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Next.Hazel.Dtls.Handshake.Constant; - -/// -/// Named curves -/// -public enum NamedCurve : ushort -{ - Reserved = 0, - secp256r1 = 23, - x25519 = 29 -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/Random.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/Random.cs deleted file mode 100644 index eba6f19..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/Random.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Next.Hazel.Dtls.Handshake.Constant; - -/// -/// Random state for entropy -/// -public struct Random -{ - public const int Size = 0 - + 4 // gmt_unix_time - + 28 // random_bytes - ; -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/SignatureAlgorithm.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/SignatureAlgorithm.cs deleted file mode 100644 index a701b49..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Constant/SignatureAlgorithm.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Next.Hazel.Dtls.Handshake.Constant; - -/// -/// Signature algorithms -/// -public enum SignatureAlgorithm : byte -{ - Anonymous = 0, - RSA = 1, - ECDSA = 3 -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Handshake.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Handshake.cs deleted file mode 100644 index bdb2e67..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/Handshake.cs +++ /dev/null @@ -1,48 +0,0 @@ -using Next.Hazel.Dtls.Handshake.Constant; - -namespace Next.Hazel.Dtls.Handshake; - -/// -/// Encode/decode handshake protocol header -/// -public struct Handshake -{ - public HandshakeType MessageType; - public uint Length; - public ushort MessageSequence; - public uint FragmentOffset; - public uint FragmentLength; - - public const int Size = 12; - - /// - /// Parse a Handshake protocol header from wire format - /// - /// True if we successfully decode a handshake header. Otherwise false - public static bool Parse(out Handshake header, ByteSpan span) - { - header = new Handshake(); - - if (span.Length < Size) return false; - - header.MessageType = (HandshakeType)span[0]; - header.Length = span.ReadBigEndian24(1); - header.MessageSequence = span.ReadBigEndian16(4); - header.FragmentOffset = span.ReadBigEndian24(6); - header.FragmentLength = span.ReadBigEndian24(9); - return true; - } - - /// - /// Encode the Handshake protocol header to wire format - /// - /// - public void Encode(ByteSpan span) - { - span[0] = (byte)MessageType; - span.WriteBigEndian24(Length, 1); - span.WriteBigEndian16(MessageSequence, 4); - span.WriteBigEndian24(FragmentOffset, 6); - span.WriteBigEndian24(FragmentLength, 9); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/HazelDtlsSessionInfo.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/HazelDtlsSessionInfo.cs deleted file mode 100644 index 229e72f..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/HazelDtlsSessionInfo.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System; - -namespace Next.Hazel.Dtls.Handshake; - -/// -/// Encode/Decode session information in ClientHello -/// -public struct HazelDtlsSessionInfo -{ - public const byte CurrentClientSessionSize = 1; - public const byte CurrentClientSessionVersion = 1; - - public byte FullSize => (byte)(1 + PayloadSize); - public byte PayloadSize; - public byte Version; - - public HazelDtlsSessionInfo(byte version) - { - Version = version; - switch (version) - { - case 0: // Does not write version byte - PayloadSize = 0; - return; - case 1: // Writes version byte only - PayloadSize = 1; - return; - } - - throw new ArgumentOutOfRangeException(nameof(version)); - } - - public void Encode(ByteSpan writer) - { - writer[0] = PayloadSize; - - if (Version > 0) writer[1] = Version; - } - - public static bool Parse(out HazelDtlsSessionInfo result, ByteSpan reader) - { - result = new HazelDtlsSessionInfo(); - if (reader.Length < 1) return false; - - result.PayloadSize = reader[0]; - - // Back compat, length may be zero, version defaults to 0. - if (result.PayloadSize == 0) - { - result.Version = 0; - return true; - } - - // Forward compat, if length > 1, ignore the rest - result.Version = reader[1]; - return true; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/HelloVerifyRequest.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/HelloVerifyRequest.cs deleted file mode 100644 index 5b37070..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/HelloVerifyRequest.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System.Net; -using System.Security.Cryptography; -using Next.Hazel.Crypto; - -namespace Next.Hazel.Dtls.Handshake; - -/// -/// Encode/decode Handshake HelloVerifyRequest message -/// -public struct HelloVerifyRequest -{ - public const int CookieSize = 20; - - public const int Size = 0 - + 2 // server_version - + 1 // cookie (size) - + CookieSize // cookie (data) - ; - - public ProtocolVersion ServerProtocolVersion; - public ByteSpan Cookie; - - /// - /// Parse a Handshake HelloVerifyRequest payload from wire - /// format - /// - /// - /// True if we successfully decode the HelloVerifyRequest - /// message. Otherwise false. - /// - public static bool Parse(out HelloVerifyRequest result, ProtocolVersion? expectedProtocolVersion, ByteSpan span) - { - result = new HelloVerifyRequest(); - if (span.Length < 3) return false; - - result.ServerProtocolVersion = (ProtocolVersion)span.ReadBigEndian16(); - if (expectedProtocolVersion.HasValue && result.ServerProtocolVersion != expectedProtocolVersion.Value) - return false; - - - var cookieSize = span[2]; - span = span[3..]; - - if (span.Length < cookieSize) return false; - - result.Cookie = span; - return true; - } - - /// - /// Encode a HelloVerifyRequest payload to wire format - /// - /// - /// Address of the remote peer - /// Listener HMAC signature provider - /// - public static void Encode(ByteSpan span, EndPoint peerAddress, HMAC hmac, ProtocolVersion protocolVersion) - { - var cookie = ComputeAddressMac(peerAddress, hmac); - - span.WriteBigEndian16((ushort)protocolVersion); - span[2] = CookieSize; - cookie.CopyTo(span[3..]); - } - - /// - /// Generate an HMAC for a peer address - /// - /// Address of the remote peer - /// Listener HMAC signature provider - public static ByteSpan ComputeAddressMac(EndPoint peerAddress, HMAC hmac) - { - var address = peerAddress.Serialize(); - var data = new byte[address.Size]; - for (int ii = 0, nn = data.Length; ii != nn; ++ii) data[ii] = address[ii]; - - ByteSpan signature = hmac.ComputeHash(data); - return signature[..CookieSize]; - } - - /// - /// Verify a client's cookie was signed by our listener - /// - /// Wire format cookie - /// Address of the remote peer - /// Listener HMAC signature provider - /// True if the cookie is valid. Otherwise false - public static bool VerifyCookie(ByteSpan cookie, EndPoint peerAddress, HMAC hmac) - { - if (cookie.Length != CookieSize) return false; - - var expectedHash = ComputeAddressMac(peerAddress, hmac); - if (expectedHash.Length != cookie.Length) return false; - - return 1 == Const.ConstantCompareSpans(cookie, expectedHash); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/ServerHello.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/ServerHello.cs deleted file mode 100644 index 547d732..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Handshake/ServerHello.cs +++ /dev/null @@ -1,76 +0,0 @@ -using System.Diagnostics; -using Next.Hazel.Dtls.Handshake.Constant; - -namespace Next.Hazel.Dtls.Handshake; - -/// -/// Encode/decode Handshake ServerHello message -/// -public struct ServerHello -{ - public ProtocolVersion ServerProtocolVersion; - public ByteSpan Random; - public CipherSuite CipherSuite; - public HazelDtlsSessionInfo Session; - - public const int MinSize = 0 - + 2 // server_version - + Constant.Random.Size // random - + 1 // session_id (size) - + 2 // cipher_suite - + 1 // compression_method - ; - - public int Size => MinSize + Session.PayloadSize; - - /// - /// Parse a Handshake ServerHello payload from wire format - /// - /// - /// True if we successfully decode the ServerHello - /// message. Otherwise false. - /// - public static bool Parse(out ServerHello result, ByteSpan span) - { - result = new ServerHello(); - if (span.Length < MinSize) return false; - - result.ServerProtocolVersion = (ProtocolVersion)span.ReadBigEndian16(); - span = span[2..]; - - result.Random = span[..Constant.Random.Size]; - span = span[Constant.Random.Size..]; - - if (!HazelDtlsSessionInfo.Parse(out result.Session, span)) return false; - - span = span[result.Session.FullSize..]; - - result.CipherSuite = (CipherSuite)span.ReadBigEndian16(); - span = span[2..]; - - var compressionMethod = (CompressionMethod)span[0]; - return compressionMethod == CompressionMethod.Null; - } - - /// - /// Encode Handshake ServerHello to wire format - /// - public void Encode(ByteSpan span) - { - Debug.Assert(Random.Length == Constant.Random.Size); - - span.WriteBigEndian16((ushort)ServerProtocolVersion); - span = span[2..]; - - Random.CopyTo(span); - span = span[Constant.Random.Size..]; - - Session.Encode(span); - span = span[Session.FullSize..]; - - span.WriteBigEndian16((ushort)CipherSuite); - span = span[2..]; - - span[0] = (byte)CompressionMethod.Null; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/IHandshakeCipherSuite.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/IHandshakeCipherSuite.cs deleted file mode 100644 index d672e3a..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/IHandshakeCipherSuite.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; - -namespace Next.Hazel.Dtls; - -/// -/// DTLS cipher suite interface for the handshake portion of -/// the connection. -/// -public interface IHandshakeCipherSuite : IDisposable -{ - /// - /// Gets the size of the shared key - /// - /// Size of the shared key in bytes - int SharedKeySize(); - - /// - /// Calculate the size of the ServerKeyExchnage message - /// - /// - /// Private key that will be used to sign the message - /// - /// Size of the message in bytes - int CalculateServerMessageSize(object privateKey); - - /// - /// Encodes the ServerKeyExchange message - /// - /// - /// Private key to use for signing - void EncodeServerKeyExchangeMessage(ByteSpan output, object privateKey); - - /// - /// Verifies the authenticity of a server key exchange - /// message and calculates the shared secret. - /// - /// - /// True if the authenticity has been validated and a shared key - /// was generated. Otherwise, false. - /// - bool VerifyServerMessageAndGenerateSharedKey(ByteSpan output, ByteSpan serverKeyExchangeMessage, object publicKey); - - /// - /// Calculate the size of the ClientKeyExchange message - /// - /// Size of the message in bytes - int CalculateClientMessageSize(); - - /// - /// Encodes the ClientKeyExchangeMessage - /// - void EncodeClientKeyExchangeMessage(ByteSpan output); - - /// - /// Verifies the validity of a client key exchange message - /// and calculats the hsared secret. - /// - /// - /// True if the client exchange message is valid and a - /// shared key was generated. Otherwise, false. - /// - bool VerifyClientMessageAndGenerateSharedKey(ByteSpan output, ByteSpan clientKeyExchangeMessage); -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/IRecordProtection.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/IRecordProtection.cs deleted file mode 100644 index 7db4d15..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/IRecordProtection.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using Next.Hazel.Dtls.Handshake.Constant; - -namespace Next.Hazel.Dtls; - -/// -/// DTLS cipher suite interface for protection of record payload. -/// -public interface IRecordProtection : IDisposable -{ - /// - /// Calculate the size of an encrypted plaintext - /// - /// Size of plaintext in bytes - /// Size of encrypted ciphertext in bytes - int GetEncryptedSize(int dataSize); - - /// - /// Calculate the size of decrypted ciphertext - /// - /// Size of ciphertext in bytes - /// Size of decrypted plaintext in bytes - int GetDecryptedSize(int dataSize); - - /// - /// Encrypt a plaintext intput with server keys - /// Output may overlap with input. - /// - /// Output ciphertext - /// Input plaintext - /// Parent DTLS record - void EncryptServerPlaintext(ByteSpan output, ByteSpan input, ref Record record); - - /// - /// Encrypt a plaintext intput with client keys - /// Output may overlap with input. - /// - /// Output ciphertext - /// Input plaintext - /// Parent DTLS record - void EncryptClientPlaintext(ByteSpan output, ByteSpan input, ref Record record); - - /// - /// Decrypt a ciphertext intput with server keys - /// Output may overlap with input. - /// - /// Output plaintext - /// Input ciphertext - /// Parent DTLS record - /// True if the input was authenticated and decrypted. Otherwise false - bool DecryptCiphertextFromServer(ByteSpan output, ByteSpan input, ref Record record); - - /// - /// Decrypt a ciphertext intput with client keys - /// Output may overlap with input. - /// - /// Output plaintext - /// Input ciphertext - /// Parent DTLS record - /// True if the input was authenticated and decrypted. Otherwise false - bool DecryptCiphertextFromClient(ByteSpan output, ByteSpan input, ref Record record); -} - -/// -/// Factory to create record protection from cipher suite identifiers -/// -public sealed class RecordProtectionFactory -{ - public static IRecordProtection Create(CipherSuite cipherSuite, ByteSpan masterSecret, ByteSpan serverRandom, - ByteSpan clientRandom) - { - switch (cipherSuite) - { - case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: - return new Aes128GcmRecordProtection(masterSecret, serverRandom, clientRandom); - - default: - return null; - } - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/NullRecordProtection.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/NullRecordProtection.cs deleted file mode 100644 index d059888..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/NullRecordProtection.cs +++ /dev/null @@ -1,55 +0,0 @@ -namespace Next.Hazel.Dtls; - -/// -/// Passthrough record protection implementaion -/// -public class NullRecordProtection : IRecordProtection -{ - public static readonly NullRecordProtection Instance = new(); - - public void Dispose() - { - } - - public int GetEncryptedSize(int dataSize) - { - return dataSize; - } - - public int GetDecryptedSize(int dataSize) - { - return dataSize; - } - - public void EncryptServerPlaintext(ByteSpan output, ByteSpan input, ref Record record) - { - CopyMaybeOverlappingSpans(output, input); - } - - public void EncryptClientPlaintext(ByteSpan output, ByteSpan input, ref Record record) - { - CopyMaybeOverlappingSpans(output, input); - } - - public bool DecryptCiphertextFromServer(ByteSpan output, ByteSpan input, ref Record record) - { - CopyMaybeOverlappingSpans(output, input); - return true; - } - - public bool DecryptCiphertextFromClient(ByteSpan output, ByteSpan input, ref Record record) - { - CopyMaybeOverlappingSpans(output, input); - return true; - } - - private static void CopyMaybeOverlappingSpans(ByteSpan output, ByteSpan input) - { - // Early out if the ranges `output` is equal to `input` - if (output.GetUnderlyingArray() == input.GetUnderlyingArray()) - if (output.Offset == input.Offset && output.Length == input.Length) - return; - - input.CopyTo(output); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/PrfSha256.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/PrfSha256.cs deleted file mode 100644 index 4c89243..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/PrfSha256.cs +++ /dev/null @@ -1,80 +0,0 @@ -using System.Security.Cryptography; -using System.Text; - -namespace Next.Hazel.Dtls; - -/// -/// Common Psuedorandom Function labels for TLS -/// -public struct PrfLabel -{ - public static readonly ByteSpan MASTER_SECRET = LabelToBytes("master secert"); - public static readonly ByteSpan KEY_EXPANSION = LabelToBytes("key expansion"); - public static readonly ByteSpan CLIENT_FINISHED = LabelToBytes("client finished"); - public static readonly ByteSpan SERVER_FINISHED = LabelToBytes("server finished"); - - /// - /// Convert a text label to a byte sequence - /// - public static ByteSpan LabelToBytes(string label) - { - return Encoding.ASCII.GetBytes(label); - } -} - -/// -/// The P_SHA256 Psuedorandom Function -/// -public struct PrfSha256 -{ - /// - /// Expand a secret key - /// - /// Output span. Length determines how much data to generate - /// Original key to expand - /// Label (treated as a salt) - /// Seed for expansion (treated as a salt) - public static void ExpandSecret(ByteSpan output, ByteSpan key, string label, ByteSpan initialSeed) - { - ExpandSecret(output, key, PrfLabel.LabelToBytes(label), initialSeed); - } - - /// - /// Expand a secret key - /// - /// Output span. Length determines how much data to generate - /// Original key to expand - /// Label (treated as a salt) - /// Seed for expansion (treated as a salt) - public static void ExpandSecret(ByteSpan output, ByteSpan key, ByteSpan label, ByteSpan initialSeed) - { - var writer = output; - - var roundSeed = new byte[label.Length + initialSeed.Length]; - label.CopyTo(roundSeed); - initialSeed.CopyTo(roundSeed, label.Length); - - var hashA = roundSeed; - - using (var hmac = new HMACSHA256(key.ToArray())) - { - var input = new byte[hmac.OutputBlockSize + roundSeed.Length]; - new ByteSpan(roundSeed).CopyTo(input, hmac.OutputBlockSize); - - while (writer.Length > 0) - { - // Update hashA - hashA = hmac.ComputeHash(hashA); - - // generate hash input - new ByteSpan(hashA).CopyTo(input); - - ByteSpan roundOutput = hmac.ComputeHash(input); - if (roundOutput.Length > writer.Length) roundOutput = roundOutput[..writer.Length]; - - roundOutput.CopyTo(writer); - writer = writer[roundOutput.Length..]; - } - } - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Record.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/Record.cs deleted file mode 100644 index fc2bb44..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/Record.cs +++ /dev/null @@ -1,106 +0,0 @@ -namespace Next.Hazel.Dtls; - -/// -/// DTLS version constants -/// -public enum ProtocolVersion : ushort -{ - /// - /// Use to obfuscate DTLS as regular UDP packets - /// - UDP = 0, - - /// - /// DTLS 1.2 - /// - DTLS1_2 = 0xFEFD -} - -/// -/// DTLS record content type -/// -public enum ContentType : byte -{ - ChangeCipherSpec = 20, - Alert = 21, - Handshake = 22, - ApplicationData = 23 -} - -/// -/// Encode/decode DTLS record header -/// -public struct Record -{ - public ContentType ContentType; - public ProtocolVersion ProtocolVersion; - public ushort Epoch; - public ulong SequenceNumber; - public ushort Length; - - public const int Size = 13; - - /// - /// Parse a DTLS record from wire format - /// - /// True if we successfully parse the record header. Otherwise false - public static bool Parse(out Record record, ProtocolVersion? expectedProtocolVersion, ByteSpan span) - { - record = new Record(); - - if (span.Length < Size) return false; - - record.ContentType = (ContentType)span[0]; - record.ProtocolVersion = (ProtocolVersion)span.ReadBigEndian16(1); - record.Epoch = span.ReadBigEndian16(3); - record.SequenceNumber = span.ReadBigEndian48(5); - record.Length = span.ReadBigEndian16(11); - - return !expectedProtocolVersion.HasValue || record.ProtocolVersion == expectedProtocolVersion.Value; - } - - /// - /// Encode a DTLS record to wire format - /// - public void Encode(ByteSpan span) - { - span[0] = (byte)ContentType; - span.WriteBigEndian16((ushort)ProtocolVersion, 1); - span.WriteBigEndian16(Epoch, 3); - span.WriteBigEndian48(SequenceNumber, 5); - span.WriteBigEndian16(Length, 11); - } -} - -public struct ChangeCipherSpec -{ - public const int Size = 1; - - private enum Value : byte - { - ChangeCipherSpec = 1 - } - - /// - /// Parse a ChangeCipherSpec record from wire format - /// - /// - /// True if we successfully parse the ChangeCipherSpec - /// record. Otherwise, false. - /// - public static bool Parse(ByteSpan span) - { - if (span.Length != 1) return false; - - var value = (Value)span[0]; - return value == Value.ChangeCipherSpec; - } - - /// - /// Encode a ChangeCipherSpec record to wire format - /// - public static void Encode(ByteSpan span) - { - span[0] = (byte)Value.ChangeCipherSpec; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Dtls/X25519EcdheRsaSha256.cs b/src/NextFast.Hazel-New/Next.Hazel/Dtls/X25519EcdheRsaSha256.cs deleted file mode 100644 index 2a77ec7..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Dtls/X25519EcdheRsaSha256.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Diagnostics; -using System.Security.Cryptography; -using Next.Hazel.Crypto; -using Next.Hazel.Dtls.Handshake.Constant; -using HashAlgorithm = Next.Hazel.Dtls.Handshake.Constant.HashAlgorithm; - -namespace Next.Hazel.Dtls; - -/// -/// ECDHE_RSA_*_256 cipher suite -/// -public class X25519EcdheRsaSha256 : IHandshakeCipherSuite -{ - private static readonly int ClientMessageSize = 0 - + 1 + X25519.KeySize // ECPoint ClientKeyExchange.ecdh_Yc - ; - - private readonly ByteSpan privateAgreementKey; - private SHA256 sha256 = SHA256.Create(); - - /// - /// Create a new instance of the x25519 key exchange - /// - /// Random data source - public X25519EcdheRsaSha256(RandomNumberGenerator random) - { - var buffer = new byte[X25519.KeySize]; - random.GetBytes(buffer); - privateAgreementKey = buffer; - } - - /// - public void Dispose() - { - sha256?.Dispose(); - sha256 = null; - } - - /// - public int SharedKeySize() - { - return X25519.KeySize; - } - - /// - public int CalculateServerMessageSize(object privateKey) - { - if (privateKey is not RSA rsaPrivateKey) throw new ArgumentException("Invalid private key", nameof(privateKey)); - - return CalculateServerMessageSize(rsaPrivateKey.KeySize); - } - - /// - public void EncodeServerKeyExchangeMessage(ByteSpan output, object privateKey) - { - var rsaPrivateKey = privateKey as RSA; - if (rsaPrivateKey == null) throw new ArgumentException("Invalid private key", nameof(privateKey)); - - output[0] = (byte)ECCurveType.NamedCurve; - output.WriteBigEndian16((ushort)NamedCurve.x25519, 1); - output[3] = X25519.KeySize; - X25519.Func(output.Slice(4, X25519.KeySize), privateAgreementKey); - - // Hash the key parameters - var paramterDigest = sha256.ComputeHash(output.GetUnderlyingArray(), output.Offset, 4 + X25519.KeySize); - - // Sign the paramter digest - var signer = new RSAPKCS1SignatureFormatter(rsaPrivateKey); - signer.SetHashAlgorithm("SHA256"); - ByteSpan signature = signer.CreateSignature(paramterDigest); - - Debug.Assert(signature.Length == rsaPrivateKey.KeySize / 8); - output[4 + X25519.KeySize] = (byte)HashAlgorithm.Sha256; - output[5 + X25519.KeySize] = (byte)SignatureAlgorithm.RSA; - output[(6 + X25519.KeySize)..].WriteBigEndian16((ushort)signature.Length); - signature.CopyTo(output[(8 + X25519.KeySize)..]); - } - - /// - public bool VerifyServerMessageAndGenerateSharedKey(ByteSpan output, ByteSpan serverKeyExchangeMessage, - object publicKey) - { - if (publicKey is not RSA rsaPublicKey) return false; - - if (output.Length != X25519.KeySize) return false; - - // Verify message is compatible with this cipher suite - if (serverKeyExchangeMessage.Length != CalculateServerMessageSize(rsaPublicKey.KeySize)) return false; - - if (serverKeyExchangeMessage[0] != (byte)ECCurveType.NamedCurve) return false; - - if (serverKeyExchangeMessage.ReadBigEndian16(1) != (ushort)NamedCurve.x25519) return false; - - if (serverKeyExchangeMessage[3] != X25519.KeySize) return false; - - if (serverKeyExchangeMessage[4 + X25519.KeySize] != (byte)HashAlgorithm.Sha256) return false; - - if (serverKeyExchangeMessage[5 + X25519.KeySize] != (byte)SignatureAlgorithm.RSA) return false; - - var keyParameters = serverKeyExchangeMessage[..(4 + X25519.KeySize)]; - var othersPublicKey = keyParameters[4..]; - var signatureSize = serverKeyExchangeMessage.ReadBigEndian16(6 + X25519.KeySize); - var signature = serverKeyExchangeMessage[(4 + keyParameters.Length)..]; - - if (signatureSize != signature.Length) return false; - - // Hash the key parameters - var parameterDigest = - sha256.ComputeHash(keyParameters.GetUnderlyingArray(), keyParameters.Offset, keyParameters.Length); - - // Verify the signature - var verifier = new RSAPKCS1SignatureDeformatter(rsaPublicKey); - verifier.SetHashAlgorithm("SHA256"); - if (!verifier.VerifySignature(parameterDigest, signature.ToArray())) return false; - - // Signature has been validated, generate the shared key - return X25519.Func(output, privateAgreementKey, othersPublicKey); - } - - /// - public int CalculateClientMessageSize() - { - return ClientMessageSize; - } - - /// - public void EncodeClientKeyExchangeMessage(ByteSpan output) - { - output[0] = X25519.KeySize; - X25519.Func(output.Slice(1, X25519.KeySize), privateAgreementKey); - } - - /// - public bool VerifyClientMessageAndGenerateSharedKey(ByteSpan output, ByteSpan clientKeyExchangeMessage) - { - if (clientKeyExchangeMessage.Length != ClientMessageSize) return false; - - if (clientKeyExchangeMessage[0] != X25519.KeySize) return false; - - var othersPublicKey = clientKeyExchangeMessage[1..]; - return X25519.Func(output, privateAgreementKey, othersPublicKey); - } - - /// - /// Calculate the server message size given an RSA key size - /// - /// - /// Size of the private key (in bits) - /// - /// - /// Size of the ServerKeyExchange message in bytes - /// - private static int CalculateServerMessageSize(int keySize) - { - var signatureSize = keySize / 8; - - return 0 - + 1 // ECCurveType ServerKeyExchange.params.curve_params.curve_type - + 2 // NamedCurve ServerKeyExchange.params.curve_params.namedcurve - + 1 + X25519.KeySize // ECPoint ServerKeyExchange.params.public - + 1 // HashAlgorithm ServerKeyExchange.algorithm.hash - + 1 // SignatureAlgorithm ServerKeyExchange.signed_params.algorithm.signature - + 2 // ServerKeyExchange.signed_params.size - + signatureSize // ServerKeyExchange.signed_params.opaque - ; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/DtlsHelper.cs b/src/NextFast.Hazel-New/Next.Hazel/DtlsHelper.cs deleted file mode 100644 index 7922150..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/DtlsHelper.cs +++ /dev/null @@ -1,59 +0,0 @@ -#nullable enable -using System; -using System.Collections.Generic; -using System.IO; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.OpenSsl; -using Org.BouncyCastle.Security; - -namespace Next.Hazel; - -// https://github.com/willardf/Hazel-Networking/blob/main/Hazel.UnitTests/Dtls/DtlsConnectionTests.cs -public static class DtlsHelper -{ - public static X509Certificate2 GetCertificate(string certificateSting, string privateKeyString = "") - { - var privateKey = privateKeyString != "" ? DecodeRSAKeyFromPEM(privateKeyString) : null; - var rawData = DecodePEM(certificateSting); -#if NET8_0 || NET6_0 - var certificate = new X509Certificate2(rawData); -#else - var certificate = X509CertificateLoader.LoadCertificate(rawData); -#endif - return privateKey != null - ? certificate.CopyWithPrivateKey(privateKey) - : certificate; - } - - public static X509Certificate2Collection GetCertificateCollection(this X509Certificate2 certificate) - { - return new X509Certificate2Collection(certificate); - } - - public static byte[] DecodePEM(string pemData) - { - var result = new List(); - - var lines = pemData.Replace("\r", "").Split('\n'); - foreach (var line in lines) - { - if (line.StartsWith("-----")) continue; - - var lineData = Convert.FromBase64String(line); - result.AddRange(lineData); - } - - return result.ToArray(); - } - - public static RSA DecodeRSAKeyFromPEM(string pemData) - { - var pemReader = new PemReader(new StringReader(pemData)); - var parameters = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)pemReader.ReadObject()); - var rsa = RSA.Create(); - rsa.ImportParameters(parameters); - return rsa; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Extensions/DefaultMessageWriterProvider.cs b/src/NextFast.Hazel-New/Next.Hazel/Extensions/DefaultMessageWriterProvider.cs deleted file mode 100644 index 12f64c0..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Extensions/DefaultMessageWriterProvider.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Next.Hazel.Abstractions; - -namespace Next.Hazel.Extensions; - -public class DefaultMessageWriterProvider : IMessageWriterProvider -{ - public IMessageWriter Get(MessageType sendOption = MessageType.Unreliable) - { - return MessageWriter.Get(sendOption); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Extensions/ServiceProviderExtensions.cs b/src/NextFast.Hazel-New/Next.Hazel/Extensions/ServiceProviderExtensions.cs deleted file mode 100644 index c98f786..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Extensions/ServiceProviderExtensions.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.ObjectPool; - -namespace Next.Hazel.Extensions; - -#nullable enable -public static class ServiceProviderExtensions -{ - public static IServiceCollection AddPolicy(this IServiceCollection services) - where TPolicy : class, IPooledObjectPolicy - where TP : class - { - return services.AddPolicy(new DefaultObjectPoolProvider()); - } - - public static IServiceCollection AddPolicy(this IServiceCollection services, - TPoolProvider? Instance = null) - where TPolicy : class, IPooledObjectPolicy - where TPoolProvider : ObjectPoolProvider - where TP : class - { - if (Instance != null) - services.TryAddSingleton(Instance); - else - services.TryAddSingleton(); - - return services.AddSingleton(serviceProvider => - { - var provider = serviceProvider.GetRequiredService(); - var policy = ActivatorUtilities.CreateInstance(serviceProvider); - return provider.Create(policy); - }); - } - - public static IServiceCollection AddHazel(this IServiceCollection services) - { - return services.AddPolicy(); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Hazel.nuspec b/src/NextFast.Hazel-New/Next.Hazel/Hazel.nuspec deleted file mode 100644 index cd90fed..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Hazel.nuspec +++ /dev/null @@ -1,19 +0,0 @@ - - - - DarkRiftNetworking.Hazel - $version$ - $title$ - DarkRiftNetworking - DarkRiftNetworking - https://github.com/DarkRiftNetworking/Hazel-Networking/blob/master/LICENSE - https://github.com/DarkRiftNetworking/Hazel-Networking - false - Hazel Networking is a low-level networking library for C# providing connection orientated, message - based communication via TCP, UDP and RUDP. - - First release (Beta) - Copyright 2016 - network networking TCP UDP RUDP socket sockets Unity3d Unity - - \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/HazelException.cs b/src/NextFast.Hazel-New/Next.Hazel/HazelException.cs deleted file mode 100644 index 5702cb4..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/HazelException.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; - -namespace Next.Hazel; - -/// -/// Wrapper for exceptions thrown from Hazel. -/// -[Serializable] -public class HazelException : Exception -{ - internal HazelException(string msg) : base(msg) - { - } - - internal HazelException(string msg, Exception e) : base(msg, e) - { - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/IPMode.cs b/src/NextFast.Hazel-New/Next.Hazel/IPMode.cs deleted file mode 100644 index f0f16c3..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/IPMode.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Next.Hazel; - -/// -/// Represents the IP version that a connection or listener will use. -/// -/// -/// this sets the underlying sockets to use IPv6 but still allow IPv4 sockets to connect for backwards compatability -/// and hence it is the default IPMode in most cases. -/// -public enum IPMode -{ - /// - /// Instruction to use IPv4 only, IPv6 connections will not be able to connect. - /// - IPv4, - - /// - /// Instruction to use IPv6 only, IPv4 connections will not be able to connect. IPv4 addresses can be connected - /// by converting to IPv6 addresses. - /// - IPv6 -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/IRecyclable.cs b/src/NextFast.Hazel-New/Next.Hazel/IRecyclable.cs deleted file mode 100644 index a3f7b3c..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/IRecyclable.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Next.Hazel; - -/// -/// Interface for all items that can be returned to an object pool. -/// -/// -public interface IRecyclable -{ - /// - /// Returns this object back to the object pool. - /// - /// - /// - /// Calling this when you are done with the object returns the object back to a pool in order to be reused. - /// This can reduce the amount of work the GC has to do dramatically but it is optional to call this. - /// - /// - /// Calling this indicates to Hazel that this can be reused and thus you should only call this when you are - /// completely finished with the object as the contents can be overwritten at any point after. - /// - /// - void Recycle(); -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/MessageReader.cs b/src/NextFast.Hazel-New/Next.Hazel/MessageReader.cs deleted file mode 100644 index 6ca457f..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/MessageReader.cs +++ /dev/null @@ -1,274 +0,0 @@ -#nullable enable -using System; -using System.Buffers.Binary; -using System.Runtime.CompilerServices; -using System.Text; -using Microsoft.Extensions.ObjectPool; -using Next.Hazel.Abstractions; - -namespace Next.Hazel; - -public class MessageReader : IMessageReader -{ - private readonly ObjectPool _pool; - private bool _inUse; - - internal MessageReader(ObjectPool pool) - { - _pool = pool; - } - - private MessageReader? _parent { get; set; } - - private int ReadPosition => Offset + Position; - - public int BytesRemaining => Length - Position; - - public IMessageReader? Parent => _parent; - - public byte[]? Buffer { get; private set; } - - public int Offset { get; internal set; } - - public int Position { get; internal set; } - - public int Length { get; internal set; } - - public byte Tag { get; private set; } - - public IMessageReader ReadMessage() - { - var length = ReadUInt16(); - var tag = FastByte(); - var pos = ReadPosition; - - Position += length; - - var reader = _pool.Get(); - reader.Update(Buffer!, pos, 0, length, tag, this); - return reader; - } - - public void RemoveMessage(IMessageReader message) - { - if (message.Buffer != Buffer) - throw new InvalidOperationException( - "Tried to remove message from a message that does not have the same buffer."); - - // Offset of where to start removing. - var offsetStart = message.Offset - 3; - - // Offset of where to end removing. - var offsetEnd = message.Offset + message.Length; - - // The amount of bytes to copy over ourselves. - var lengthToCopy = message.Buffer!.Length - offsetEnd; - - System.Buffer.BlockCopy(Buffer!, offsetEnd, Buffer!, offsetStart, lengthToCopy); - - ((MessageReader)message)._parent?.AdjustLength(message.Offset, message.Length + 3); - } - - public void Dispose() - { - if (_inUse) _pool.Return(this); - } - - public void CopyTo(IMessageWriter writer) - { - writer.Write((ushort)Length); - writer.Write(Tag); - writer.Write(Buffer.AsMemory(Offset, Length)); - } - - public IMessageReader Copy(int offset = 0) - { - var reader = _pool.Get(); - reader.Update(Buffer!, Offset + offset, Position, Length - offset, Tag, _parent); - return reader; - } - - public void Seek(int position) - { - Position = position; - } - - public void Update(byte[] buffer, int offset = 0, int position = 0, int? length = null, byte tag = byte.MaxValue, - MessageReader? parent = null) - { - _inUse = true; - - Buffer = buffer; - Offset = offset; - Position = position; - Length = length ?? buffer.Length; - Tag = tag; - _parent = parent; - } - - internal void Reset() - { - _inUse = false; - - Tag = byte.MaxValue; - Buffer = null; - Offset = 0; - Position = 0; - Length = 0; - _parent = null; - } - - /*public void InsertMessage(IMessageReader reader, IMessageWriter writer) - { - }*/ - - private void AdjustLength(int offset, int amount) - { - Length -= amount; - - if (ReadPosition > offset) Position -= amount; - - if (_parent == null || Buffer == null) return; - var lengthOffset = Offset - 3; - var curLen = Buffer[lengthOffset] | - (Buffer[lengthOffset + 1] << 8); - - curLen -= amount; - - Buffer[lengthOffset] = (byte)curLen; - Buffer[lengthOffset + 1] = (byte)(Buffer[lengthOffset + 1] >> 8); - - _parent.AdjustLength(offset, amount); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private byte FastByte() - { - return Buffer![Offset + Position++]; - } - - #region Read Methods - - public bool ReadBoolean() - { - var val = FastByte(); - return val != 0; - } - - public sbyte ReadSByte() - { - return (sbyte)FastByte(); - } - - public byte ReadByte() - { - return FastByte(); - } - - public ushort ReadUInt16() - { - var output = BinaryPrimitives.ReadUInt16LittleEndian(Buffer.AsSpan(ReadPosition)); - Position += sizeof(ushort); - return output; - } - - public short ReadInt16() - { - var output = BinaryPrimitives.ReadInt16LittleEndian(Buffer.AsSpan(ReadPosition)); - Position += sizeof(short); - return output; - } - - public uint ReadUInt32() - { - var output = BinaryPrimitives.ReadUInt32LittleEndian(Buffer.AsSpan(ReadPosition)); - Position += sizeof(uint); - return output; - } - - public int ReadInt32() - { - var output = BinaryPrimitives.ReadInt32LittleEndian(Buffer.AsSpan(ReadPosition)); - Position += sizeof(int); - return output; - } - - public ulong ReadUInt64() - { - var output = BinaryPrimitives.ReadUInt64LittleEndian(Buffer.AsSpan(ReadPosition)); - Position += sizeof(ulong); - return output; - } - - public long ReadInt64() - { - var output = BinaryPrimitives.ReadInt64LittleEndian(Buffer.AsSpan(ReadPosition)); - Position += sizeof(long); - return output; - } - - public float ReadSingle() - { - var output = BinaryPrimitives.ReadSingleLittleEndian(Buffer.AsSpan(ReadPosition)); - Position += sizeof(float); - return output; - } - - public string ReadString(int length) - { - var output = Encoding.UTF8.GetString(Buffer.AsSpan(ReadPosition, length)); - Position += length; - return output; - } - - public string ReadString() - { - return ReadString(ReadPackedInt32()); - } - - public ReadOnlyMemory ReadBytesAndSize() - { - var len = ReadPackedInt32(); - return ReadBytes(len); - } - - public ReadOnlyMemory ReadBytes(int length) - { - var output = Buffer.AsMemory(ReadPosition, length); - Position += length; - return output; - } - - public int ReadPackedInt32() - { - return (int)ReadPackedUInt32(); - } - - public uint ReadPackedUInt32() - { - var readMore = true; - var shift = 0; - uint output = 0; - - while (readMore) - { - var b = FastByte(); - if (b >= 0x80) - { - readMore = true; - b ^= 0x80; - } - else - { - readMore = false; - } - - output |= (uint)(b << shift); - shift += 7; - } - - return output; - } - - #endregion -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/MessageReaderPolicy.cs b/src/NextFast.Hazel-New/Next.Hazel/MessageReaderPolicy.cs deleted file mode 100644 index c944adb..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/MessageReaderPolicy.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.ObjectPool; - -namespace Next.Hazel; - -public class MessageReaderPolicy : IPooledObjectPolicy -{ - private readonly IServiceProvider _serviceProvider; - - public MessageReaderPolicy(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - - public MessageReader Create() - { - return new MessageReader(_serviceProvider.GetRequiredService>()); - } - - public bool Return(MessageReader obj) - { - obj.Reset(); - return true; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/MessageWriter.cs b/src/NextFast.Hazel-New/Next.Hazel/MessageWriter.cs deleted file mode 100644 index 75b3b84..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/MessageWriter.cs +++ /dev/null @@ -1,321 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Text; -using Next.Hazel.Abstractions; - -namespace Next.Hazel; - -public class MessageWriter : IMessageWriter, IRecyclable -{ - public static int BufferSize = 64000; - private static readonly ObjectPoolCustom WriterPool = new(() => new MessageWriter(BufferSize)); - - private readonly Stack messageStarts = new(); - - public MessageWriter(byte[] buffer) - { - Buffer = buffer; - Length = Buffer.Length; - } - - public MessageWriter(int bufferSize) - { - Buffer = new byte[bufferSize]; - } - - public MessageType SendOption { get; private set; } - - public byte[] Buffer { get; } - public int Length { get; set; } - public int Position { get; set; } - - public byte[] ToByteArray(bool includeHeader) - { - if (includeHeader) - { - var output = new byte[Length]; - System.Buffer.BlockCopy(Buffer, 0, output, 0, Length); - return output; - } - - switch (SendOption) - { - case MessageType.Reliable: - { - var output = new byte[Length - 3]; - System.Buffer.BlockCopy(Buffer, 3, output, 0, Length - 3); - return output; - } - case MessageType.Unreliable: - { - var output = new byte[Length - 1]; - System.Buffer.BlockCopy(Buffer, 1, output, 0, Length - 1); - return output; - } - - default: - return []; - } - } - - public void StartMessage(byte typeFlag) - { - messageStarts.Push(Position); - Position += 2; // Skip for size - Write(typeFlag); - } - - public void EndMessage() - { - var lastMessageStart = messageStarts.Pop(); - var length = (ushort)(Position - lastMessageStart - 3); // Minus length and type byte - Buffer[lastMessageStart] = (byte)length; - Buffer[lastMessageStart + 1] = (byte)(length >> 8); - } - - public void Clear(MessageType sendOption) - { - messageStarts.Clear(); - SendOption = sendOption; - Buffer[0] = (byte)sendOption; - switch (sendOption) - { - default: - case MessageType.Unreliable: - Length = Position = 1; - break; - - case MessageType.Reliable: - Length = Position = 3; - break; - } - } - - public void Dispose() - { - Recycle(); - } - - public void Recycle() - { - Position = Length = 0; - WriterPool.PutObject(this); - } - - /// The option specifying how the message should be sent. - public static MessageWriter Get(MessageType sendOption = MessageType.Unreliable) - { - var output = WriterPool.GetObject(); - output.Clear(sendOption); - - return output; - } - - public bool HasBytes(int expected) - { - if (SendOption == MessageType.Unreliable) return Length > 1 + expected; - - return Length > 3 + expected; - } - - public void CancelMessage() - { - Position = messageStarts.Pop(); - Length = Position; - } - - #region WriteMethods - - public void Write(bool value) - { - Buffer[Position++] = (byte)(value ? 1 : 0); - if (Position > Length) Length = Position; - } - - public void Write(sbyte value) - { - Buffer[Position++] = (byte)value; - if (Position > Length) Length = Position; - } - - public void Write(byte value) - { - Buffer[Position++] = value; - if (Position > Length) Length = Position; - } - - public void Write(short value) - { - Buffer[Position++] = (byte)value; - Buffer[Position++] = (byte)(value >> 8); - if (Position > Length) Length = Position; - } - - public void Write(ushort value) - { - Buffer[Position++] = (byte)value; - Buffer[Position++] = (byte)(value >> 8); - if (Position > Length) Length = Position; - } - - public void Write(uint value) - { - Buffer[Position++] = (byte)value; - Buffer[Position++] = (byte)(value >> 8); - Buffer[Position++] = (byte)(value >> 16); - Buffer[Position++] = (byte)(value >> 24); - if (Position > Length) Length = Position; - } - - public void Write(int value) - { - Buffer[Position++] = (byte)value; - Buffer[Position++] = (byte)(value >> 8); - Buffer[Position++] = (byte)(value >> 16); - Buffer[Position++] = (byte)(value >> 24); - if (Position > Length) Length = Position; - } - - public void Write(ulong value) - { - Buffer[Position++] = (byte)value; - Buffer[Position++] = (byte)(value >> 8); - Buffer[Position++] = (byte)(value >> 16); - Buffer[Position++] = (byte)(value >> 24); - Buffer[Position++] = (byte)(value >> 32); - Buffer[Position++] = (byte)(value >> 40); - Buffer[Position++] = (byte)(value >> 48); - Buffer[Position++] = (byte)(value >> 56); - if (Position > Length) Length = Position; - } - - public void Write(long value) - { - Buffer[Position++] = (byte)value; - Buffer[Position++] = (byte)(value >> 8); - Buffer[Position++] = (byte)(value >> 16); - Buffer[Position++] = (byte)(value >> 24); - Buffer[Position++] = (byte)(value >> 32); - Buffer[Position++] = (byte)(value >> 40); - Buffer[Position++] = (byte)(value >> 48); - Buffer[Position++] = (byte)(value >> 56); - if (Position > Length) Length = Position; - } - - public unsafe void Write(float value) - { - fixed (byte* ptr = &Buffer[Position]) - { - var valuePtr = (byte*)&value; - - *ptr = *valuePtr; - *(ptr + 1) = *(valuePtr + 1); - *(ptr + 2) = *(valuePtr + 2); - *(ptr + 3) = *(valuePtr + 3); - } - - Position += 4; - if (Position > Length) Length = Position; - } - - public void Write(string value) - { - var bytes = Encoding.UTF8.GetBytes(value); - WritePacked(bytes.Length); - Write(bytes); - } - - public void WriteBytesAndSize(byte[] bytes) - { - WritePacked((uint)bytes.Length); - Write(bytes); - } - - public void WriteBytesAndSize(byte[] bytes, int length) - { - WritePacked((uint)length); - Write(bytes, length); - } - - public void WriteBytesAndSize(byte[] bytes, int offset, int length) - { - WritePacked((uint)length); - Write(bytes, offset, length); - } - - public void Write(ReadOnlyMemory data) - { - Write(data.Span); - } - - public void Write(ReadOnlySpan bytes) - { - bytes.CopyTo(Buffer.AsSpan(Position, bytes.Length)); - - Position += bytes.Length; - if (Position > Length) Length = Position; - } - - public void Write(byte[] bytes) - { - Array.Copy(bytes, 0, Buffer, Position, bytes.Length); - Position += bytes.Length; - if (Position > Length) Length = Position; - } - - public void Write(byte[] bytes, int offset, int length) - { - Array.Copy(bytes, offset, Buffer, Position, length); - Position += length; - if (Position > Length) Length = Position; - } - - public void Write(byte[] bytes, int length) - { - Array.Copy(bytes, 0, Buffer, Position, length); - Position += length; - if (Position > Length) Length = Position; - } - - public void WritePacked(int value) - { - WritePacked((uint)value); - } - - public void WritePacked(uint value) - { - do - { - var b = (byte)(value & 0xFF); - if (value >= 0x80) b |= 0x80; - - Write(b); - value >>= 7; - } while (value > 0); - } - - public void Write(MessageWriter msg, bool includeHeader) - { - var offset = 0; - if (!includeHeader) - switch (msg.SendOption) - { - case MessageType.Unreliable: - offset = 1; - break; - case MessageType.Reliable: - offset = 3; - break; - } - - Write(msg.Buffer, offset, msg.Length - offset); - } - - public void Write(IPAddress value) - { - Write(value.GetAddressBytes()); - } - - #endregion -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/NetworkConnection.cs b/src/NextFast.Hazel-New/Next.Hazel/NetworkConnection.cs deleted file mode 100644 index b1ce147..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/NetworkConnection.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using System.Threading.Tasks; - -namespace Next.Hazel; - -public enum HazelInternalErrors -{ - SocketExceptionSend, - SocketExceptionReceive, - ReceivedZeroBytes, - PingsWithoutResponse, - ReliablePacketWithoutResponse, - ConnectionDisconnected -} - -/// -/// Abstract base class for a to a remote end point via a network protocol like TCP or UDP. -/// -/// -public abstract class NetworkConnection : Connection -{ - /// - /// An event that gives us a chance to send well-formed disconnect messages to clients when an internal disconnect - /// happens. - /// - public Func OnInternalDisconnect; - - public abstract float AveragePingMs { get; } - - public long GetIP4Address() - { - if (IPMode == IPMode.IPv4) - { -#pragma warning disable 618 - return EndPoint.Address.Address; -#pragma warning restore 618 - } - - var bytes = EndPoint.Address.GetAddressBytes(); - return BitConverter.ToInt64(bytes, bytes.Length - 8); - } - - /// - /// Sends a disconnect message to the end point. - /// - protected abstract ValueTask SendDisconnect(MessageWriter writer); - - /// - /// Called when the socket has been disconnected at the remote host. - /// - protected async ValueTask DisconnectRemote(string reason, MessageReader reader) - { - if (await SendDisconnect(null)) - try - { - await InvokeDisconnected(reason, reader); - } - catch - { - // ignored - } - - Dispose(); - } - - /// - /// Called when socket is disconnected internally - /// - internal async ValueTask DisconnectInternal(HazelInternalErrors error, string reason) - { - var handler = OnInternalDisconnect; - if (handler != null) - { - var messageToRemote = handler(error); - if (messageToRemote != null) - try - { - await Disconnect(reason, messageToRemote); - } - finally - { - messageToRemote.Recycle(); - } - else - await Disconnect(reason); - } - else - { - await Disconnect(reason); - } - } - - /// - /// Called when the socket has been disconnected locally. - /// - public override async ValueTask Disconnect(string reason, MessageWriter writer = null) - { - if (await SendDisconnect(writer)) - try - { - await InvokeDisconnected(reason, null); - } - catch - { - // ignored - } - - Dispose(); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/NetworkConnectionListener.cs b/src/NextFast.Hazel-New/Next.Hazel/NetworkConnectionListener.cs deleted file mode 100644 index 7473a92..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/NetworkConnectionListener.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Net; - -namespace Next.Hazel; - -/// -/// Abstract base class for a for network based connections. -/// -/// -public abstract class NetworkConnectionListener : ConnectionListener -{ - /// - /// The local end point the listener is listening for new clients on. - /// - public IPEndPoint EndPoint { get; protected set; } - - /// - /// The IPMode the listener is listening for new clients on. - /// - public IPMode IPMode { get; protected set; } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/NewConnectionEventArgs.cs b/src/NextFast.Hazel-New/Next.Hazel/NewConnectionEventArgs.cs deleted file mode 100644 index b447a7f..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/NewConnectionEventArgs.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Next.Hazel.Abstractions; - -namespace Next.Hazel; - -public struct NewConnectionEventArgs -{ - /// - /// The data received from the client in the handshake. - /// This data is yours. Remember to recycle it. - /// - public readonly IMessageReader HandshakeData; - - /// - /// The to the new client. - /// - public readonly Connection Connection; - - public NewConnectionEventArgs(IMessageReader handshakeData, Connection connection) - { - HandshakeData = handshakeData; - Connection = connection; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Next.Hazel.csproj b/src/NextFast.Hazel-New/Next.Hazel/Next.Hazel.csproj deleted file mode 100644 index b0e40ff..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Next.Hazel.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - - true - HAZEL_BAG - Next.Hazel - Next.Hazel - true - NextFast.Hazel - - - - - <_Parameter1>Hazel.UnitTests - - - - - - - - - - - - - - - - diff --git a/src/NextFast.Hazel-New/Next.Hazel/ObjectPoolCustom.cs b/src/NextFast.Hazel-New/Next.Hazel/ObjectPoolCustom.cs deleted file mode 100644 index b332b0c..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/ObjectPoolCustom.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Threading; - -namespace Next.Hazel; - -/// -/// A fairly simple object pool for items that will be created a lot. -/// -/// The type that is pooled. -/// -public sealed class ObjectPoolCustom where T : IRecyclable -{ - private int numberCreated; - public int NumberCreated => numberCreated; - - public int NumberInUse => inuse.Count; - public int NumberNotInUse => pool.Count; - public int Size => NumberInUse + NumberNotInUse; - -#if HAZEL_BAG - private readonly ConcurrentBag pool = new(); -#else - private readonly List pool = new List(); -#endif - - // Unavailable objects - private readonly ConcurrentDictionary inuse = new(); - - /// - /// The generator for creating new objects. - /// - /// - private readonly Func objectFactory; - - /// - /// Internal constructor for our ObjectPool. - /// - internal ObjectPoolCustom(Func objectFactory) - { - this.objectFactory = objectFactory; - } - - /// - /// Returns a pooled object of type T, if none are available another is created. - /// - /// An instance of T. - internal T GetObject() - { -#if HAZEL_BAG - if (!pool.TryTake(out var item)) - { - Interlocked.Increment(ref numberCreated); - item = objectFactory.Invoke(); - } -#else - T item; - lock (this.pool) - { - if (this.pool.Count > 0) - { - var idx = this.pool.Count - 1; - item = this.pool[idx]; - this.pool.RemoveAt(idx); - } - else - { - Interlocked.Increment(ref numberCreated); - item = objectFactory.Invoke(); - } - } -#endif - - if (!inuse.TryAdd(item, true)) throw new Exception("Duplicate pull " + typeof(T).Name); - - return item; - } - - /// - /// Returns an object to the pool. - /// - /// The item to return. - internal void PutObject(T item) - { - if (inuse.TryRemove(item, out var b)) - { -#if HAZEL_BAG - pool.Add(item); -#else - lock (this.pool) - { - pool.Add(item); - } -#endif - } - else - { -#if DEBUG - throw new Exception("Duplicate add " + typeof(T).Name); -#endif - } - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/UPnP/ILogger.cs b/src/NextFast.Hazel-New/Next.Hazel/UPnP/ILogger.cs deleted file mode 100644 index cf49eac..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/UPnP/ILogger.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; - -namespace Next.Hazel.UPnP; - -public interface ILogger -{ - void WriteVerbose(string msg); - void WriteError(string msg); - void WriteInfo(string msg); -} - -public class NullLogger : ILogger -{ - public static readonly NullLogger Instance = new(); - - public void WriteVerbose(string msg) - { - } - - public void WriteError(string msg) - { - } - - public void WriteInfo(string msg) - { - } -} - -public class ConsoleLogger : ILogger -{ - private readonly bool verbose; - - public ConsoleLogger(bool verbose) - { - this.verbose = verbose; - } - - public void WriteVerbose(string msg) - { - if (verbose) Console.WriteLine($"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff zzz} [VRB] {msg}"); - } - - public void WriteError(string msg) - { - Console.WriteLine($"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff zzz} [ERR] {msg}"); - } - - public void WriteInfo(string msg) - { - Console.WriteLine($"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff zzz} [INF] {msg}"); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/UPnP/NetUtility.cs b/src/NextFast.Hazel-New/Next.Hazel/UPnP/NetUtility.cs deleted file mode 100644 index f26ce2e..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/UPnP/NetUtility.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.Net; -using System.Net.NetworkInformation; -using System.Net.Sockets; - -namespace Next.Hazel.UPnP; - -internal class NetUtility -{ - private static NetworkInterface GetNetworkInterface() - { - var computerProperties = IPGlobalProperties.GetIPGlobalProperties(); - if (computerProperties == null) - return null; - - var nics = NetworkInterface.GetAllNetworkInterfaces(); - if (nics == null || nics.Length < 1) - return null; - - NetworkInterface best = null; - foreach (var adapter in nics) - { - if (adapter.NetworkInterfaceType == NetworkInterfaceType.Loopback || - adapter.NetworkInterfaceType == NetworkInterfaceType.Unknown) - continue; - if (!adapter.Supports(NetworkInterfaceComponent.IPv4)) - continue; - if (best == null) - best = adapter; - if (adapter.OperationalStatus != OperationalStatus.Up) - continue; - - // make sure this adapter has any ipv4 addresses - var properties = adapter.GetIPProperties(); - foreach (var unicastAddress in properties.UnicastAddresses) - if (unicastAddress != null && unicastAddress.Address != null && - unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork) - // Yes it does, return this network interface. - return adapter; - } - - return best; - } - - /// - /// Gets my local IPv4 address (not necessarily external) and subnet mask - /// - public static IPAddress GetMyAddress(out IPAddress mask) - { - var ni = GetNetworkInterface(); - if (ni == null) - { - mask = null; - return null; - } - - var properties = ni.GetIPProperties(); - foreach (var unicastAddress in properties.UnicastAddresses) - if (unicastAddress != null && unicastAddress.Address != null && - unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork) - { - mask = unicastAddress.IPv4Mask; - return unicastAddress.Address; - } - - mask = null; - return null; - } - - public static IPAddress GetBroadcastAddress() - { - var ni = GetNetworkInterface(); - if (ni == null) - return null; - - var properties = ni.GetIPProperties(); - foreach (var unicastAddress in properties.UnicastAddresses) - if (unicastAddress != null && unicastAddress.Address != null && - unicastAddress.Address.AddressFamily == AddressFamily.InterNetwork) - { - var mask = unicastAddress.IPv4Mask; - var ipAdressBytes = unicastAddress.Address.GetAddressBytes(); - var subnetMaskBytes = mask.GetAddressBytes(); - - if (ipAdressBytes.Length != subnetMaskBytes.Length) - throw new ArgumentException("Lengths of IP address and subnet mask do not match."); - - var broadcastAddress = new byte[ipAdressBytes.Length]; - for (var i = 0; i < broadcastAddress.Length; i++) - broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255)); - return new IPAddress(broadcastAddress); - } - - return IPAddress.Broadcast; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/UPnP/UPnPHelper.cs b/src/NextFast.Hazel-New/Next.Hazel/UPnP/UPnPHelper.cs deleted file mode 100644 index b101148..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/UPnP/UPnPHelper.cs +++ /dev/null @@ -1,352 +0,0 @@ -using System; -using System.Net; -using System.Net.Http; -using System.Net.Sockets; -using System.Text; -using System.Threading; -using System.Xml; - -namespace Next.Hazel.UPnP; - -/// -/// Status of the UPnP capabilities -/// -public enum UPnPStatus -{ - /// - /// Still discovering UPnP capabilities - /// - Discovering, - - /// - /// UPnP is not available - /// - NotAvailable, - - /// - /// UPnP is available and ready to use - /// - Available -} - -public class UPnPHelper : IDisposable -{ - private const int DiscoveryTimeOutMs = 1000; - private readonly byte[] buffer; - - private readonly ManualResetEvent discoveryComplete = new(false); - - private readonly ILogger logger; - private readonly Socket socket; - - private DateTime discoveryResponseDeadline; - - private EndPoint ep; - private string serviceName = ""; - - private string serviceUrl; - - public UPnPHelper(ILogger logger) - { - this.logger = logger; - - socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - socket.EnableBroadcast = true; - socket.MulticastLoopback = false; - - socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1); - socket.Bind(new IPEndPoint(IPAddress.Any, 0)); - - ep = new IPEndPoint(IPAddress.Any, 1900); - buffer = new byte[ushort.MaxValue]; - - ListenForUPnP(); - - Discover(); - } - - /// - /// Status of the UPnP capabilities of this NetPeer - /// - public UPnPStatus Status { get; private set; } - - public void Dispose() - { - discoveryComplete.Dispose(); - try - { - socket.Shutdown(SocketShutdown.Both); - } - catch - { - // ignored - } - - socket.Dispose(); - } - - private void ListenForUPnP() - { - try - { - socket.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref ep, HandleMessage, null); - } - catch (Exception e) - { - logger.WriteInfo("Exception listening for UPnP: " + e.Message); - } - } - - private void HandleMessage(IAsyncResult ar) - { - int len; - try - { - len = socket.EndReceiveFrom(ar, ref ep); - } - catch - { - return; - } - - var resp = Encoding.UTF8.GetString(buffer, 0, len); - if (resp.Contains("upnp:rootdevice") || resp.Contains("UPnP/1.0")) - { - var locationStart = resp.IndexOf("location:", StringComparison.OrdinalIgnoreCase); - if (locationStart >= 0) - { - locationStart += 10; - var locationEnd = resp.IndexOf('\r', locationStart); - - resp = resp.Substring(locationStart, locationEnd - locationStart); - if (!ExtractServiceUrl(resp)) ListenForUPnP(); - } - else - { - ListenForUPnP(); - } - } - else - { - ListenForUPnP(); - } - } - - internal void Discover() - { - var str = - "M-SEARCH * HTTP/1.1\r\n" + - "HOST: 239.255.255.250:1900\r\n" + - "ST:upnp:rootdevice\r\n" + - "MAN:\"ssdp:discover\"\r\n" + - "MX:3\r\n\r\n"; - - discoveryResponseDeadline = DateTime.UtcNow.AddSeconds(6); - Status = UPnPStatus.Discovering; - - var bytes = Encoding.UTF8.GetBytes(str); - - logger.WriteInfo("Attempting UPnP discovery"); - - socket.SendTo(bytes, new IPEndPoint(NetUtility.GetBroadcastAddress(), 1900)); - } - - internal bool ExtractServiceUrl(string resp) - { - try - { - var desc = new XmlDocument(); - using var client = new HttpClient(); - using var response = client.GetStreamAsync(resp).Result; - desc.Load(response); - - var nsMgr = new XmlNamespaceManager(desc.NameTable); - nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0"); - var typeNode = desc.SelectSingleNode("//tns:device/tns:deviceType/text()", nsMgr); - if (typeNode?.Value == null) - return false; - - if (!typeNode.Value.Contains("InternetGatewayDevice")) - return false; - - serviceName = "WANIPConnection"; - var node = desc.SelectSingleNode( - "//tns:service[tns:serviceType=\"urn:schemas-upnp-org:service:" + serviceName + - ":1\"]/tns:controlURL/text()", nsMgr); - if (node == null) - { - //try another service name - serviceName = "WANPPPConnection"; - node = desc.SelectSingleNode( - "//tns:service[tns:serviceType=\"urn:schemas-upnp-org:service:" + serviceName + - ":1\"]/tns:controlURL/text()", nsMgr); - if (node == null) - return false; - } - - serviceUrl = CombineUrls(resp, node.Value); - logger.WriteInfo("UPnP service ready"); - Status = UPnPStatus.Available; - discoveryComplete.Set(); - return true; - } - catch (Exception e) - { - logger.WriteError("Exception while parsing UPnP Service URL: " + e.Message); - return false; - } - } - - private static string CombineUrls(string gatewayURL, string subURL) - { - // Is Control URL an absolute URL? - if (subURL.Contains("http:") || subURL.Contains(".")) - return subURL; - - gatewayURL = gatewayURL.Replace("http://", ""); // strip any protocol - var n = gatewayURL.IndexOf("/", StringComparison.Ordinal); - if (n >= 0) gatewayURL = gatewayURL[..n]; // Use first portion of URL - - return "http://" + gatewayURL + subURL; - } - - private bool CheckAvailability() - { - switch (Status) - { - case UPnPStatus.NotAvailable: - break; - case UPnPStatus.Available: - return true; - case UPnPStatus.Discovering: - while (!discoveryComplete.WaitOne(DiscoveryTimeOutMs)) - if (DateTime.UtcNow > discoveryResponseDeadline) - { - Status = UPnPStatus.NotAvailable; - return false; - } - - return true; - } - - return false; - } - - /// - /// Add a forwarding rule to the router using UPnP - /// - /// The external, WAN facing, port - /// A description for the port forwarding rule - /// The port on the client machine to send traffic to - /// The lease duration on the port forwarding rule, in seconds. 0 for indefinite. - public bool ForwardPort(int externalPort, string description, int internalPort = 0, int durationSeconds = 0) - { - if (!CheckAvailability()) - return false; - - if (internalPort == 0) - internalPort = externalPort; - - try - { - var client = NetUtility.GetMyAddress(out _); - if (client == null) - return false; - - SOAPRequest(serviceUrl, - $"" + - "" + - $"{externalPort}" + - "UDP" + - $"{internalPort}" + - $"{client}" + - "1" + - $"{description}" + - $"{durationSeconds}" + - "", - "AddPortMapping"); - - logger.WriteInfo("Sent UPnP port forward request."); - return true; - } - catch (Exception ex) - { - logger.WriteError("UPnP port forward failed: " + ex.Message); - return false; - } - } - - /// - /// Delete a forwarding rule from the router using UPnP - /// - /// The external, 'internet facing', port - public bool DeleteForwardingRule(int externalPort) - { - if (!CheckAvailability()) - return false; - - try - { - SOAPRequest(serviceUrl, - $"" + - "" + - $"{externalPort}" + - "UDP" + - "", "DeletePortMapping"); - return true; - } - catch (Exception) - { - // m_peer.LogWarning("UPnP delete forwarding rule failed: " + ex.Message); - return false; - } - } - - /// - /// Retrieve the extern ip using UPnP - /// - public IPAddress GetExternalIP() - { - if (!CheckAvailability()) - return null; - try - { - var xdoc = SOAPRequest(serviceUrl, "" + - "", "GetExternalIPAddress"); - var nsMgr = new XmlNamespaceManager(xdoc.NameTable); - nsMgr.AddNamespace("tns", "urn:schemas-upnp-org:device-1-0"); - var IP = xdoc.SelectSingleNode("//NewExternalIPAddress/text()", nsMgr).Value; - return IPAddress.Parse(IP); - } - catch (Exception) - { - // m_peer.LogWarning("Failed to get external IP: " + ex.Message); - return null; - } - } - - private XmlDocument SOAPRequest(string url, string soap, string function) - { - var req = - "" + - "" + - $"{soap}" + - ""; - - var request = new HttpRequestMessage(HttpMethod.Post, url) - { - Content = new StringContent(req, Encoding.UTF8, "text/xml") - }; - request.Headers.Add("SOAPACTION", $"\"urn:schemas-upnp-org:service:{serviceName}:1#{function}\""); - - using var client = new HttpClient(); - - using var response = client.SendAsync(request).Result; - - var xmlDoc = new XmlDocument(); - xmlDoc.Load(response.Content.ReadAsStream()); - - return xmlDoc; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Udp/SendOptionInternal.cs b/src/NextFast.Hazel-New/Next.Hazel/Udp/SendOptionInternal.cs deleted file mode 100644 index c809144..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Udp/SendOptionInternal.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace Next.Hazel.Udp; - -/// -/// Extra internal states for SendOption enumeration when using UDP. -/// -public enum UdpSendOption : byte -{ - /// - /// Hello message for initiating communication. - /// - Hello = 8, - - /// - /// A single byte of continued existence - /// - Ping = 12, - - /// - /// Message for discontinuing communication. - /// - Disconnect = 9, - - /// - /// Message acknowledging the receipt of a message. - /// - Acknowledgement = 10, - - /// - /// Message that is part of a larger, fragmented message. - /// - Fragment = 11 -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpBroadcastListener.cs b/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpBroadcastListener.cs deleted file mode 100644 index 9214db3..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpBroadcastListener.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Net; -using System.Net.Sockets; -using System.Text; - -namespace Next.Hazel.Udp; - -public class BroadcastPacket -{ - public string Data; - public DateTime ReceiveTime; - public IPEndPoint Sender; - - public BroadcastPacket(string data, IPEndPoint sender) - { - Data = data; - Sender = sender; - ReceiveTime = DateTime.Now; - } - - public string GetAddress() - { - return Sender.Address.ToString(); - } -} - -public class UdpBroadcastListener : IDisposable -{ - private readonly byte[] buffer = new byte[1024]; - private readonly Action logger; - - private readonly List packets = new(); - private Socket socket; - - /// - public UdpBroadcastListener(int port, Action logger = null) - { - this.logger = logger; - socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - socket.EnableBroadcast = true; - socket.MulticastLoopback = false; - EndPoint endpoint1 = new IPEndPoint(IPAddress.Any, port); - socket.Bind(endpoint1); - } - - public bool Running { get; private set; } - - /// - public void Dispose() - { - if (socket == null) return; - try - { - socket.Shutdown(SocketShutdown.Both); - socket.Close(); - socket.Dispose(); - } - catch (Exception e) - { - logger.Invoke(e.ToString()); - } - - socket = null; - } - - /// - public void StartListen() - { - if (Running) return; - Running = true; - - try - { - EndPoint endpt = new IPEndPoint(IPAddress.Any, 0); - socket.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref endpt, HandleData, null); - } - catch (NullReferenceException) - { - } - catch (Exception e) - { - logger?.Invoke("BroadcastListener: " + e); - Dispose(); - } - } - - private void HandleData(IAsyncResult result) - { - Running = false; - - int numBytes; - EndPoint endpt = new IPEndPoint(IPAddress.Any, 0); - try - { - numBytes = socket.EndReceiveFrom(result, ref endpt); - } - catch (NullReferenceException) - { - // Already disposed - return; - } - catch (Exception e) - { - logger?.Invoke("BroadcastListener: " + e); - Dispose(); - return; - } - - if (numBytes < 3 - || buffer[0] != 4 || buffer[1] != 2) - { - StartListen(); - return; - } - - var ipEnd = (IPEndPoint)endpt; - var data = Encoding.UTF8.GetString(buffer, 2, numBytes - 2); - var dataHash = data.GetHashCode(); - - lock (packets) - { - for (var i = 0; i < packets.Count; ++i) - { - var pkt = packets[i]; - if (pkt == null || pkt.Data == null) - { - packets.RemoveAt(i); - i--; - continue; - } - - if (pkt.Data.GetHashCode() != dataHash - || !pkt.Sender.Equals(ipEnd)) continue; - packets[i].ReceiveTime = DateTime.Now; - break; - } - - packets.Add(new BroadcastPacket(data, ipEnd)); - } - - StartListen(); - } - - /// - public BroadcastPacket[] GetPackets() - { - lock (packets) - { - var output = packets.ToArray(); - packets.Clear(); - return output; - } - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpBroadcaster.cs b/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpBroadcaster.cs deleted file mode 100644 index 891d456..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpBroadcaster.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Text; - -namespace Next.Hazel.Udp; - -/// -public class UdpBroadcaster : IDisposable -{ - private readonly EndPoint endpoint; - private readonly Action logger; - private byte[] data; - private Socket socket; - - /// - public UdpBroadcaster(int port, Action logger = null) - { - this.logger = logger; - socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); - socket.EnableBroadcast = true; - socket.MulticastLoopback = false; - endpoint = new IPEndPoint(IPAddress.Broadcast, port); - } - - /// - public void Dispose() - { - if (socket == null) return; - try - { - socket.Shutdown(SocketShutdown.Both); - socket.Close(); - socket.Dispose(); - } - catch - { - // ignored - } - - socket = null; - } - - /// - public void SetData(string dataValue) - { - var len = Encoding.UTF8.GetByteCount(dataValue); - data = new byte[len + 2]; - data[0] = 4; - data[1] = 2; - - Encoding.UTF8.GetBytes(dataValue, 0, dataValue.Length, data, 2); - } - - /// - public void Broadcast() - { - if (data == null) return; - - try - { - socket.BeginSendTo(data, 0, data.Length, SocketFlags.None, endpoint, FinishSendTo, null); - } - catch (Exception e) - { - logger?.Invoke("BroadcastListener: " + e); - } - } - - private void FinishSendTo(IAsyncResult evt) - { - try - { - socket.EndSendTo(evt); - } - catch (Exception e) - { - logger?.Invoke("BroadcastListener: " + e); - } - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpClientConnection.cs b/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpClientConnection.cs deleted file mode 100644 index 951b2e1..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpClientConnection.cs +++ /dev/null @@ -1,244 +0,0 @@ -using System; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.ObjectPool; -using Next.Hazel.Abstractions; - -namespace Next.Hazel.Udp; - -/// -/// Represents a client's connection to a server that uses the UDP protocol. -/// -/// -public class UdpClientConnection : UdpConnection -{ - /// - /// Reset event that is triggered when the connection is marked Connected. - /// - private readonly SemaphoreSlim _connectWaitLock; - - /// - /// The socket we're connected via. - /// - private readonly UdpClient _socket; - - private readonly Timer reliablePacketTimer; - - private Task _listenTask; - - /// - /// Creates a new UdpClientConnection. - /// - public UdpClientConnection(IPEndPoint remoteEndPoint, ObjectPool readerPool, - IPMode ipMode = IPMode.IPv4) : base(null, readerPool) - { - EndPoint = remoteEndPoint; - IPMode = ipMode; - - _socket = new UdpClient - { - DontFragment = false - }; - - reliablePacketTimer = new Timer(ManageReliablePacketsInternal, null, 100, Timeout.Infinite); - _connectWaitLock = new SemaphoreSlim(0, 1); - - InitializeKeepAliveTimer(); - } - - ~UdpClientConnection() - { - Dispose(false); - } - - private async void ManageReliablePacketsInternal(object state) - { - try - { - await ManageReliablePackets(); - reliablePacketTimer.Change(100, Timeout.Infinite); - } - catch - { - // ignored - } - } - - protected virtual async ValueTask ResendPacketsIfNeeded() - { - await ManageReliablePackets(); - } - - /// - protected override ValueTask WriteBytesToConnection(byte[] bytes, int length) - { - return WriteBytesToConnectionReal(bytes, length); - } - - private async ValueTask WriteBytesToConnectionReal(byte[] bytes, int length) - { - try - { - await _socket.SendAsync(bytes, length); - } - catch (NullReferenceException) - { - } - catch (ObjectDisposedException) - { - // Already disposed and disconnected... - } - catch (SocketException ex) - { - await DisconnectInternal(HazelInternalErrors.SocketExceptionSend, - "Could not send data as a SocketException occurred: " + ex.Message); - } - } - - /// - public override async ValueTask ConnectAsync(byte[] bytes = null, int timeout = 5000) - { - State = ConnectionState.Connecting; - - try - { - _socket.Connect(EndPoint); - } - catch (SocketException e) - { - State = ConnectionState.NotConnected; - throw new HazelException("A SocketException occurred while binding to the port.", e); - } - - RestartConnection(); - - try - { - _listenTask = Task.Factory.StartNew(ListenAsync, TaskCreationOptions.LongRunning); - } - catch (ObjectDisposedException) - { - // If the socket's been disposed then we can just end there but make sure we're in NotConnected state. - // If we end up here I'm really lost... - State = ConnectionState.NotConnected; - return; - } - catch (SocketException e) - { - Dispose(); - throw new HazelException("A SocketException occurred while initiating a receive operation.", e); - } - - // Write bytes to the server to tell it hi (and to punch a hole in our NAT, if present) - // When acknowledged set the state to connected - await SendHello(bytes, () => - { - State = ConnectionState.Connected; - InitializeKeepAliveTimer(); - }); - - await _connectWaitLock.WaitAsync(TimeSpan.FromSeconds(10)); - } - - protected virtual void RestartConnection() - { - } - - private async Task ListenAsync() - { - // Start packet handler. - await StartAsync(); - - // Listen. - while (State != ConnectionState.NotConnected) - { - UdpReceiveResult data; - - try - { - data = await _socket.ReceiveAsync(); - } - catch (SocketException e) - { - await DisconnectInternal(HazelInternalErrors.SocketExceptionReceive, - "Socket exception while reading data: " + e.Message); - return; - } - catch (Exception) - { - return; - } - - if (data.Buffer.Length == 0) - { - await DisconnectInternal(HazelInternalErrors.ReceivedZeroBytes, "Received 0 bytes"); - return; - } - - // Write to client. - await Pipeline.Writer.WriteAsync(data.Buffer); - } - } - - protected override void SetState(ConnectionState state) - { - if (state == ConnectionState.Connected) _connectWaitLock.Release(); - } - - /// - /// Sends a disconnect message to the end point. - /// You may include optional disconnect data. The SendOption must be unreliable. - /// - protected override async ValueTask SendDisconnect(MessageWriter data) - { - lock (this) - { - if (_state == ConnectionState.NotConnected) return false; - _state = ConnectionState.NotConnected; - } - - var bytes = EmptyDisconnectBytes; - if (data != null && data.Length > 0) - { - if (data.SendOption != MessageType.Unreliable) - throw new ArgumentException("Disconnect messages can only be unreliable."); - - bytes = data.ToByteArray(true); - bytes[0] = (byte)UdpSendOption.Disconnect; - } - - try - { - await _socket.SendAsync(bytes, bytes.Length, EndPoint); - } - catch - { - // ignored - } - - return true; - } - - /// - protected override void Dispose(bool disposing) - { - State = ConnectionState.NotConnected; - - try - { - _socket.Close(); - _socket.Dispose(); - } - catch - { - // ignored - } - - reliablePacketTimer.Dispose(); - _connectWaitLock.Dispose(); - - base.Dispose(disposing); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnection.KeepAlive.cs b/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnection.KeepAlive.cs deleted file mode 100644 index 621ff7e..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnection.KeepAlive.cs +++ /dev/null @@ -1,158 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; - -namespace Next.Hazel.Udp; - -partial class UdpConnection -{ - internal ConcurrentDictionary activePingPackets = new(); - private int keepAliveInterval = 1000; - - /// - /// The timer creating keepalive pulses. - /// - private Timer keepAliveTimer; - - private volatile int pingsSinceAck; - - /// - /// The interval from data being received or transmitted to a keepalive packet being sent in milliseconds. - /// - /// - /// - /// Keepalive packets serve to close connections when an endpoint abruptly disconnects and to ensure than any - /// NAT devices do not close their translation for our argument. By ensuring there is regular contact the - /// connection can detect and prevent these issues. - /// - /// - /// The default value is 10 seconds, set to System.Threading.Timeout.Infinite to disable keepalive packets. - /// - /// - public int KeepAliveInterval - { - get => keepAliveInterval; - - set - { - keepAliveInterval = value; - ResetKeepAliveTimer(); - } - } - - public int MissingPingsUntilDisconnect { get; set; } = 6; - - /// - /// Starts the keepalive timer. - /// - protected void InitializeKeepAliveTimer() - { - keepAliveTimer = new Timer( - HandleKeepAlive, - null, - keepAliveInterval, - keepAliveInterval - ); - } - - private async void HandleKeepAlive(object state) - { - if (State != ConnectionState.Connected) return; - - if (pingsSinceAck >= MissingPingsUntilDisconnect) - { - DisposeKeepAliveTimer(); - await DisconnectInternal(HazelInternalErrors.PingsWithoutResponse, - $"Sent {pingsSinceAck} pings that remote has not responded to."); - return; - } - - try - { - Interlocked.Increment(ref pingsSinceAck); - await SendPing(); - } - catch - { - // ignored - } - } - - // Pings are special, quasi-reliable packets. - // We send them to trigger responses that validate our connection is alive - // An unacked ping should never be the sole cause of a disconnect. - // Rather, the responses will reset our pingsSinceAck, enough unacked - // pings should cause a disconnect. - private async ValueTask SendPing() - { - var id = (ushort)Interlocked.Increment(ref lastIDAllocated); - - var bytes = new byte[3]; - bytes[0] = (byte)UdpSendOption.Ping; - bytes[1] = (byte)(id >> 8); - bytes[2] = (byte)id; - - PingPacket pkt; - if (!activePingPackets.TryGetValue(id, out pkt)) - { - pkt = PingPacket.GetObject(); - if (!activePingPackets.TryAdd(id, pkt)) throw new Exception("This shouldn't be possible"); - } - - pkt.Stopwatch.Restart(); - - await WriteBytesToConnection(bytes, bytes.Length); - - Statistics.LogReliableSend(0, bytes.Length); - } - - /// - /// Resets the keepalive timer to zero. - /// - private void ResetKeepAliveTimer() - { - try - { - keepAliveTimer.Change(keepAliveInterval, keepAliveInterval); - } - catch - { - // ignored - } - } - - /// - /// Disposes of the keep alive timer. - /// - private void DisposeKeepAliveTimer() - { - if (keepAliveTimer != null) keepAliveTimer.Dispose(); - - foreach (var kvp in activePingPackets) - if (activePingPackets.TryRemove(kvp.Key, out var pkt)) - pkt.Recycle(); - } - - /// - /// Class to hold packet data - /// - public class PingPacket : IRecyclable - { - private static readonly ObjectPoolCustom PacketPool = new(() => new PingPacket()); - - public readonly Stopwatch Stopwatch = new(); - - public void Recycle() - { - Stopwatch.Stop(); - PacketPool.PutObject(this); - } - - internal static PingPacket GetObject() - { - return PacketPool.GetObject(); - } - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnection.Reliable.cs b/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnection.Reliable.cs deleted file mode 100644 index 9ff13fd..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnection.Reliable.cs +++ /dev/null @@ -1,473 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using Next.Hazel.Abstractions; - -namespace Next.Hazel.Udp; - -partial class UdpConnection -{ - private readonly object PingLock = new(); - - /// - /// Packet ids that have not been received, but are expected. - /// - private readonly HashSet reliableDataPacketsMissing = new(); - - /// - /// Returns the average ping to this endpoint. - /// - /// - /// This returns the average ping for a one-way trip as calculated from the reliable packets that have been sent - /// and acknowledged by the endpoint. - /// - private float _pingMs = 500; - - /// - /// The maximum times a message should be resent before marking the endpoint as disconnected. - /// - /// - /// Reliable packets will be resent at an interval defined in for the number of times - /// specified here. Once a packet has been retransmitted this number of times and has not been acknowledged the - /// connection will be marked as disconnected and the Disconnected event - /// will be invoked. - /// - public volatile int DisconnectTimeout = 7500; - - /// - /// Holds the last ID allocated. - /// - private int lastIDAllocated; - - /// - /// The packets of data that have been transmitted reliably and not acknowledged. - /// - internal ConcurrentDictionary reliableDataPacketsSent = new(); - - /// - /// The packet id that was received last. - /// - protected volatile ushort reliableReceiveLast = ushort.MaxValue; - - /// - /// Max number of times to resend. 0 == no limit - /// - public volatile int ResendLimit = 0; - - /// - /// A compounding multiplier to back off resend timeout. - /// Applied to ping before first timeout when ResendTimeout == 0. - /// - public volatile float ResendPingMultiplier = 1.2f; - - /// - /// The starting timeout, in miliseconds, at which data will be resent. - /// - /// - /// - /// For reliable delivery data is resent at specified intervals unless an acknowledgement is received from the - /// receiving device. The ResendTimeout specifies the interval between the packets being resent, each time a packet - /// is resent the interval is increased for that packet until the duration exceeds the - /// value. - /// - /// - /// Setting this to its default of 0 will mean the timeout is 2 times the value of the average ping, usually - /// resulting in a more dynamic resend that responds to endpoints on slower or faster connections. - /// - /// - public volatile int ResendTimeout = 0; - - internal async ValueTask ManageReliablePackets() - { - var output = 0; - if (reliableDataPacketsSent.IsEmpty) return output; - foreach (var kvp in reliableDataPacketsSent) - { - var pkt = kvp.Value; - - try - { - output += await pkt.Resend(); - } - catch - { - // ignored - } - } - - return output; - } - - /// - /// Adds a 2 byte ID to the packet at offset and stores the packet reference for retransmission. - /// - /// The buffer to attach to. - /// The offset to attach at. - /// The callback to make once the packet has been acknowledged. - protected void AttachReliableID(byte[] buffer, int offset, Action ackCallback = null) - { - var id = (ushort)Interlocked.Increment(ref lastIDAllocated); - - buffer[offset] = (byte)(id >> 8); - buffer[offset + 1] = (byte)id; - - var packet = Packet.GetObject(); - lock (PingLock) - { - packet.Set( - id, - this, - buffer, - buffer.Length, - ResendTimeout > 0 ? ResendTimeout : (int)Math.Min(_pingMs * ResendPingMultiplier, 300), - ackCallback); - } - - if (!reliableDataPacketsSent.TryAdd(id, packet)) throw new Exception("That shouldn't be possible"); - } - - public static int ClampToInt(float value, int min, int max) - { - if (value < min) return min; - if (value > max) return max; - return (int)value; - } - - /// - /// Sends the bytes reliably and stores the send. - /// - /// - /// The byte array to write to. - /// The callback to make once the packet has been acknowledged. - private async ValueTask ReliableSend(byte sendOption, byte[] data, Action ackCallback = null) - { - //Inform keepalive not to send for a while - ResetKeepAliveTimer(); - - var bytes = new byte[data.Length + 3]; - - //Add message type - bytes[0] = sendOption; - - //Add reliable ID - AttachReliableID(bytes, 1, ackCallback); - - //Copy data into new array - Buffer.BlockCopy(data, 0, bytes, bytes.Length - data.Length, data.Length); - - //Write to connection - await WriteBytesToConnection(bytes, bytes.Length); - - Statistics.LogReliableSend(data.Length, bytes.Length); - } - - /// - /// Handles a reliable message being received and invokes the data event. - /// - /// The buffer received. - /// - private async ValueTask ReliableMessageReceive(MessageReader message, int bytesReceived) - { - if (await ProcessReliableReceive(message.Buffer, 1)) - await InvokeDataReceived(MessageType.Reliable, message, 3, bytesReceived); - - Statistics.LogReliableReceive(message.Length - 3, message.Length); - } - - /// - /// Handles receives from reliable packets. - /// - /// The buffer containing the data. - /// The offset of the reliable header. - /// Whether the packet was a new packet or not. - private async ValueTask ProcessReliableReceive(ReadOnlyMemory bytes, int offset) - { - var b1 = bytes.Span[offset]; - var b2 = bytes.Span[offset + 1]; - - //Get the ID form the packet - var id = (ushort)((b1 << 8) + b2); - - /* - * It gets a little complicated here (note the fact I'm actually using a multiline comment for once...) - * - * In a simple world if our data is greater than the last reliable packet received (reliableReceiveLast) - * then it is guaranteed to be a new packet, if it's not we can see if we are missing that packet (lookup - * in reliableDataPacketsMissing). - * - * --------rrl############# (1) - * - * (where --- are packets received already and #### are packets that will be counted as new) - * - * Unfortunately if id becomes greater than 65535 it will loop back to zero so we will add a pointer that - * specifies any packets with an id behind it are also new (overwritePointer). - * - * ####op----------rrl##### (2) - * - * ------rll#########op---- (3) - * - * Anything behind than the reliableReceiveLast pointer (but greater than the overwritePointer is either a - * missing packet or something we've already received so when we change the pointers we need to make sure - * we keep note of what hasn't been received yet (reliableDataPacketsMissing). - * - * So... - */ - - var result = true; - - lock (reliableDataPacketsMissing) - { - //Calculate overwritePointer - var overwritePointer = (ushort)(reliableReceiveLast - 32768); - - //Calculate if it is a new packet by examining if it is within the range - bool isNew; - if (overwritePointer < reliableReceiveLast) - isNew = id > reliableReceiveLast || id <= overwritePointer; //Figure (2) - else - isNew = id > reliableReceiveLast && id <= overwritePointer; //Figure (3) - - //If it's new or we've not received anything yet - if (isNew) - { - // Mark items between the most recent receive and the id received as missing - if (id > reliableReceiveLast) - { - for (var i = (ushort)(reliableReceiveLast + 1); i < id; i++) reliableDataPacketsMissing.Add(i); - } - else - { - var cnt = ushort.MaxValue - reliableReceiveLast + id; - for (ushort i = 1; i <= cnt; ++i) reliableDataPacketsMissing.Add((ushort)(i + reliableReceiveLast)); - } - - //Update the most recently received - reliableReceiveLast = id; - } - - //Else it could be a missing packet - else - { - //See if we're missing it, else this packet is a duplicate as so we return false - if (!reliableDataPacketsMissing.Remove(id)) result = false; - } - } - - // Send an acknowledgement - await SendAck(id); - - return result; - } - - /// - /// Handles acknowledgement packets to us. - /// - /// The buffer containing the data. - /// - private void AcknowledgementMessageReceive(byte[] bytes, int bytesReceived) - { - pingsSinceAck = 0; - - var id = (ushort)((bytes[1] << 8) + bytes[2]); - AcknowledgeMessageId(id); - - if (bytesReceived == 4) - { - var recentPackets = bytes[3]; - for (var i = 1; i <= 8; ++i) - { - if ((recentPackets & 1) != 0) AcknowledgeMessageId((ushort)(id - i)); - - recentPackets >>= 1; - } - } - - Statistics.LogReliableReceive(0, bytesReceived); - } - - private void AcknowledgeMessageId(ushort id) - { - // Dispose of timer and remove from dictionary - if (reliableDataPacketsSent.TryRemove(id, out var packet)) - { - float rt = packet.Stopwatch.ElapsedMilliseconds; - - packet.AckCallback?.Invoke(); - packet.Recycle(); - - lock (PingLock) - { - _pingMs = Math.Max(50, _pingMs * .7f + rt * .3f); - } - } - else if (activePingPackets.TryRemove(id, out var pingPkt)) - { - float rt = pingPkt.Stopwatch.ElapsedMilliseconds; - - pingPkt.Recycle(); - - lock (PingLock) - { - _pingMs = Math.Max(50, _pingMs * .7f + rt * .3f); - } - } - } - - /// - /// Sends an acknowledgement for a packet given its identification bytes. - /// - private async ValueTask SendAck(ushort id) - { - byte recentPackets = 0; - lock (reliableDataPacketsMissing) - { - for (var i = 1; i <= 8; ++i) - if (!reliableDataPacketsMissing.Contains((ushort)(id - i))) - recentPackets |= (byte)(1 << (i - 1)); - } - - var bytes = new[] - { - (byte)UdpSendOption.Acknowledgement, - (byte)(id >> 8), - (byte)(id >> 0), - recentPackets - }; - - try - { - await WriteBytesToConnection(bytes, bytes.Length); - } - catch (InvalidOperationException) - { - } - } - - private void DisposeReliablePackets() - { - foreach (var kvp in reliableDataPacketsSent) - if (reliableDataPacketsSent.TryRemove(kvp.Key, out var pkt)) - pkt.Recycle(); - } - - /// - /// Class to hold packet data - /// - public class Packet : IRecyclable - { - /// - /// Object pool for this event. - /// - public static readonly ObjectPoolCustom PacketPool = new(() => new Packet()); - - public Action AckCallback; - public volatile bool Acknowledged; - private UdpConnection Connection; - private byte[] Data; - - public ushort Id; - private int Length; - - public int NextTimeout; - - public int Retransmissions; - public Stopwatch Stopwatch = new(); - - private Packet() - { - } - - /// - /// Returns this object back to the object pool from whence it came. - /// - public void Recycle() - { - Acknowledged = true; - Connection = null; - - PacketPool.PutObject(this); - } - - /// - /// Returns an instance of this object from the pool. - /// - /// - internal static Packet GetObject() - { - return PacketPool.GetObject(); - } - - internal void Set(ushort id, UdpConnection connection, byte[] data, int length, int timeout, Action ackCallback) - { - Id = id; - Data = data; - Connection = connection; - Length = length; - - Acknowledged = false; - NextTimeout = timeout; - AckCallback = ackCallback; - Retransmissions = 0; - - Stopwatch.Restart(); - } - - // Packets resent - public async ValueTask Resend() - { - var connection = Connection; - if (!Acknowledged && connection != null) - { - var lifetime = Stopwatch.ElapsedMilliseconds; - if (lifetime >= connection.DisconnectTimeout) - { - if (connection.reliableDataPacketsSent.TryRemove(Id, out var self)) - { - await connection.DisconnectInternal(HazelInternalErrors.ReliablePacketWithoutResponse, - $"Reliable packet {self.Id} (size={Length}) was not ack'd after {lifetime}ms ({self.Retransmissions} resends)"); - - self.Recycle(); - } - - return 0; - } - - if (lifetime >= NextTimeout) - { - ++Retransmissions; - if (connection.ResendLimit != 0 - && Retransmissions > connection.ResendLimit) - { - if (connection.reliableDataPacketsSent.TryRemove(Id, out var self)) - { - await connection.DisconnectInternal(HazelInternalErrors.ReliablePacketWithoutResponse, - $"Reliable packet {self.Id} (size={Length}) was not ack'd after {self.Retransmissions} resends ({lifetime}ms)"); - - self.Recycle(); - } - - return 0; - } - - NextTimeout += (int)Math.Min(NextTimeout * connection.ResendPingMultiplier, 1000); - try - { - await connection.WriteBytesToConnection(Data, Length); - connection.Statistics.LogMessageResent(); - return 1; - } - catch (InvalidOperationException) - { - await connection.DisconnectInternal(HazelInternalErrors.ConnectionDisconnected, - "Could not resend data as connection is no longer connected"); - } - } - } - - return 0; - } - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnection.cs b/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnection.cs deleted file mode 100644 index 4f9b12b..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnection.cs +++ /dev/null @@ -1,316 +0,0 @@ -using System; -using System.Threading; -using System.Threading.Channels; -using System.Threading.Tasks; -using Microsoft.Extensions.ObjectPool; -using Next.Hazel.Abstractions; -using Serilog; - -namespace Next.Hazel.Udp; - -/// -/// Represents a connection that uses the UDP protocol. -/// -/// -public abstract partial class UdpConnection : NetworkConnection -{ - private const int SioUdpConnectionReset = -1744830452; - private static readonly ILogger Logger = Log.ForContext(); - - public static readonly byte[] EmptyDisconnectBytes = new[] { (byte)UdpSendOption.Disconnect }; - - private readonly ConnectionListener _listener; - protected readonly ObjectPool _readerPool; - private readonly CancellationTokenSource _stoppingCts; - private Task _executingTask; - - private bool _isDisposing; - private bool _isFirst = true; - - protected UdpConnection(ConnectionListener listener, ObjectPool readerPool) - { - _listener = listener; - _readerPool = readerPool; - _stoppingCts = new CancellationTokenSource(); - - Pipeline = Channel.CreateUnbounded(new UnboundedChannelOptions - { - SingleReader = true, - SingleWriter = true - }); - } - - public override float AveragePingMs => _pingMs; - - internal Channel Pipeline { get; } - - public Task StartAsync() - { - // Store the task we're executing - _executingTask = Task.Factory.StartNew(ReadAsync, TaskCreationOptions.LongRunning); - - // If the task is completed then return it, this will bubble cancellation and failure to the caller - if (_executingTask.IsCompleted) return _executingTask; - - // Otherwise it's running - return Task.CompletedTask; - } - - public void Stop() - { - // Stop called without start - if (_executingTask == null) return; - - // Signal cancellation to methods. - _stoppingCts.Cancel(); - - try - { - // Cancel reader. - Pipeline.Writer.Complete(); - } - catch (ChannelClosedException) - { - // Already done. - } - - // Remove references. - if (!_isDisposing) Dispose(true); - } - - private async Task ReadAsync() - { - var reader = new MessageReader(_readerPool); - - while (!_stoppingCts.IsCancellationRequested) - { - var result = await Pipeline.Reader.ReadAsync(_stoppingCts.Token); - - try - { - reader.Update(result); - - await HandleReceive(reader, reader.Length); - } - catch (Exception e) - { - Logger.Error(e, "Exception during ReadAsync"); - Dispose(true); - break; - } - } - } - - /// - /// Writes the given bytes to the connection. - /// - /// The bytes to write. - /// - protected abstract ValueTask WriteBytesToConnection(byte[] bytes, int length); - - /// - public override async ValueTask SendAsync(IMessageWriter msg) - { - if (_state != ConnectionState.Connected) - throw new InvalidOperationException( - "Could not send data as this Connection is not connected. Did you disconnect?"); - - var buffer = new byte[msg.Length]; - Buffer.BlockCopy(msg.Buffer, 0, buffer, 0, msg.Length); - - switch (msg.SendOption) - { - case MessageType.Reliable: - ResetKeepAliveTimer(); - - AttachReliableID(buffer, 1); - await WriteBytesToConnection(buffer, buffer.Length); - Statistics.LogReliableSend(buffer.Length - 3, buffer.Length); - break; - - default: - await WriteBytesToConnection(buffer, buffer.Length); - Statistics.LogUnreliableSend(buffer.Length - 1, buffer.Length); - break; - } - } - - /// - /// - /// - /// - /// Udp connections can currently send messages using and - /// . Fragmented messages are not currently supported and will default to - /// until implemented. - /// - /// - public override async ValueTask SendBytes(byte[] bytes, MessageType sendOption = MessageType.Unreliable) - { - //Add header information and send - await HandleSend(bytes, (byte)sendOption); - } - - /// - /// Handles the reliable/fragmented sending from this connection. - /// - /// The data being sent. - /// - /// The callback to invoke when this packet is acknowledged. - /// The bytes that should actually be sent. - protected async ValueTask HandleSend(byte[] data, byte sendOption, Action ackCallback = null) - { - switch (sendOption) - { - case (byte)UdpSendOption.Ping: - case (byte)MessageType.Reliable: - case (byte)UdpSendOption.Hello: - await ReliableSend(sendOption, data, ackCallback); - break; - - //Treat all else as unreliable - default: - await UnreliableSend(sendOption, data); - break; - } - } - - /// - /// Handles the receiving of data. - /// - /// The buffer containing the bytes received. - /// - internal virtual async ValueTask HandleReceive(MessageReader message, int bytesReceived) - { - // Check if the first message received is the hello packet. - if (_isFirst) - { - _isFirst = false; - - // Slice 4 bytes to get handshake data. - if (_listener != null) - { - using var handshake = message.Copy(4); - await _listener.InvokeNewConnection(handshake, this); - } - } - - switch (message.Buffer[0]) - { - //Handle reliable receives - case (byte)MessageType.Reliable: - await ReliableMessageReceive(message, bytesReceived); - break; - - //Handle acknowledgments - case (byte)UdpSendOption.Acknowledgement: - AcknowledgementMessageReceive(message.Buffer, bytesReceived); - break; - - //We need to acknowledge hello and ping messages but dont want to invoke any events! - case (byte)UdpSendOption.Ping: - case (byte)UdpSendOption.Hello: - await ProcessReliableReceive(message.Buffer, 1); - Statistics.LogHelloReceive(bytesReceived); - break; - - case (byte)UdpSendOption.Disconnect: - message.Offset = 1; - message.Position = 0; - await DisconnectRemote("The remote sent a disconnect request", message); - break; - - //Treat everything else as unreliable - default: - await InvokeDataReceived(MessageType.Unreliable, message, 1, bytesReceived); - Statistics.LogUnreliableReceive(bytesReceived - 1, bytesReceived); - break; - } - } - - /// - /// Sends bytes using the unreliable UDP protocol. - /// - /// The SendOption to attach. - /// The data. - private ValueTask UnreliableSend(byte sendOption, byte[] data) - { - return UnreliableSend(sendOption, data, 0, data.Length); - } - - /// - /// Sends bytes using the unreliable UDP protocol. - /// - /// The data. - /// The SendOption to attach. - /// - /// - private async ValueTask UnreliableSend(byte sendOption, byte[] data, int offset, int length) - { - var bytes = new byte[length + 1]; - - //Add message type - bytes[0] = sendOption; - - //Copy data into new array - Buffer.BlockCopy(data, offset, bytes, bytes.Length - length, length); - - //Write to connection - await WriteBytesToConnection(bytes, bytes.Length); - - Statistics.LogUnreliableSend(length, bytes.Length); - } - - /// - /// Helper method to invoke the data received event. - /// - /// The send option the message was received with. - /// The buffer received. - /// The offset of data in the buffer. - /// - private ValueTask InvokeDataReceived(MessageType sendOption, MessageReader buffer, int dataOffset, - int bytesReceived) - { - buffer.Offset = dataOffset; - buffer.Length = bytesReceived - dataOffset; - buffer.Position = 0; - - return InvokeDataReceived(buffer, sendOption); - } - - /// - /// Sends a hello packet to the remote endpoint. - /// - /// - /// The callback to invoke when the hello packet is acknowledged. - protected ValueTask SendHello(byte[] bytes, Action acknowledgeCallback) - { - //First byte of handshake is version indicator so add data after - byte[] actualBytes; - if (bytes == null) - { - actualBytes = new byte[1]; - } - else - { - actualBytes = new byte[bytes.Length + 1]; - Buffer.BlockCopy(bytes, 0, actualBytes, 1, bytes.Length); - } - - return HandleSend(actualBytes, (byte)UdpSendOption.Hello, acknowledgeCallback); - } - - /// - protected override void Dispose(bool disposing) - { - if (disposing) - { - _isDisposing = true; - - Stop(); - DisposeKeepAliveTimer(); - DisposeReliablePackets(); - } - - base.Dispose(disposing); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnectionListener.cs b/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnectionListener.cs deleted file mode 100644 index 5fd37cf..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnectionListener.cs +++ /dev/null @@ -1,257 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Extensions.ObjectPool; -using Serilog; - -namespace Next.Hazel.Udp; - -/// -/// Listens for new UDP connections and creates UdpConnections for them. -/// -/// -public class UdpConnectionListener : NetworkConnectionListener -{ - public delegate bool AcceptConnectionCheck(IPEndPoint endPoint, byte[] input, out byte[] response); - - private static readonly ILogger Logger = Log.ForContext(); - private readonly ConcurrentDictionary _allConnections; - private readonly UdpConnectionRateLimit _connectionRateLimit; - private readonly UdpPacketFilter _packetFilter; - protected readonly ObjectPool _readerPool; - private readonly Timer _reliablePacketTimer; - - private readonly UdpClient _socket; - private readonly CancellationTokenSource _stoppingCts; - private Task _executingTask; - - /// - /// A callback for early connection rejection. - /// * Return false to reject connection. - /// * A null response is ok, we just won't send anything. - /// - public AcceptConnectionCheck AcceptConnection; - - /// - /// The layer-7 packet filter used to drop junk UDP at line speed. - /// Tune its thresholds before if needed. - /// - public UdpPacketFilter PacketFilter => _packetFilter; - -#nullable enable - /// - /// Creates a new UdpConnectionListener for the given , port and . - /// - /// The endpoint to listen on. - /// - /// - /// - public UdpConnectionListener(IPEndPoint endPoint, ObjectPool readerPool, IPMode ipMode = IPMode.IPv4, Action? Setup = null) - { - EndPoint = endPoint; - IPMode = ipMode; - - _readerPool = readerPool; - _socket = new UdpClient(endPoint); - - try - { - _socket.DontFragment = false; - } - catch (SocketException) - { - } - - _reliablePacketTimer = new Timer(ManageReliablePackets, null, 100, Timeout.Infinite); - - _allConnections = new ConcurrentDictionary(); - - _stoppingCts = new CancellationTokenSource(); - _stoppingCts.Token.Register(() => { _socket.Dispose(); }); - - _connectionRateLimit = new UdpConnectionRateLimit(); - _packetFilter = new UdpPacketFilter(); - Setup?.Invoke(_socket, _connectionRateLimit); - } - - private async void ManageReliablePackets(object? state) - { - foreach (var kvp in _allConnections) - { - var sock = kvp.Value; - await sock.ManageReliablePackets(); - } - - try - { - _reliablePacketTimer.Change(100, Timeout.Infinite); - } - catch - { - // ignored - } - } - - /// - public override Task StartAsync() - { - // Store the task we're executing - _executingTask = Task.Factory.StartNew(ListenAsync, TaskCreationOptions.LongRunning); - - // If the task is completed then return it, this will bubble cancellation and failure to the caller - return _executingTask.IsCompleted ? _executingTask : - // Otherwise it's running - Task.CompletedTask; - } - - private async Task StopAsync() - { - // Stop called without start - if (_executingTask == null) return; - - try - { - // Signal cancellation to the executing method - await _stoppingCts.CancelAsync(); - } - finally - { - // Wait until the task completes or the timeout triggers - await Task.WhenAny(_executingTask, Task.Delay(TimeSpan.FromSeconds(5))); - } - } - - /// - /// Instructs the listener to begin listening. - /// - private async Task ListenAsync() - { - try - { - while (!_stoppingCts.IsCancellationRequested) - { - UdpReceiveResult data; - - try - { - data = await _socket.ReceiveAsync(); - - if (data.Buffer.Length == 0) - { - Logger.Fatal("Hazel read 0 bytes from UDP server socket."); - continue; - } - } - catch (SocketException) - { - // Client no longer reachable, pretend it didn't happen - continue; - } - catch (ObjectDisposedException) - { - // Socket was disposed, don't care. - return; - } - - await ProcessData(data); - } - } - catch (Exception e) - { - Logger.Error(e, "Listen loop error"); - } - } - - protected virtual async ValueTask ProcessData(UdpReceiveResult data) - { - // Get client from active clients - if (!_allConnections.TryGetValue(data.RemoteEndPoint, out var client)) - { - // Filtaur-style layer-7 firewall: drop junk packets at line speed - // before they can reach the game server. Only applies to unknown - // endpoints; established connections are never filtered here. - if (_packetFilter.ShouldDrop(data.RemoteEndPoint.Address, data.Buffer, data.Buffer.Length)) - { - return; - } - - // Check for malformed connection attempts - if (data.Buffer[0] != (byte)UdpSendOption.Hello) - { - Logger.Debug("Rejected non-Hello packet from {0} (first byte: 0x{1:X2})", data.RemoteEndPoint, data.Buffer[0]); - return; - } - - // Check rateLimit. - if (!_connectionRateLimit.IsAllowed(data.RemoteEndPoint.Address)) - { - Logger.Warning("Ratelimited connection attempt from {0}.", data.RemoteEndPoint); - return; - } - - // Create new client - client = new UdpServerConnection(this, data.RemoteEndPoint, IPMode, _readerPool); - - // Store the client - if (!_allConnections.TryAdd(data.RemoteEndPoint, client)) - throw new HazelException("Failed to add a connection. This should never happen."); - - // Activate the reader loop of the client - await client.StartAsync(); - } - - // Write to client. - await client.Pipeline.Writer.WriteAsync(data.Buffer); - } - - /// - /// Sends data from the listener socket. - /// - /// The bytes to send. - /// - /// The endpoint to send to. - internal virtual async ValueTask SendData(byte[] bytes, int length, IPEndPoint endPoint) - { - if (length > bytes.Length) return; - - try - { - await _socket.SendAsync(bytes, length, endPoint); - } - catch (SocketException e) - { - Logger.Error(e, "Could not send data as a SocketException occurred"); - } - catch (ObjectDisposedException) - { - //Keep alive timer probably ran, ignore - } - } - - /// - /// Removes a virtual connection from the list. - /// - /// The endpoint of the virtual connection. - internal void RemoveConnectionTo(EndPoint endPoint) - { - _allConnections.TryRemove(endPoint, out var conn); - } - - /// - public override async ValueTask DisposeAsync() - { - foreach (var kvp in _allConnections) kvp.Value.Dispose(); - - await StopAsync(); - - await _reliablePacketTimer.DisposeAsync(); - - _connectionRateLimit.Dispose(); - _packetFilter.Dispose(); - - await base.DisposeAsync(); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnectionRateLimit.cs b/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnectionRateLimit.cs deleted file mode 100644 index d1c2d22..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpConnectionRateLimit.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Net; -using System.Threading; -using Serilog; - -namespace Next.Hazel.Udp; - -public class UdpConnectionRateLimit : IDisposable -{ - // Allow burst to 5 connections. - // Decrease by 1 every second. - public int MaxConnections { get; private set; } = 5; - - public int FalloffMs { get; private set; } = 1000; - private static readonly ILogger Logger = Log.ForContext(); - - private readonly ConcurrentDictionary _connectionCount; - private IReadOnlyDictionary _ConnectionCount => _connectionCount.AsReadOnly(); - private readonly Timer _timer; - private bool _isDisposed; - - public void Reset(int maxConnections, int falloffMs) - { - MaxConnections = maxConnections; - FalloffMs = falloffMs; - _timer.Change(FalloffMs, Timeout.Infinite); - } - - public UdpConnectionRateLimit() - { - _connectionCount = new ConcurrentDictionary(); - _timer = new Timer(UpdateRateLimit, null, FalloffMs, Timeout.Infinite); - } - - public void Dispose() - { - _isDisposed = true; - _timer.Dispose(); - } - - private void UpdateRateLimit(object state) - { - try - { - foreach (var pair in _connectionCount) - { - var count = pair.Value - 1; - if (count > 0) - _connectionCount.TryUpdate(pair.Key, count, pair.Value); - else - _connectionCount.TryRemove(pair); - } - } - catch (Exception e) - { - Logger.Error(e, "Exception caught in UpdateRateLimit."); - } - finally - { - if (!_isDisposed) _timer.Change(FalloffMs, Timeout.Infinite); - } - } - - public bool IsAllowed(IPAddress key) - { - if (_connectionCount.TryGetValue(key, out var value) && value >= MaxConnections) - return false; - - _connectionCount.AddOrUpdate(key, _ => 1, (_, i) => i + 1); - return true; - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpPacketFilter.cs b/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpPacketFilter.cs deleted file mode 100644 index 8fed83b..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpPacketFilter.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System; -using System.Collections.Concurrent; -using System.Net; -using System.Threading; -using Next.Hazel.Abstractions; -using Serilog; - -namespace Next.Hazel.Udp; - -/// -/// A Filtaur-style layer-7 firewall for the UDP listener. -/// It drops malformed / junk packets at line speed before they reach the -/// game server, so a simple packet-flooding attacker cannot overload the -/// server and drop everyone out of their games. -/// -/// -/// The filter only applies to new connection attempts (packets from -/// unknown endpoints). Packets belonging to an established connection are -/// never rate-limited here, so in-game traffic is unaffected. -/// -public sealed class UdpPacketFilter : IDisposable -{ - private static readonly ILogger Logger = Log.ForContext(); - - /// - /// Minimal valid packet length (send-option byte + 4-byte handshake nonce). - /// - public int MinPacketLength { get; set; } = 5; - - /// - /// Maximum accepted packet length. Anything larger is dropped instantly. - /// - public int MaxPacketLength { get; set; } = 1203; - - /// - /// Allowed burst of connection attempts from a single IP before - /// kicks in. - /// - public int BurstLimit { get; set; } = 30; - - /// - /// How long an abusive IP stays blacklisted. - /// - public int BlacklistSeconds { get; set; } = 60; - - private readonly bool[] _validOption = BuildValidOptionTable(); - private readonly ConcurrentDictionary _states = new(); - private bool _isDisposed; - - public UdpPacketFilter() - { - } - - /// - /// Fast synchronous check. Returns true when the packet must be - /// dropped, false when it is allowed through. - /// This path performs no allocations. - /// - public bool ShouldDrop(IPAddress ip, byte[] buffer, int length) - { - // 1. Size check (cheapest, no state). - if (length < MinPacketLength || length > MaxPacketLength) - { - Logger.Debug("UdpPacketFilter dropped packet from {Ip}: length {Length} outside [{Min}, {Max}]", ip, length, MinPacketLength, MaxPacketLength); - return true; - } - - // 2. Send-option byte check (layer-7, no state). - if (!_validOption[buffer[0]]) - { - Logger.Debug("UdpPacketFilter dropped packet from {Ip}: invalid first byte 0x{Byte:X2}", ip, buffer[0]); - return true; - } - - // 3. Per-IP connection burst limiting with a temporary blacklist. - var now = Environment.TickCount64; - var state = _states.GetOrAdd(ip, static _ => new IpState()); - - // Reset the window when the previous window expired, and lazily shed - // blacklisted entries whose cooldown is over. - if (now - state.WindowStart > 1000) - { - if (state.BlacklistUntil > 0 && state.BlacklistUntil <= now) - { - _states.TryRemove(ip, out _); - return false; - } - - state.WindowStart = now; - state.Count = 0; - } - - if (state.BlacklistUntil > now) - { - return true; - } - - state.Count++; - if (state.Count <= BurstLimit) - { - return false; - } - - // Abuse detected: blacklist the IP for a while. - state.BlacklistUntil = now + BlacklistSeconds * 1000L; - state.Count = 0; - Logger.Warning("UdpPacketFilter blacklisted {Ip} for {Seconds}s after too many connection attempts", - ip, BlacklistSeconds); - return true; - } - - private static bool[] BuildValidOptionTable() - { - var table = new bool[256]; - // MessageType - table[(byte)MessageType.Unreliable] = true; - table[(byte)MessageType.Reliable] = true; - // UdpSendOption - table[(byte)UdpSendOption.Hello] = true; - table[(byte)UdpSendOption.Ping] = true; - table[(byte)UdpSendOption.Disconnect] = true; - table[(byte)UdpSendOption.Acknowledgement] = true; - table[(byte)UdpSendOption.Fragment] = true; - return table; - } - - public void Dispose() - { - if (_isDisposed) - { - return; - } - - _isDisposed = true; - _states.Clear(); - } - - private sealed class IpState - { - public int Count; - public long WindowStart; - public long BlacklistUntil; - } -} diff --git a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpServerConnection.cs b/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpServerConnection.cs deleted file mode 100644 index 60290e6..0000000 --- a/src/NextFast.Hazel-New/Next.Hazel/Udp/UdpServerConnection.cs +++ /dev/null @@ -1,97 +0,0 @@ -#nullable enable -using System; -using System.Net; -using System.Threading.Tasks; -using Microsoft.Extensions.ObjectPool; -using Next.Hazel.Abstractions; - -namespace Next.Hazel.Udp; - -internal sealed class UdpServerConnection : UdpConnection -{ - /// - /// Creates a UdpConnection for the virtual connection to the endpoint. - /// - /// The listener that created this connection. - /// The endpoint that we are connected to. - /// The IPMode we are connected using. - /// - internal UdpServerConnection(UdpConnectionListener listener, IPEndPoint endPoint, IPMode IPMode, - ObjectPool readerPool) - : base(listener, readerPool) - { - Listener = listener; - EndPoint = endPoint; - this.IPMode = IPMode; - - State = ConnectionState.Connected; - InitializeKeepAliveTimer(); - } - - /// - /// The connection listener that we use the socket of. - /// - /// - /// Udp server connections utilize the same socket in the listener for sends/receives, this is the listener that - /// created this connection and is hence the listener this conenction sends and receives via. - /// - public UdpConnectionListener Listener { get; } - - /// - protected override ValueTask WriteBytesToConnection(byte[] bytes, int length) - { - return Listener.SendData(bytes, length, EndPoint); - } - - /// - /// - /// This will always throw a HazelException. - /// - public override ValueTask ConnectAsync(byte[] bytes = null!, int timeout = 5000) - { - throw new InvalidOperationException( - "Cannot manually connect a UdpServerConnection, did you mean to use UdpClientConnection?"); - } - - /// - /// Sends a disconnect message to the end point. - /// - protected override async ValueTask SendDisconnect(MessageWriter? data) - { - lock (this) - { - if (_state != ConnectionState.Connected) return false; - _state = ConnectionState.NotConnected; - } - - var bytes = EmptyDisconnectBytes; - if (data is { Length: > 0 }) - { - if (data.SendOption != MessageType.Unreliable) - throw new ArgumentException("Disconnect messages can only be unreliable."); - - bytes = data.ToByteArray(true); - bytes[0] = (byte)UdpSendOption.Disconnect; - } - - try - { - await Listener.SendData(bytes, bytes.Length, EndPoint); - } - catch - { - // ignored - } - - return true; - } - - protected override void Dispose(bool disposing) - { - Listener.RemoveConnectionTo(EndPoint); - - if (disposing) _ = SendDisconnect(null); - - base.Dispose(disposing); - } -} \ No newline at end of file diff --git a/src/NextFast.Hazel-New/README.md b/src/NextFast.Hazel-New/README.md deleted file mode 100644 index bb96164..0000000 --- a/src/NextFast.Hazel-New/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Empostor.Hazel - -Fork of Hazel made for [Empostor](https://github.com/Empostor/Empostor) diff --git a/src/NextFast.Hazel-New/build.cake b/src/NextFast.Hazel-New/build.cake deleted file mode 100644 index 7d03b16..0000000 --- a/src/NextFast.Hazel-New/build.cake +++ /dev/null @@ -1,29 +0,0 @@ -var target = Argument("target", "Build"); - -var workflow = BuildSystem.GitHubActions.Environment.Workflow; -var buildId = workflow.RunNumber; -var tag = workflow.RefType == GitHubActionsRefType.Tag ? workflow.RefName : null; - -Task("Build") - .Does(() => -{ - var settings = new DotNetBuildSettings - { - Configuration = "Release", - OutputDirectory = "./Build/", - MSBuildSettings = new DotNetMSBuildSettings(), - }; - - if (tag != null) - { - settings.MSBuildSettings.Version = tag; - } - else if (buildId != 0) - { - settings.MSBuildSettings.VersionSuffix = "ci." + buildId; - } - - DotNetBuild(".", settings); -}); - -RunTarget(target);