diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 986e18d2..dfb542e4 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,3 +1,12 @@
+### 0.12.2 March 31 2022 ####
+
+* Fix [deserialization type cache was shared between multiple serializer instances](https://github.com/akkadotnet/Hyperion/pull/306)
+
+### 0.12.1 March 23 2022 ####
+
+* Fix disallow-unsafe-type Akka.NET settings and harden unsafe type detection [301](https://github.com/akkadotnet/Hyperion/pull/301)
+* Bump [Akka version from 1.4.34 to 1.4.35](https://github.com/akkadotnet/akka.net/releases/tag/1.4.35)
+
### 0.12.0 January 12 2022 ####
* Allow explicit control over which types can be deserialized [#281](https://github.com/akkadotnet/Hyperion/pull/281)
diff --git a/build-system/pr-validation.yaml b/build-system/pr-validation.yaml
index 6a62781c..71133c5e 100644
--- a/build-system/pr-validation.yaml
+++ b/build-system/pr-validation.yaml
@@ -21,10 +21,19 @@ jobs:
vmImage: 'windows-2019'
scriptFileName: build.cmd
scriptArgs: all
+
- template: azure-pipeline.template.yaml
parameters:
- name: 'linux_pr'
- displayName: 'Linux PR Validation'
+ name: 'linux_pr_net_core'
+ displayName: 'Linux PR Validation (netcoreapp3.1)'
vmImage: 'ubuntu-16.04'
scriptFileName: ./build.sh
- scriptArgs: all
\ No newline at end of file
+ scriptArgs: runTestsNetCore
+
+ - template: azure-pipeline.template.yaml
+ parameters:
+ name: 'linux_pr_net_5'
+ displayName: 'Linux PR Validation (net5.0)'
+ vmImage: 'ubuntu-16.04'
+ scriptFileName: ./build.sh
+ scriptArgs: runTestsNet
diff --git a/build-system/windows-pr-validation.yaml b/build-system/windows-pr-validation.yaml
index 5f14abd4..18a7e762 100644
--- a/build-system/windows-pr-validation.yaml
+++ b/build-system/windows-pr-validation.yaml
@@ -20,10 +20,19 @@ jobs:
vmImage: 'windows-2019'
scriptFileName: build.cmd
scriptArgs: all
+
- template: azure-pipeline.template.yaml
parameters:
- name: 'linux_pr'
- displayName: 'Linux PR Validation'
+ name: 'linux_pr_net_core'
+ displayName: 'Linux PR Validation (netcoreapp3.1)'
vmImage: 'ubuntu-18.04'
scriptFileName: ./build.sh
- scriptArgs: all
+ scriptArgs: runTestsNetCore
+
+- template: azure-pipeline.template.yaml
+ parameters:
+ name: 'linux_pr_net_5'
+ displayName: 'Linux PR Validation (net5.0)'
+ vmImage: 'ubuntu-18.04'
+ scriptFileName: ./build.sh
+ scriptArgs: runTestsNet
diff --git a/build.fsx b/build.fsx
index 2b65f763..b1919251 100644
--- a/build.fsx
+++ b/build.fsx
@@ -71,6 +71,8 @@ Target "Clean" (fun _ ->
CleanDirs !! "./**/bin"
CleanDirs !! "./**/obj"
+
+ CreateDir "bin/nuget"
)
Target "AssemblyInfo" (fun _ ->
diff --git a/src/Hyperion.API.Tests/Hyperion.API.Tests.csproj b/src/Hyperion.API.Tests/Hyperion.API.Tests.csproj
index 47966af4..4b11f1fc 100644
--- a/src/Hyperion.API.Tests/Hyperion.API.Tests.csproj
+++ b/src/Hyperion.API.Tests/Hyperion.API.Tests.csproj
@@ -9,7 +9,7 @@
-
+
@@ -17,7 +17,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/src/Hyperion.Akka.Integration.Tests/Hyperion.Akka.Integration.Tests.csproj b/src/Hyperion.Akka.Integration.Tests/Hyperion.Akka.Integration.Tests.csproj
index a0b6417d..baae8a32 100644
--- a/src/Hyperion.Akka.Integration.Tests/Hyperion.Akka.Integration.Tests.csproj
+++ b/src/Hyperion.Akka.Integration.Tests/Hyperion.Akka.Integration.Tests.csproj
@@ -19,7 +19,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
all
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
all
diff --git a/src/Hyperion.Akka.Integration.Tests/IntegrationSpec.cs b/src/Hyperion.Akka.Integration.Tests/IntegrationSpec.cs
index aaf7ece9..2a2d6200 100644
--- a/src/Hyperion.Akka.Integration.Tests/IntegrationSpec.cs
+++ b/src/Hyperion.Akka.Integration.Tests/IntegrationSpec.cs
@@ -1,5 +1,12 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Runtime.Serialization;
+using System.Security.Claims;
+using System.Security.Principal;
+using System.Threading.Tasks;
using Akka.Actor;
using Akka.Configuration;
using Akka.Serialization;
@@ -7,6 +14,7 @@
using Akka.TestKit;
using Akka.TestKit.Xunit2;
using FluentAssertions;
+using Hyperion.Internal;
using Xunit.Abstractions;
using AkkaSerializer = Akka.Serialization.Serializer;
@@ -72,6 +80,79 @@ public void Bugfix263_Akka_HyperionSerializer_should_serialize_ActorPath_list()
deserialized.Destinations[0].Should().Be(deserialized.Destinations[1]);
}
+ [Fact]
+ public async Task CanDeserializeANaughtyTypeWhenAllowed()
+ {
+ var config = ConfigurationFactory.ParseString(@"
+akka {
+ serialize-messages = on
+ actor {
+ serializers {
+ hyperion = ""Akka.Serialization.HyperionSerializer, Akka.Serialization.Hyperion""
+ }
+ serialization-bindings {
+ ""System.Object"" = hyperion
+ }
+ serialization-settings.hyperion.disallow-unsafe-type = false
+ }
+}");
+ var system = ActorSystem.Create("unsafeSystem", config);
+
+ try
+ {
+ var serializer = system.Serialization.FindSerializerForType(typeof(DirectoryInfo));
+ var di = new DirectoryInfo(@"c:\");
+
+ var serialized = serializer.ToBinary(di);
+ var deserialized = serializer.FromBinary(serialized);
+ }
+ finally
+ {
+ await system.Terminate();
+ }
+ }
+
+ [Fact]
+ public async Task CantDeserializeANaughtyTypeByDefault()
+ {
+ var config = ConfigurationFactory.ParseString(@"
+akka {
+ serialize-messages = on
+ actor {
+ serializers {
+ hyperion = ""Akka.Serialization.HyperionSerializer, Akka.Serialization.Hyperion""
+ }
+ serialization-bindings {
+ ""System.Object"" = hyperion
+ }
+ serialization-settings.hyperion.disallow-unsafe-type = true # this is the default value
+ }
+}");
+ var system = ActorSystem.Create("unsafeSystem", config);
+
+ try
+ {
+ var deserializer = system.Serialization.FindSerializerForType(typeof(DirectoryInfo));
+ var di = new DirectoryInfo(@"c:\");
+
+ byte[] serialized;
+ using (var stream = new MemoryStream())
+ {
+ var serializer = new Serializer(SerializerOptions.Default.WithDisallowUnsafeType(false));
+ serializer.Serialize(di, stream);
+ stream.Position = 0;
+ serialized = stream.ToArray();
+ }
+
+ var ex = Assert.Throws(() => deserializer.FromBinary(serialized));
+ ex.InnerException.Should().BeOfType();
+ }
+ finally
+ {
+ await system.Terminate();
+ }
+ }
+
private class MyActor: ReceiveActor
{
diff --git a/src/Hyperion.Benchmarks/TypeRejectionBenchmark.cs b/src/Hyperion.Benchmarks/TypeRejectionBenchmark.cs
new file mode 100644
index 00000000..7cda0a9f
--- /dev/null
+++ b/src/Hyperion.Benchmarks/TypeRejectionBenchmark.cs
@@ -0,0 +1,46 @@
+using System;
+using System.IO;
+using BenchmarkDotNet.Attributes;
+using Hyperion.Internal;
+
+namespace Hyperion.Benchmarks
+{
+ [Config(typeof(HyperionConfig))]
+ public class TypeRejectionBenchmark
+ {
+ private Serializer _serializer;
+ private Stream _dangerousStream;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ var di = new DirectoryInfo("C:\\Windows\\Windows32");
+ var serializer = new Serializer(SerializerOptions.Default.WithDisallowUnsafeType(false));
+ _dangerousStream = new MemoryStream();
+ serializer.Serialize(di, _dangerousStream);
+
+ _serializer = new Serializer();
+ }
+
+ [GlobalCleanup]
+ public void Cleanup()
+ {
+ _dangerousStream.Dispose();
+ }
+
+ [Benchmark]
+ public void DeserializeDanger()
+ {
+ _dangerousStream.Position = 0;
+ try
+ {
+ _serializer.Deserialize(_dangerousStream);
+ }
+ catch(EvilDeserializationException)
+ {
+ // no-op
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Hyperion.Tests.FSharpData/Hyperion.Tests.FSharpData.fsproj b/src/Hyperion.Tests.FSharpData/Hyperion.Tests.FSharpData.fsproj
index d8fa6533..2304331f 100644
--- a/src/Hyperion.Tests.FSharpData/Hyperion.Tests.FSharpData.fsproj
+++ b/src/Hyperion.Tests.FSharpData/Hyperion.Tests.FSharpData.fsproj
@@ -9,7 +9,7 @@
-
+
diff --git a/src/Hyperion.Tests/Hyperion.Tests.csproj b/src/Hyperion.Tests/Hyperion.Tests.csproj
index 6983f5f3..1e934f67 100644
--- a/src/Hyperion.Tests/Hyperion.Tests.csproj
+++ b/src/Hyperion.Tests/Hyperion.Tests.csproj
@@ -18,17 +18,54 @@
$(DefineConstants);NETFX
-
-
- true
-
+
+ ./lib
+ true
+
+
+ ./lib
+ true
+
+
+ ./lib
+ true
+
+
+ ./lib
+ true
+
+
+ ./lib
+ true
+
+
+ ./lib
+ true
+
+
+ ./lib
+ true
+
+
+ ./lib
+ true
+
+
+ ./lib
+ true
+
+
+
+
+
+
diff --git a/src/Hyperion.Tests/UnsafeDeserializationExclusionTests.cs b/src/Hyperion.Tests/UnsafeDeserializationExclusionTests.cs
index e69a58bd..955635e3 100644
--- a/src/Hyperion.Tests/UnsafeDeserializationExclusionTests.cs
+++ b/src/Hyperion.Tests/UnsafeDeserializationExclusionTests.cs
@@ -1,27 +1,117 @@
using System;
+using System.Collections.Generic;
using System.IO;
-using Hyperion.Extensions;
+using System.Runtime.InteropServices;
using Hyperion.Internal;
using Xunit;
using FluentAssertions;
+using Hyperion.Extensions;
+using Xunit.Abstractions;
namespace Hyperion.Tests
{
public class UnsafeDeserializationExclusionTests
{
+ private readonly ITestOutputHelper _output;
+
+ public UnsafeDeserializationExclusionTests(ITestOutputHelper output)
+ {
+ _output = output;
+ }
+
[Fact]
public void CantDeserializeANaughtyType()
{
- //System.Diagnostics.Process p = new Process();
- var serializer = new Hyperion.Serializer();
- var di =new System.IO.DirectoryInfo(@"c:\");
+ var serializer = new Serializer(SerializerOptions.Default.WithDisallowUnsafeType(false));
+ var deserializer = new Serializer();
+ var di = new DirectoryInfo(@"c:\");
using (var stream = new MemoryStream())
{
serializer.Serialize(di, stream);
stream.Position = 0;
Assert.Throws(() =>
- serializer.Deserialize(stream));
+ deserializer.Deserialize(stream));
+ }
+ }
+
+ [Fact]
+ public void CantSerializeANaughtyType()
+ {
+ var serializer = new Serializer();
+ var di = new FileInfo(@"c:\windows\windows32\dangerous.exe");
+
+ using (var stream = new MemoryStream())
+ {
+ Assert.Throws(() =>
+ serializer.Serialize(di, stream));
+ }
+ }
+
+ [Theory]
+ [MemberData(nameof(DangerousObjectFactory))]
+ public void DetectNaughtyTypesByDefault(Type dangerousType)
+ {
+ _output.WriteLine($"Testing for dangerous type [{dangerousType.AssemblyQualifiedName}]");
+ TypeEx.IsDisallowedType(dangerousType).Should().BeTrue();
+ }
+/*
+ X "System.Security.Principal.WindowsIdentity",
+ X "System.Security.Principal.WindowsPrincipal",
+ X "System.Security.Claims.ClaimsIdentity",
+ X "System.Web.Security.RolePrincipal",
+ X "System.Windows.Forms.AxHost.State",
+ X "System.Windows.Data.ObjectDataProvider",
+ X "System.Management.Automation.PSObject",
+ X "System.IO.FileSystemInfo",
+ X "System.IO.FileInfo",
+ X "System.IdentityModel.Tokens.SessionSecurityToken",
+ X "SessionViewStateHistoryItem",
+ X "TextFormattingRunProperties",
+ X "ToolboxItemContainer",
+ X "System.CodeDom.Compiler.TempFileCollection",
+ X "System.Activities.Presentation.WorkflowDesigner",
+ X "System.Windows.ResourceDictionary",
+ X "System.Windows.Forms.BindingSource",
+ X "System.Diagnostics.Process",
+ "System.Management.IWbemClassObjectFreeThreaded" // Need to have sharepoint installed, simulated
+ "Microsoft.Exchange.Management.SystemManager.WinForms.ExchangeSettingsProvider", // Need to have ?Exchange? installed, simulated
+ ??? "System.Security.Principal.WindowsClaimsIdentity", // This FQCN seemed to not exist in the past
+ */
+ public static IEnumerable