mirror of
https://github.com/zoriya/octokit.net.git
synced 2025-12-21 14:45:11 +00:00
Add attribute to serialize strings as base64 encoded
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using Octokit.Helpers;
|
||||||
using Octokit.Internal;
|
using Octokit.Internal;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
@@ -63,6 +63,21 @@ namespace Octokit.Tests
|
|||||||
|
|
||||||
Assert.Equal("{\"int\":42,\"bool\":true}", json);
|
Assert.Equal("{\"int\":42,\"bool\":true}", json);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void HandlesBase64EncodedStrings()
|
||||||
|
{
|
||||||
|
var item = new SomeObject
|
||||||
|
{
|
||||||
|
Name = "Ferris Bueller",
|
||||||
|
Content = "Day off",
|
||||||
|
Description = "stuff"
|
||||||
|
};
|
||||||
|
|
||||||
|
var json = new SimpleJsonSerializer().Serialize(item);
|
||||||
|
|
||||||
|
Assert.Equal("{\"name\":\"RmVycmlzIEJ1ZWxsZXI=\",\"description\":\"stuff\",\"content\":\"RGF5IG9mZg==\"}", json);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TheDeserializeMethod
|
public class TheDeserializeMethod
|
||||||
@@ -80,6 +95,18 @@ namespace Octokit.Tests
|
|||||||
Assert.True(sample.Private);
|
Assert.True(sample.Private);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void UnencodesBase64Strings()
|
||||||
|
{
|
||||||
|
const string json = "{\"name\":\"RmVycmlzIEJ1ZWxsZXI=\",\"description\":\"stuff\",\"content\":\"RGF5IG9mZg==\"}";
|
||||||
|
|
||||||
|
var someObject = new SimpleJsonSerializer().Deserialize<SomeObject>(json);
|
||||||
|
|
||||||
|
Assert.Equal("Ferris Bueller", someObject.Name);
|
||||||
|
Assert.Equal("Day off", someObject.Content);
|
||||||
|
Assert.Equal("stuff", someObject.Description);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void CanDeserializeOrganization()
|
public void CanDeserializeOrganization()
|
||||||
{
|
{
|
||||||
@@ -154,5 +181,16 @@ namespace Octokit.Tests
|
|||||||
[Parameter(Key = "_links")]
|
[Parameter(Key = "_links")]
|
||||||
public string Links { get; set; }
|
public string Links { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class SomeObject
|
||||||
|
{
|
||||||
|
[SerializeAsBase64]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[SerializeAsBase64]
|
||||||
|
public string Content;
|
||||||
|
|
||||||
|
public string Description { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
Octokit/Helpers/SerializeAsBase64Attribute.cs
Normal file
12
Octokit/Helpers/SerializeAsBase64Attribute.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Octokit.Helpers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute used to denote that a string property should be serialized as a base64 encoded string.
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
|
||||||
|
public sealed class SerializeAsBase64Attribute : Attribute
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using Octokit.Helpers;
|
||||||
using Octokit.Reflection;
|
using Octokit.Reflection;
|
||||||
|
|
||||||
namespace Octokit.Internal
|
namespace Octokit.Internal
|
||||||
@@ -23,8 +24,8 @@ namespace Octokit.Internal
|
|||||||
|
|
||||||
class GitHubSerializerStrategy : PocoJsonSerializerStrategy
|
class GitHubSerializerStrategy : PocoJsonSerializerStrategy
|
||||||
{
|
{
|
||||||
readonly List<string> _membersWhichShouldPublishNull
|
readonly List<string> membersWhichShouldPublishNull = new List<string>();
|
||||||
= new List<string>();
|
readonly List<string> membersWhichShouldBeBase64Encoded = new List<string>();
|
||||||
|
|
||||||
protected override string MapClrMemberToJsonFieldName(MemberInfo member)
|
protected override string MapClrMemberToJsonFieldName(MemberInfo member)
|
||||||
{
|
{
|
||||||
@@ -56,19 +57,30 @@ namespace Octokit.Internal
|
|||||||
var getMethod = ReflectionUtils.GetGetterMethodInfo(propertyInfo);
|
var getMethod = ReflectionUtils.GetGetterMethodInfo(propertyInfo);
|
||||||
if (getMethod.IsStatic || !getMethod.IsPublic)
|
if (getMethod.IsStatic || !getMethod.IsPublic)
|
||||||
continue;
|
continue;
|
||||||
var attribute = propertyInfo.GetCustomAttribute<SerializeNullAttribute>();
|
var base64Attribute = propertyInfo.GetCustomAttribute<SerializeAsBase64Attribute>();
|
||||||
if (attribute == null)
|
if (base64Attribute != null)
|
||||||
|
{
|
||||||
|
membersWhichShouldBeBase64Encoded.Add(fullName + MapClrMemberToJsonFieldName(propertyInfo));
|
||||||
|
}
|
||||||
|
var serializeNullAttribute = propertyInfo.GetCustomAttribute<SerializeNullAttribute>();
|
||||||
|
if (serializeNullAttribute == null)
|
||||||
continue;
|
continue;
|
||||||
_membersWhichShouldPublishNull.Add(fullName + MapClrMemberToJsonFieldName(propertyInfo));
|
membersWhichShouldPublishNull.Add(fullName + MapClrMemberToJsonFieldName(propertyInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var fieldInfo in ReflectionUtils.GetFields(type))
|
foreach (var fieldInfo in ReflectionUtils.GetFields(type))
|
||||||
{
|
{
|
||||||
if (fieldInfo.IsStatic || !fieldInfo.IsPublic)
|
if (fieldInfo.IsStatic || !fieldInfo.IsPublic)
|
||||||
continue;
|
continue;
|
||||||
|
var base64Attribute = fieldInfo.GetCustomAttribute<SerializeAsBase64Attribute>();
|
||||||
|
if (base64Attribute != null)
|
||||||
|
{
|
||||||
|
membersWhichShouldBeBase64Encoded.Add(fullName + MapClrMemberToJsonFieldName(fieldInfo));
|
||||||
|
}
|
||||||
var attribute = fieldInfo.GetCustomAttribute<SerializeNullAttribute>();
|
var attribute = fieldInfo.GetCustomAttribute<SerializeNullAttribute>();
|
||||||
if (attribute == null)
|
if (attribute == null)
|
||||||
continue;
|
continue;
|
||||||
_membersWhichShouldPublishNull.Add(fullName + MapClrMemberToJsonFieldName(fieldInfo));
|
membersWhichShouldPublishNull.Add(fullName + MapClrMemberToJsonFieldName(fieldInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.GetterValueFactory(type);
|
return base.GetterValueFactory(type);
|
||||||
@@ -91,10 +103,18 @@ namespace Octokit.Internal
|
|||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
var key = type.FullName + "-" + getter.Key;
|
var key = type.FullName + "-" + getter.Key;
|
||||||
if (!_membersWhichShouldPublishNull.Contains(key))
|
if (!membersWhichShouldPublishNull.Contains(key))
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var key = type.FullName + "-" + getter.Key;
|
||||||
|
if (membersWhichShouldBeBase64Encoded.Contains(key))
|
||||||
|
{
|
||||||
|
var stringValue = value as string ?? "";
|
||||||
|
value = Convert.ToBase64String(Encoding.UTF8.GetBytes(stringValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
jsonObject.Add(getter.Key, value);
|
jsonObject.Add(getter.Key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,7 +163,38 @@ namespace Octokit.Internal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.DeserializeObject(value, type);
|
var deserialized = base.DeserializeObject(value, type);
|
||||||
|
|
||||||
|
// Handle base64 encoding
|
||||||
|
foreach (var propertyInfo in ReflectionUtils.GetProperties(type))
|
||||||
|
{
|
||||||
|
if (!propertyInfo.CanRead) continue;
|
||||||
|
if (!propertyInfo.CanWrite) continue;
|
||||||
|
if (propertyInfo.GetCustomAttribute<SerializeAsBase64Attribute>() != null)
|
||||||
|
{
|
||||||
|
var propertyValue = propertyInfo.GetValue(deserialized) as string;
|
||||||
|
if (propertyValue != null)
|
||||||
|
{
|
||||||
|
var unencoded = Encoding.UTF8.GetString(Convert.FromBase64String(propertyValue));
|
||||||
|
propertyInfo.SetValue(deserialized, unencoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var fieldInfo in ReflectionUtils.GetFields(type))
|
||||||
|
{
|
||||||
|
if (fieldInfo.GetCustomAttribute<SerializeAsBase64Attribute>() != null)
|
||||||
|
{
|
||||||
|
var propertyValue = fieldInfo.GetValue(deserialized) as string;
|
||||||
|
if (propertyValue != null)
|
||||||
|
{
|
||||||
|
var unencoded = Encoding.UTF8.GetString(Convert.FromBase64String(propertyValue));
|
||||||
|
fieldInfo.SetValue(deserialized, unencoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return deserialized;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -352,6 +352,7 @@
|
|||||||
<Compile Include="Models\Response\DirectoryContent.cs" />
|
<Compile Include="Models\Response\DirectoryContent.cs" />
|
||||||
<Compile Include="Models\Request\CreateFileRequest.cs" />
|
<Compile Include="Models\Request\CreateFileRequest.cs" />
|
||||||
<Compile Include="Models\Request\Signature.cs" />
|
<Compile Include="Models\Request\Signature.cs" />
|
||||||
|
<Compile Include="Helpers\SerializeAsBase64Attribute.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
@@ -362,6 +362,7 @@
|
|||||||
<Compile Include="Models\Response\DirectoryContent.cs" />
|
<Compile Include="Models\Response\DirectoryContent.cs" />
|
||||||
<Compile Include="Models\Request\CreateFileRequest.cs" />
|
<Compile Include="Models\Request\CreateFileRequest.cs" />
|
||||||
<Compile Include="Models\Request\Signature.cs" />
|
<Compile Include="Models\Request\Signature.cs" />
|
||||||
|
<Compile Include="Helpers\SerializeAsBase64Attribute.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath)\Novell\Novell.MonoDroid.CSharp.targets" />
|
||||||
</Project>
|
</Project>
|
||||||
@@ -357,6 +357,7 @@
|
|||||||
<Compile Include="Models\Response\DirectoryContent.cs" />
|
<Compile Include="Models\Response\DirectoryContent.cs" />
|
||||||
<Compile Include="Models\Request\CreateFileRequest.cs" />
|
<Compile Include="Models\Request\CreateFileRequest.cs" />
|
||||||
<Compile Include="Models\Request\Signature.cs" />
|
<Compile Include="Models\Request\Signature.cs" />
|
||||||
|
<Compile Include="Helpers\SerializeAsBase64Attribute.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.MonoTouch.CSharp.targets" />
|
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.MonoTouch.CSharp.targets" />
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
|
|||||||
@@ -350,6 +350,7 @@
|
|||||||
<Compile Include="Models\Response\DirectoryContent.cs" />
|
<Compile Include="Models\Response\DirectoryContent.cs" />
|
||||||
<Compile Include="Models\Request\CreateFileRequest.cs" />
|
<Compile Include="Models\Request\CreateFileRequest.cs" />
|
||||||
<Compile Include="Models\Request\Signature.cs" />
|
<Compile Include="Models\Request\Signature.cs" />
|
||||||
|
<Compile Include="Helpers\SerializeAsBase64Attribute.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CodeAnalysisDictionary Include="..\CustomDictionary.xml">
|
<CodeAnalysisDictionary Include="..\CustomDictionary.xml">
|
||||||
|
|||||||
@@ -354,6 +354,7 @@
|
|||||||
<Compile Include="Models\Response\DirectoryContent.cs" />
|
<Compile Include="Models\Response\DirectoryContent.cs" />
|
||||||
<Compile Include="Models\Request\CreateFileRequest.cs" />
|
<Compile Include="Models\Request\CreateFileRequest.cs" />
|
||||||
<Compile Include="Models\Request\Signature.cs" />
|
<Compile Include="Models\Request\Signature.cs" />
|
||||||
|
<Compile Include="Helpers\SerializeAsBase64Attribute.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CodeAnalysisDictionary Include="..\CustomDictionary.xml">
|
<CodeAnalysisDictionary Include="..\CustomDictionary.xml">
|
||||||
|
|||||||
@@ -365,6 +365,7 @@
|
|||||||
<Compile Include="Models\Request\UserUpdate.cs" />
|
<Compile Include="Models\Request\UserUpdate.cs" />
|
||||||
<Compile Include="Helpers\StringExtensions.cs" />
|
<Compile Include="Helpers\StringExtensions.cs" />
|
||||||
<Compile Include="Clients\RepositoriesClient.cs" />
|
<Compile Include="Clients\RepositoriesClient.cs" />
|
||||||
|
<Compile Include="Helpers\SerializeAsBase64Attribute.cs" />
|
||||||
<Compile Include="SimpleJson.cs" />
|
<Compile Include="SimpleJson.cs" />
|
||||||
<Compile Include="Models\Request\NewRepository.cs" />
|
<Compile Include="Models\Request\NewRepository.cs" />
|
||||||
<Compile Include="Clients\UsersClient.cs" />
|
<Compile Include="Clients\UsersClient.cs" />
|
||||||
|
|||||||
Reference in New Issue
Block a user