Skip to content

Commit

Permalink
Add JSON Source Gen (#17)
Browse files Browse the repository at this point in the history
* Add JSON Source Gen

- LTS Target
- AOT Analyzer for .NET 8

* Get Ready For Merge

* Formatting
  • Loading branch information
justindbaur authored Sep 1, 2023
1 parent d0255ae commit 75fade0
Show file tree
Hide file tree
Showing 27 changed files with 495 additions and 106 deletions.
6 changes: 4 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<Project>
<!-- See https://aka.ms/dotnet/msbuild/customize for more details on customizing your build -->
<PropertyGroup>
<TargetFrameworks>net6.0;net462</TargetFrameworks>
<CurrentPreviewTfm>net8.0</CurrentPreviewTfm>
<!--<IncludePreview>true</IncludePreview>-->
<IncludePreview Condition=" '$(IncludePreview)' == ''">false</IncludePreview>
<LangVersion>latest</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
Expand All @@ -10,7 +12,7 @@
<PropertyGroup>
<PasswordlessMajorVersion>1</PasswordlessMajorVersion>
<PasswordlessMinorVersion>0</PasswordlessMinorVersion>
<PasswordlessPatchVersion>1</PasswordlessPatchVersion>
<PasswordlessPatchVersion>2</PasswordlessPatchVersion>
<PasswordlessMajorMinorVersion>$(PasswordlessMajorVersion).$(PasswordlessMinorVersion)</PasswordlessMajorMinorVersion>
<VersionPrefix>$(PasswordlessMajorMinorVersion).$(PasswordlessPatchVersion)</VersionPrefix>
</PropertyGroup>
Expand Down
4 changes: 2 additions & 2 deletions src/Sdk/Base64Url.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public static string Encode(ReadOnlySpan<byte> arg)

#if NET5_0_OR_GREATER
Convert.TryToBase64Chars(arg, array, out var charsWritten);
#elif NET462
#elif NET462 || NETSTANDARD2_0
var charsWritten = Convert.ToBase64CharArray(arg.ToArray(), 0, minimumLength, array, 0);
#endif
Span<char> span = array.AsSpan(0, charsWritten);
Expand All @@ -42,7 +42,7 @@ public static string Encode(ReadOnlySpan<byte> arg)

#if NET5_0_OR_GREATER
string result = new string(span);
#elif NET462
#elif NET462 || NETSTANDARD2_0
string result = new string(span.ToArray());
#endif
ArrayPool<char>.Shared.Return(array, clearArray: true);
Expand Down
8 changes: 0 additions & 8 deletions src/Sdk/Helpers/Json.cs

This file was deleted.

26 changes: 26 additions & 0 deletions src/Sdk/Helpers/PasswordlessSerializerContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Passwordless.Net.Models;

namespace Passwordless.Net.Helpers;

[JsonSourceGenerationOptions(
PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(RegisterTokenResponse))]
[JsonSerializable(typeof(RegisterOptions))]
[JsonSerializable(typeof(VerifyTokenRequest))] // TODO: Use this with JsonContent.Create
[JsonSerializable(typeof(VerifiedUser))]
[JsonSerializable(typeof(DeleteUserRequest))]
[JsonSerializable(typeof(ListResponse<PasswordlessUserSummary>))]
[JsonSerializable(typeof(ListResponse<AliasPointer>))]
[JsonSerializable(typeof(ListResponse<Credential>))]
[JsonSerializable(typeof(DeleteCredentialRequest))]
[JsonSerializable(typeof(UsersCount))]
[JsonSerializable(typeof(PasswordlessProblemDetails))]
[JsonSerializable(typeof(Dictionary<string, JsonElement>))]
[JsonSerializable(typeof(JsonElement))]
internal partial class PasswordlessSerializerContext : JsonSerializerContext
{

}
2 changes: 1 addition & 1 deletion src/Sdk/IPasswordlessClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public interface IPasswordlessClient
/// <param name="cancellationToken"></param>
/// <returns>A task object representing the asynchronous operation containing the <see cref="IReadOnlyList{PasswordlessUserSummary}" />.</returns>
/// <exception cref="PasswordlessApiException">An exception containing details abaout the reason for failure.</exception>
Task<IReadOnlyList<PasswordlessUserSummary>?> ListUsersAsync(CancellationToken cancellationToken = default);
Task<IReadOnlyList<PasswordlessUserSummary>> ListUsersAsync(CancellationToken cancellationToken = default);

/// <summary>
/// Verifies that the given token is valid and returns information packed into it. The token should have been generated
Expand Down
13 changes: 10 additions & 3 deletions src/Sdk/Models/AliasPointer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@

public class AliasPointer
{
public string UserId { get; set; }
public string Alias { get; set; }
public string Plaintext { get; set; }
public AliasPointer(string userId, string alias, string plaintext)
{
UserId = userId;
Alias = alias;
Plaintext = plaintext;
}

public string UserId { get; }
public string Alias { get; }
public string Plaintext { get; }
}
9 changes: 0 additions & 9 deletions src/Sdk/Models/AuditLog.cs

This file was deleted.

48 changes: 34 additions & 14 deletions src/Sdk/Models/Credential.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,38 @@

public class Credential
{
public CredentialDescriptor Descriptor { get; set; }
public byte[] PublicKey { get; set; }
public byte[] UserHandle { get; set; }
public uint SignatureCounter { get; set; }
public string AttestationFmt { get; set; }
public DateTime CreatedAt { get; set; }
public Guid AaGuid { get; set; }
public DateTime LastUsedAt { get; set; }
public string RPID { get; set; }
public string Origin { get; set; }
public string Country { get; set; }
public string Device { get; set; }
public string Nickname { get; set; }
public string UserId { get; set; }
public Credential(CredentialDescriptor descriptor, byte[] publicKey, byte[] userHandle, uint signatureCounter,
string attestationFmt, DateTime createdAt, Guid aaGuid, DateTime lastUsedAt, string rpid,
string origin, string country, string device, string nickname, string userId)
{
Descriptor = descriptor;
PublicKey = publicKey;
UserHandle = userHandle;
SignatureCounter = signatureCounter;
AttestationFmt = attestationFmt;
CreatedAt = createdAt;
AaGuid = aaGuid;
LastUsedAt = lastUsedAt;
RPID = rpid;
Origin = origin;
Country = country;
Device = device;
Nickname = nickname;
UserId = userId;
}

public CredentialDescriptor Descriptor { get; }
public byte[] PublicKey { get; }
public byte[] UserHandle { get; }
public uint SignatureCounter { get; }
public string AttestationFmt { get; }
public DateTime CreatedAt { get; }
public Guid AaGuid { get; }
public DateTime LastUsedAt { get; }
public string RPID { get; }
public string Origin { get; }
public string Country { get; }
public string Device { get; }
public string Nickname { get; }
public string UserId { get; }
}
7 changes: 5 additions & 2 deletions src/Sdk/Models/CredentialDescriptor.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
using System.Text.Json.Serialization;

using static Passwordless.Net.PasswordlessClient;

namespace Passwordless.Net;

public class CredentialDescriptor
{
public CredentialDescriptor(byte[] id)
{
Id = id;
}

[JsonConverter(typeof(Base64UrlConverter))]
public byte[] Id { get; set; }
}
11 changes: 11 additions & 0 deletions src/Sdk/Models/DeleteCredentialRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Passwordless.Net.Models;

internal class DeleteCredentialRequest
{
public DeleteCredentialRequest(string credentialId)
{
CredentialId = credentialId;
}

public string CredentialId { get; }
}
11 changes: 11 additions & 0 deletions src/Sdk/Models/DeleteUserRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Passwordless.Net.Models;

internal class DeleteUserRequest
{
public DeleteUserRequest(string userId)
{
UserId = userId;
}

public string UserId { get; }
}
20 changes: 15 additions & 5 deletions src/Sdk/Models/PasswordlessUserSummary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@ namespace Passwordless.Net;

public class PasswordlessUserSummary
{
public string UserId { get; set; }
public List<string> Aliases { get; set; }
public int CredentialsCount { get; set; }
public int AliasCount { get; set; }
public DateTime? LastUsedAt { get; set; }
public PasswordlessUserSummary(string userId, IReadOnlyList<string> aliases, int credentialsCount,
int aliasCount, DateTime? lastUsedAt)
{
UserId = userId;
Aliases = aliases;
CredentialsCount = credentialsCount;
AliasCount = aliasCount;
LastUsedAt = lastUsedAt;
}

public string UserId { get; }
public IReadOnlyList<string> Aliases { get; }
public int CredentialsCount { get; }
public int AliasCount { get; }
public DateTime? LastUsedAt { get; }
}
4 changes: 3 additions & 1 deletion src/Sdk/Models/RegisterOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Passwordless.Net;
using System.Text.Json.Serialization;

namespace Passwordless.Net;

/// <summary>
///
Expand Down
11 changes: 9 additions & 2 deletions src/Sdk/Models/RegisterTokenResponse.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
namespace Passwordless.Net.Models;
using System.Text.Json.Serialization;

namespace Passwordless.Net.Models;

public class RegisterTokenResponse
{
public string Token { get; set; }
public RegisterTokenResponse(string token)
{
Token = token;
}

public string Token { get; }
}
7 changes: 6 additions & 1 deletion src/Sdk/Models/UsersCount.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,10 @@ namespace Passwordless.Net;

public class UsersCount
{
public int Count { get; set; }
public UsersCount(int count)
{
Count = count;
}

public int Count { get; }
}
42 changes: 30 additions & 12 deletions src/Sdk/Models/VerifiedUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,34 @@

public class VerifiedUser
{
public string UserId { get; set; }
public byte[] CredentialId { get; set; }
public bool Success { get; set; }
public DateTime Timestamp { get; set; }
public string RpId { get; set; }
public string Origin { get; set; }
public string Device { get; set; }
public string Country { get; set; }
public string Nickname { get; set; }
public DateTime ExpiresAt { get; set; }
public Guid TokenId { get; set; }
public string Type { get; set; }
public VerifiedUser(string userId, byte[] credentialId, bool success,
DateTime timestamp, string rpId, string origin, string device,
string country, string nickname, DateTime expiresAt, Guid tokenId,
string type)
{
UserId = userId;
CredentialId = credentialId;
Success = success;
Timestamp = timestamp;
RpId = rpId;
Origin = origin;
Device = device;
Country = country;
Nickname = nickname;
ExpiresAt = expiresAt;
TokenId = tokenId;
Type = type;
}
public string UserId { get; }
public byte[] CredentialId { get; }
public bool Success { get; }
public DateTime Timestamp { get; }
public string RpId { get; }
public string Origin { get; }
public string Device { get; }
public string Country { get; }
public string Nickname { get; }
public DateTime ExpiresAt { get; }
public Guid TokenId { get; }
public string Type { get; }
}
11 changes: 11 additions & 0 deletions src/Sdk/Models/VerifyTokenRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace Passwordless.Net.Models;

internal class VerifyTokenRequest
{
public VerifyTokenRequest(string token)
{
Token = token;
}

public string Token { get; }
}
31 changes: 21 additions & 10 deletions src/Sdk/PasswordlessApiException.cs
Original file line number Diff line number Diff line change
@@ -1,28 +1,39 @@
using System.Diagnostics;
using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Passwordless.Net;

public sealed class PasswordlessApiException : HttpRequestException
{
public ProblemDetails Details { get; }
public PasswordlessProblemDetails Details { get; }

public PasswordlessApiException(ProblemDetails problemDetails) : base(problemDetails.Title)
public PasswordlessApiException(PasswordlessProblemDetails problemDetails) : base(problemDetails.Title)
{
Details = problemDetails;
}
}

public class ProblemDetails
public class PasswordlessProblemDetails
{
// TODO: Make immutable
public PasswordlessProblemDetails(string type,
string title, int status, string? detail, string? instance)
{
Type = type;
Title = title;
Status = status;
Detail = detail;
Instance = instance;
}

// TODO: Include errorCode as a property once it's more common
public string Type { get; set; } = null!;
public string Title { get; set; } = null!;
public int Status { get; set; }
public string? Detail { get; set; }
public string? Instance { get; set; }
public string Type { get; }
public string Title { get; }
public int Status { get; }
public string? Detail { get; }
public string? Instance { get; }

[JsonExtensionData]
public Dictionary<string, object?> Extensions { get; set; }
public Dictionary<string, JsonElement> Extensions { get; set; } = new Dictionary<string, JsonElement>();
}
Loading

0 comments on commit 75fade0

Please sign in to comment.