Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add type safe check when sending custom request / response types #127

Merged
merged 2 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Core Modules/WalletConnectSharp.Common/Utils/TypeSafety.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Newtonsoft.Json;

namespace WalletConnectSharp.Common.Utils;

public static class TypeSafety
{
private static JsonSerializerSettings Settings =
new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Auto };

public static void EnsureTypeSerializerSafe<T>(T testObject)
{
// unwrapping and rewrapping the object
// to / from JSON should tell us
// if it's serializer safe, since
// we are using the serializer to test
UnsafeJsonRewrap<T, T>(testObject, Settings);
}

public static TR UnsafeJsonRewrap<T, TR>(this T source, JsonSerializerSettings settings = null)
{
var json = settings == null ?
JsonConvert.SerializeObject(source) :
JsonConvert.SerializeObject(source, settings);

return JsonConvert.DeserializeObject<TR>(json);
}
}
22 changes: 22 additions & 0 deletions WalletConnectSharp.Core/Controllers/TypedMessageHandler.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Newtonsoft.Json;
using WalletConnectSharp.Common.Logging;
using WalletConnectSharp.Common.Model.Errors;
using WalletConnectSharp.Common.Utils;
using WalletConnectSharp.Core.Interfaces;
using WalletConnectSharp.Core.Models.Relay;
using WalletConnectSharp.Crypto.Models;
Expand All @@ -14,6 +15,7 @@ public class TypedMessageHandler : ITypedMessageHandler
{
private bool _initialized = false;
private Dictionary<string, DecodeOptions> _decodeOptionsMap = new Dictionary<string, DecodeOptions>();
private HashSet<string> _typeSafeCache = new HashSet<string>();

public EventDelegator Events { get; }

Expand Down Expand Up @@ -303,6 +305,8 @@ public DecodeOptions DecodeOptionForTopic(string topic)
/// <returns>The id of the request sent</returns>
public async Task<long> SendRequest<T, TR>(string topic, T parameters, long? expiry = null, EncodeOptions options = null)
{
EnsureTypeIsSerializerSafe(parameters);

var method = RpcMethodAttribute.MethodForType<T>();

var payload = new JsonRpcRequest<T>(method, parameters);
Expand Down Expand Up @@ -339,6 +343,8 @@ public async Task<long> SendRequest<T, TR>(string topic, T parameters, long? exp
/// <typeparam name="TR">The response type</typeparam>
public async Task SendResult<T, TR>(long id, string topic, TR result, EncodeOptions options = null)
{
EnsureTypeIsSerializerSafe(result);

var payload = new JsonRpcResponse<TR>(id, null, result);
var message = await this.Core.Crypto.Encode(topic, payload, options);
var opts = RpcResponseOptionsFromTypes<T, TR>();
Expand All @@ -356,6 +362,9 @@ public async Task SendResult<T, TR>(long id, string topic, TR result, EncodeOpti
/// <typeparam name="TR">The response type</typeparam>
public async Task SendError<T, TR>(long id, string topic, Error error, EncodeOptions options = null)
{
// Type Error is always serializer safe
// EnsureTypeIsSerializerSafe(error);

var payload = new JsonRpcResponse<TR>(id, error, default);
var message = await this.Core.Crypto.Encode(topic, payload, options);
var opts = RpcResponseOptionsFromTypes<T, TR>();
Expand All @@ -367,5 +376,18 @@ public void Dispose()
{
Events?.Dispose();
}

private void EnsureTypeIsSerializerSafe<T>(T testObject)
{
var typeString = typeof(T).FullName;
if (_typeSafeCache.Contains(typeString))
return;

// Throw any serialization exceptions now
// before it's too late
TypeSafety.EnsureTypeSerializerSafe(testObject);

_typeSafeCache.Add(typeString);
}
}
}
Loading