diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 00000000..90dac795
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,65 @@
+name: Publish NuGet Packages
+
+on:
+ release:
+ types: [created]
+
+jobs:
+ publish:
+ runs-on: windows-2022
+ timeout-minutes: 30
+
+ env:
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+ DOTNET_CLI_TELEMETRY_OPTOUT: true
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Cache NuGet packages
+ uses: actions/cache@v3
+ with:
+ path: |
+ ~/.nuget/packages
+ ~/.local/share/NuGet/v3-cache
+ key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj', '**/*.props', '**/*.targets') }}
+ restore-keys: |
+ ${{ runner.os }}-nuget-
+
+ - name: Install .NET versions that we need for building the library
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: |
+ 6.0
+ 7.0
+ 8.0
+
+ - name: Add msbuild to PATH
+ uses: microsoft/setup-msbuild@v2
+ with:
+ vs-version: "[17.2,19.0)"
+
+ - name: Install dependencies
+ run: |
+ dotnet tool restore
+ dotnet restore
+
+ - name: Install Cake Tool
+ run: dotnet tool install --global Cake.Tool
+
+ - name: Run Cake Script to Build and Pack
+ run: dotnet cake build.cake --target=CreatePackages --libVersion=${{ github.ref_name }}
+
+ - name: Publish NuGet Packages
+ run: |
+ $ErrorActionPreference = "Stop"
+ Get-ChildItem -Path artifacts\*.nupkg | ForEach-Object {
+ try {
+ dotnet nuget push $_.FullName --api-key ${{ secrets.NUGETAPIKEY }} --source https://api.nuget.org/v3/index.json
+ Write-Host "Pushed $($_.FullName)"
+ } catch {
+ Write-Host "Failed to push $($_.FullName)"
+ exit 1
+ }
+ }
diff --git a/Aikido.Zen.Core/Aikido.Zen.Core.csproj b/Aikido.Zen.Core/Aikido.Zen.Core.csproj
index 9cf940ba..cbacc671 100644
--- a/Aikido.Zen.Core/Aikido.Zen.Core.csproj
+++ b/Aikido.Zen.Core/Aikido.Zen.Core.csproj
@@ -39,6 +39,6 @@
-
+
diff --git a/Aikido.Zen.Core/Helpers/AgentInfoHelper.cs b/Aikido.Zen.Core/Helpers/AgentInfoHelper.cs
index dd5ee1de..3e2b2bc7 100644
--- a/Aikido.Zen.Core/Helpers/AgentInfoHelper.cs
+++ b/Aikido.Zen.Core/Helpers/AgentInfoHelper.cs
@@ -41,7 +41,6 @@ public static AgentInfo GetInfo()
_cachedAgentInfo.DryMode = EnvironmentHelper.DryMode;
_cachedAgentInfo.Serverless = Environment.GetEnvironmentVariable("AWS_LAMBDA_FUNCTION_NAME") != null || Environment.GetEnvironmentVariable("WEBSITE_INSTANCE_ID") != null;
-
return _cachedAgentInfo;
}
}
diff --git a/Aikido.Zen.Core/Helpers/ReflectionHelper.cs b/Aikido.Zen.Core/Helpers/ReflectionHelper.cs
index 763f1a80..9de36e6d 100644
--- a/Aikido.Zen.Core/Helpers/ReflectionHelper.cs
+++ b/Aikido.Zen.Core/Helpers/ReflectionHelper.cs
@@ -32,11 +32,9 @@ static ReflectionHelper()
public static MethodInfo GetMethodFromAssembly(string assemblyName, string typeName, string methodName, params string[] parameterTypeNames)
{
// Attempt to load the assembly
- // Attempt to get the assembly from the cache, if not found, load it
if (!_assemblies.TryGetValue(assemblyName, out var assembly))
{
assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.GetName().Name == assemblyName);
- // If the assembly is not loaded, and the assembly path exists, load it
if (File.Exists($"{assemblyName}.dll") && assembly == null)
{
assembly = Assembly.LoadFrom($"{assemblyName}.dll");
@@ -50,12 +48,16 @@ public static MethodInfo GetMethodFromAssembly(string assemblyName, string typeN
if (!_types.TryGetValue(typeKey, out var type))
{
type = assembly.ExportedTypes.FirstOrDefault(t => t.Name == typeName || t.FullName == typeName);
+
if (type == null) return null;
_types[typeKey] = type;
}
- // Use reflection to get the method
- var method = type.GetMethods().FirstOrDefault(m => m.Name == methodName && m.GetParameters().All(p => parameterTypeNames.Any(ptn => ptn == p.ParameterType.FullName)));
+ // Use reflection to get the method, make sure to check for public, internal and private methods
+ var method = type
+ .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static)
+ .FirstOrDefault(m => m.Name == methodName &&
+ m.GetParameters().Select(p => p.ParameterType.FullName).SequenceEqual(parameterTypeNames));
return method;
}
diff --git a/Aikido.Zen.Core/Patches/SqlClientPatcher.cs b/Aikido.Zen.Core/Patches/SqlClientPatcher.cs
index 690238f4..fd6299a3 100644
--- a/Aikido.Zen.Core/Patches/SqlClientPatcher.cs
+++ b/Aikido.Zen.Core/Patches/SqlClientPatcher.cs
@@ -10,7 +10,8 @@ public static class SqlClientPatcher
{
public static bool OnCommandExecuting(object[] __args, MethodBase __originalMethod, DbCommand __instance, string assembly, Context context)
{
- var command = __instance;
+ var command = __instance
+ ?? __args[0] as DbCommand;
var methodInfo = __originalMethod as MethodInfo;
if (context == null)
@@ -37,6 +38,7 @@ public static SQLDialect GetDialect(string assembly)
{
case "System.Data.SqlClient":
case "Microsoft.Data.SqlClient":
+ case "System.Data.SqlServerCe":
return SQLDialect.MicrosoftSQL;
case "MySql.Data":
case "MySqlConnector":
diff --git a/Aikido.Zen.DotNetCore/Aikido.Zen.DotNetCore.nuspec b/Aikido.Zen.DotNetCore/Aikido.Zen.DotNetCore.nuspec
new file mode 100644
index 00000000..9d3556f7
--- /dev/null
+++ b/Aikido.Zen.DotNetCore/Aikido.Zen.DotNetCore.nuspec
@@ -0,0 +1,64 @@
+
+
+
+ Aikido.Zen.DotNetCore
+ *
+ $title$
+ Aikido Security
+ Aikido Security
+ Aikido Security Zen .NET Core Firewall
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Aikido.Zen.DotNetCore/Aikido.Zen.DotNetCore.targets b/Aikido.Zen.DotNetCore/Aikido.Zen.DotNetCore.targets
new file mode 100644
index 00000000..f84a993f
--- /dev/null
+++ b/Aikido.Zen.DotNetCore/Aikido.Zen.DotNetCore.targets
@@ -0,0 +1,16 @@
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Aikido.Zen.DotNetCore/Middleware/ContextMiddleware.cs b/Aikido.Zen.DotNetCore/Middleware/ContextMiddleware.cs
index 1e5fb9a4..92a3c0a5 100644
--- a/Aikido.Zen.DotNetCore/Middleware/ContextMiddleware.cs
+++ b/Aikido.Zen.DotNetCore/Middleware/ContextMiddleware.cs
@@ -2,6 +2,7 @@
using Aikido.Zen.Core.Helpers;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;
+using System.Collections.Concurrent;
namespace Aikido.Zen.DotNetCore.Middleware
{
@@ -18,9 +19,9 @@ public ContextMiddleware(IEnumerable endpointSources)
public async Task InvokeAsync(HttpContext httpContext, RequestDelegate next)
{
- // Convert headers and query parameters to dictionaries once
- var queryDictionary = httpContext.Request.Query.ToDictionary(q => q.Key, q => q.Value.ToArray());
- var headersDictionary = httpContext.Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToArray());
+ // Convert headers and query parameters to thread-safe dictionaries
+ var queryDictionary = new ConcurrentDictionary(httpContext.Request.Query.ToDictionary(q => q.Key, q => q.Value.ToArray()));
+ var headersDictionary = new ConcurrentDictionary(httpContext.Request.Headers.ToDictionary(h => h.Key, h => h.Value.ToArray()));
var context = new Context
{
diff --git a/Aikido.Zen.DotNetCore/Patches/SqlClientPatches.cs b/Aikido.Zen.DotNetCore/Patches/SqlClientPatches.cs
index 81e86345..a4e2f0db 100644
--- a/Aikido.Zen.DotNetCore/Patches/SqlClientPatches.cs
+++ b/Aikido.Zen.DotNetCore/Patches/SqlClientPatches.cs
@@ -46,6 +46,11 @@ public static void ApplyPatches(Harmony harmony)
PatchMethod(harmony, "MySqlX", "XDevAPI.Relational.Table", "Insert");
PatchMethod(harmony, "MySqlX", "XDevAPI.Relational.Table", "Update");
PatchMethod(harmony, "MySqlX", "XDevAPI.Relational.Table", "Delete");
+
+ // NPoco
+ PatchMethod(harmony, "NPoco", "Database", "ExecuteReaderHelper", "System.Data.Common.DbCommand");
+ PatchMethod(harmony, "NPoco", "Database", "ExecuteNonQueryHelper", "System.Data.Common.DbCommand");
+ PatchMethod(harmony, "NPoco", "Database", "ExecuteScalarHelper", "System.Data.Common.DbCommand");
}
private static void PatchMethod(Harmony harmony, string assemblyName, string typeName, string methodName, params string[] parameterTypeNames)
@@ -59,7 +64,8 @@ private static void PatchMethod(Harmony harmony, string assemblyName, string typ
private static bool OnCommandExecuting(object[] __args, MethodBase __originalMethod, object __instance)
{
- var dbCommand = __instance as System.Data.Common.DbCommand;
+ var dbCommand = __instance as System.Data.Common.DbCommand
+ ?? __args[0] as System.Data.Common.DbCommand;
if (dbCommand == null) return true;
var assembly = __instance.GetType().Assembly.FullName?.Split(", Culture=")[0];
return Aikido.Zen.Core.Patches.SqlClientPatcher.OnCommandExecuting(__args, __originalMethod, dbCommand, assembly, Zen.GetContext());
diff --git a/Aikido.Zen.DotNetFramework/Aikido.Zen.DotNetFramework.nuspec b/Aikido.Zen.DotNetFramework/Aikido.Zen.DotNetFramework.nuspec
index 1e6a9d8b..87a208ab 100644
--- a/Aikido.Zen.DotNetFramework/Aikido.Zen.DotNetFramework.nuspec
+++ b/Aikido.Zen.DotNetFramework/Aikido.Zen.DotNetFramework.nuspec
@@ -1,17 +1,29 @@
- $id$
- $version$
+ Aikido.Zen.DotNetFramework
+ *
$title$
- $author$
+ Aikido Security
+ Aikido Security
+ Aikido Security Zen .NET Framework Firewall
false
MIT
-
- http://project_url_here_or_delete_this_line/
- Aikido Zen, An in-app firewall for .NET
- Summary of changes made in this release of the package.
Copyright 2024 Aikido
firewall .NET
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Aikido.Zen.DotNetFramework/Aikido.Zen.DotNetFramework.targets b/Aikido.Zen.DotNetFramework/Aikido.Zen.DotNetFramework.targets
new file mode 100644
index 00000000..b44589a7
--- /dev/null
+++ b/Aikido.Zen.DotNetFramework/Aikido.Zen.DotNetFramework.targets
@@ -0,0 +1,21 @@
+
+
+
+
+ libraries\libzen_internals_x86_64-pc-windows-gnu.dll
+ PreserveNewest
+
+
+ libraries\libzen_internals_x86_64-pc-windows-gnu.dll.sha256sum
+ PreserveNewest
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Aikido.Zen.DotNetFramework/Patches/SqlClientPatches.cs b/Aikido.Zen.DotNetFramework/Patches/SqlClientPatches.cs
index d9865ab5..fbcb992e 100644
--- a/Aikido.Zen.DotNetFramework/Patches/SqlClientPatches.cs
+++ b/Aikido.Zen.DotNetFramework/Patches/SqlClientPatches.cs
@@ -3,6 +3,7 @@
using HarmonyLib;
using Aikido.Zen.Core.Models;
using Aikido.Zen.Core.Helpers;
+using Aikido.Zen.Core;
namespace Aikido.Zen.DotNetFramework.Patches
{
@@ -27,6 +28,14 @@ public static void ApplyPatches(Harmony harmony)
PatchMethod(harmony, "System.Data.SqlClient", "SqlCommand", "ExecuteScalar");
PatchMethod(harmony, "System.Data.SqlClient", "SqlCommand", "ExecuteReader", "System.Data.CommandBehavior");
+ //SQL ServerCE
+ PatchMethod(harmony, "System.Data.SqlServerCe", "SqlCeCommand", "ExecuteNonQuery");
+ PatchMethod(harmony, "System.Data.SqlServerCe", "SqlCeCommand", "ExecuteScalar");
+ PatchMethod(harmony, "System.Data.SqlServerCe", "SqlCeCommand", "ExecuteReader", "System.Data.CommandBehavior");
+ PatchMethod(harmony, "System.Data.SqlServerCe", "SqlCeCommand", "ExecuteNonQuery");
+ PatchMethod(harmony, "System.Data.SqlServerCe", "SqlCeCommand", "ExecuteScalar");
+ PatchMethod(harmony, "System.Data.SqlServerCe", "SqlCeCommand", "ExecuteReader", "System.Data.CommandBehavior");
+
// SQLite
PatchMethod(harmony, "Microsoft.Data.Sqlite", "SqliteCommand", "ExecuteNonQuery");
PatchMethod(harmony, "Microsoft.Data.Sqlite", "SqliteCommand", "ExecuteScalar");
@@ -50,6 +59,11 @@ public static void ApplyPatches(Harmony harmony)
PatchMethod(harmony, "MySqlX", "XDevAPI.Relational.Table", "Insert");
PatchMethod(harmony, "MySqlX", "XDevAPI.Relational.Table", "Update");
PatchMethod(harmony, "MySqlX", "XDevAPI.Relational.Table", "Delete");
+
+ // NPoco
+ PatchMethod(harmony, "NPoco", "Database", "ExecuteReaderHelper", "System.Data.Common.DbCommand");
+ PatchMethod(harmony, "NPoco", "Database", "ExecuteNonQueryHelper", "System.Data.Common.DbCommand");
+ PatchMethod(harmony, "NPoco", "Database", "ExecuteScalarHelper", "System.Data.Common.DbCommand");
}
///
@@ -78,7 +92,8 @@ private static void PatchMethod(Harmony harmony, string assemblyName, string typ
/// True if the original method should continue execution; otherwise, false.
private static bool OnCommandExecuting(object[] __args, MethodBase __originalMethod, object __instance)
{
- var dbCommand = __instance as System.Data.Common.DbCommand;
+ var dbCommand = __instance as System.Data.Common.DbCommand
+ ?? __args[0] as System.Data.Common.DbCommand;
if (dbCommand == null) return true;
var assembly = __instance.GetType().Assembly.FullName?.Split(new[] { ", Culture=" }, StringSplitOptions.RemoveEmptyEntries)[0];
return Aikido.Zen.Core.Patches.SqlClientPatcher.OnCommandExecuting(__args, __originalMethod, dbCommand, assembly, Zen.GetContext());
diff --git a/build.cake b/build.cake
index 30676e98..2c787326 100644
--- a/build.cake
+++ b/build.cake
@@ -1,4 +1,6 @@
#addin nuget:?package=Cake.FileHelpers&version=6.0.0
+#load "nuget:https://www.nuget.org/api/v2?package=Cake.NuGet&version=5.0.0"
+
var target = Argument("target", "Default");
@@ -6,9 +8,10 @@ var configuration = Argument("configuration", "Release");
var framework = Argument("framework", "");
var solution = "./Aikido.Zen.sln";
var projectName = "Aikido.Zen.Core";
-var version = "0.1.35";
+var zenInternalsVersion = "0.1.35";
+var libVersion = Argument("libVersion", "0.0.1-alpha5");
-var baseUrl = $"https://github.com/AikidoSec/zen-internals/releases/download/v{version}/";
+var baseUrl = $"https://github.com/AikidoSec/zen-internals/releases/download/v{zenInternalsVersion}/";
var librariesDir = $"./{projectName}/libraries";
var filesToDownload = new string[] {
@@ -43,7 +46,7 @@ Task("DownloadLibraries")
{
FilePath file = files.First();
var currVersion = FileReadText(file).Split('-')[1];
- if (currVersion == version)
+ if (currVersion == zenInternalsVersion)
{
Information("Libraries already downloaded. skipping download.");
return;
@@ -81,7 +84,8 @@ Task("Build")
DetailedSummary = false,
NodeReuse = true
}
- .WithTarget("Build");
+ .WithTarget("Build")
+ .WithProperty("version", libVersion);
var projects = GetFiles("./**/*.csproj")
.Where(p => !p.FullPath.Contains("sample-apps") && !p.FullPath.Contains("Aikido.Zen.Benchmarks"));
@@ -168,19 +172,19 @@ Task("Pack")
if (configuration == "Release")
{
var projects = new[] {
- "./Aikido.Zen.Core/Aikido.Zen.Core.csproj",
"./Aikido.Zen.DotNetFramework/Aikido.Zen.DotNetFramework.csproj",
"./Aikido.Zen.DotNetCore/Aikido.Zen.DotNetCore.csproj"
};
foreach (var project in projects)
{
- DotNetPack(project, new DotNetPackSettings
+ var specFile = project.Replace(".csproj", ".nuspec");
+ var nugetPackSettings = new NuGetPackSettings
{
- Configuration = configuration,
- NoBuild = true,
OutputDirectory = "./artifacts",
- });
+ Version = libVersion,
+ };
+ NuGetPack(specFile, nugetPackSettings);
}
Information("Pack task completed successfully.");
}
@@ -191,8 +195,7 @@ Task("Pack")
});
Task("CreatePackages")
- .IsDependentOn("Test")
- .IsDependentOn("TestE2E")
+ .IsDependentOn("Build")
.IsDependentOn("Pack");
Task("Default")
diff --git a/dotnet-tools.json b/dotnet-tools.json
index 7b346950..99a3eb1c 100644
--- a/dotnet-tools.json
+++ b/dotnet-tools.json
@@ -2,11 +2,9 @@
"version": 1,
"isRoot": true,
"tools": {
- "cake.tool": {
- "version": "4.0.0",
- "commands": [
- "dotnet-cake"
- ]
- }
+ "cake.tool": {
+ "version": "5.0.0",
+ "commands": ["dotnet-cake"]
+ }
}
- }
\ No newline at end of file
+}