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

Make FluentCore AOT compatible (use source generation for JsonSerializer) #38

Merged
merged 8 commits into from
Aug 31, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace Nrk.FluentCore.Authentication;

[JsonSerializable(typeof(XBLAuthenticateRequest))]
[JsonSerializable(typeof(XBLAuthenticateResponse))]
[JsonSerializable(typeof(XSTSAuthenticateRequest))]
[JsonSerializable(typeof(XSTSAuthenticateErrorModel))]
[JsonSerializable(typeof(XSTSAuthenticateResponse))]
[JsonSerializable(typeof(MicrosoftAuthenticationResponse))]
[JsonSerializable(typeof(OAuth2DeviceCodeResponse))]
[JsonSerializable(typeof(OAuth2TokenResponse))]
[JsonSerializable(typeof(YggdrasilLoginRequest))]
[JsonSerializable(typeof(YggdrasilRefreshRequest))]
[JsonSerializable(typeof(YggdrasilResponseModel))]
internal partial class AuthenticationJsonSerializerContext : JsonSerializerContext
{
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;

Expand All @@ -22,10 +23,12 @@ public class OAuth2TokenResponse
public string? Scope { get; set; }

[JsonPropertyName("access_token")]
public required string AccessToken { get; set; }
[JsonRequired]
public string AccessToken { get; set; } = null!;

[JsonPropertyName("refresh_token")]
public required string RefreshToken { get; set; }
[JsonRequired]
public string RefreshToken { get; set; } = null!;

[JsonPropertyName("user_id")]
public string? UserId { get; set; }
Expand All @@ -43,7 +46,8 @@ public class XBLAuthenticateResponse
public string? NotAfter { get; set; }

[JsonPropertyName("Token")]
public required string Token { get; set; }
[JsonRequired]
public string Token { get; set; } = null!;

[JsonPropertyName("DisplayClaims")]
public DisplayClaims? DisplayClaims { get; set; }
Expand Down Expand Up @@ -115,19 +119,23 @@ public class SkinModel
public class OAuth2DeviceCodeResponse
{
[JsonPropertyName("user_code")]
public required string UserCode { get; set; }
[JsonRequired]
public string UserCode { get; set; } = null!;

[JsonPropertyName("device_code")]
public required string DeviceCode { get; set; }
[JsonRequired]
public string DeviceCode { get; set; } = null!;

[JsonPropertyName("verification_uri")]
public string? VerificationUrl { get; set; }

[JsonPropertyName("expires_in")]
public required int ExpiresIn { get; set; } = -1;
[JsonRequired]
public int ExpiresIn { get; set; } = -1;

[JsonPropertyName("interval")]
public required int Interval { get; set; } = -1;
[JsonRequired]
public int Interval { get; set; } = -1;

[JsonPropertyName("message")]
public string? Message { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ private async Task<OAuth2TokenResponse> AuthMsaAsync(string? parameterName, stri
{
oauth2TokenResponse = await response
.EnsureSuccessStatusCode().Content
.ReadFromJsonAsync<OAuth2TokenResponse>();
.ReadFromJsonAsync(AuthenticationJsonSerializerContext.Default.OAuth2TokenResponse);

if (oauth2TokenResponse is null)
throw new FormatException("Response is null");
Expand All @@ -197,14 +197,15 @@ private async Task<XBLAuthenticateResponse> AuthXboxLiveAsync(string msaToken)

using var xblResponseMessage = await _httpClient.PostAsJsonAsync(
"https://user.auth.xboxlive.com/user/authenticate",
xblRequest);
xblRequest,
AuthenticationJsonSerializerContext.Default.XBLAuthenticateRequest);

// Parse response
XBLAuthenticateResponse? xblResponse = null;
try {
xblResponse = await xblResponseMessage
.EnsureSuccessStatusCode().Content
.ReadFromJsonAsync<XBLAuthenticateResponse>();
.ReadFromJsonAsync(AuthenticationJsonSerializerContext.Default.XBLAuthenticateResponse);

if (xblResponse is null)
throw new FormatException("Response is null");
Expand All @@ -228,13 +229,14 @@ private async Task<string> AuthXstsAsync(string xblToken)

using var xstsResponseMessage = await _httpClient.PostAsJsonAsync(
"https://xsts.auth.xboxlive.com/xsts/authorize",
xstsAuthRequest);
xstsAuthRequest,
AuthenticationJsonSerializerContext.Default.XSTSAuthenticateRequest);

// Handle errors
if (xstsResponseMessage.StatusCode.Equals(HttpStatusCode.Unauthorized))
{
var xstsErrorResponse = await xstsResponseMessage.Content
.ReadFromJsonAsync<XSTSAuthenticateErrorModel>();
.ReadFromJsonAsync(AuthenticationJsonSerializerContext.Default.XSTSAuthenticateErrorModel);

string message = "An error occurred while verifying with Xbox Live";
if (!string.IsNullOrEmpty(xstsErrorResponse?.Message))
Expand Down Expand Up @@ -268,7 +270,7 @@ private async Task<string> AuthXstsAsync(string xblToken)
{
xstsResponse = await xstsResponseMessage
.EnsureSuccessStatusCode().Content
.ReadFromJsonAsync<XSTSAuthenticateResponse>();
.ReadFromJsonAsync(AuthenticationJsonSerializerContext.Default.XSTSAuthenticateResponse);

if (xstsResponse is null)
throw new FormatException("Response is null");
Expand All @@ -295,7 +297,9 @@ private async Task<string> AuthMinecraftAsync(XBLAuthenticateResponse xblRespons
}
catch (Exception e) when (e is FormatException || e is InvalidOperationException)
{
throw new AuthException("Error in authenticating with XBL\n" + JsonSerializer.Serialize(xblResponse));
throw new AuthException(
"Error in authenticating with XBL\n"
+ JsonSerializer.Serialize(xblResponse, AuthenticationJsonSerializerContext.Default.XBLAuthenticateResponse));
}

string requestContent = $"{{\"identityToken\":\"XBL3.0 x={x};{xstsToken}\"}}";
Expand Down Expand Up @@ -375,7 +379,7 @@ private async Task EnsureGameOwnershipAsync(string minecraftToken)
{
response = await responseMessage
.EnsureSuccessStatusCode().Content
.ReadFromJsonAsync<MicrosoftAuthenticationResponse>();
.ReadFromJsonAsync(AuthenticationJsonSerializerContext.Default.MicrosoftAuthenticationResponse);

// Check errors
if (response is null ||
Expand Down Expand Up @@ -410,7 +414,7 @@ private async Task<OAuth2DeviceCodeResponse> GetDeviceCodeAsync()
{
response = await responseMessage
.EnsureSuccessStatusCode().Content
.ReadFromJsonAsync<OAuth2DeviceCodeResponse>();
.ReadFromJsonAsync(AuthenticationJsonSerializerContext.Default.OAuth2DeviceCodeResponse);

if (response is null)
throw new FormatException("Response is null");
Expand Down Expand Up @@ -463,7 +467,7 @@ private async Task<DeviceFlowPollResult> PollDeviceFlowLoginAsync(string deviceC
{
oauthResponse = await responseMessage
.EnsureSuccessStatusCode().Content
.ReadFromJsonAsync<OAuth2TokenResponse>();
.ReadFromJsonAsync(AuthenticationJsonSerializerContext.Default.OAuth2TokenResponse);

if (oauthResponse is null)
throw new FormatException("Response is null");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,30 @@ public class YggdrasilLoginRequest
public Agent Agent { get; set; } = new Agent();

[JsonPropertyName("username")]
public required string UserName { get; set; }
[JsonRequired]
public string UserName { get; set; } = null!;

[JsonPropertyName("password")]
public required string Password { get; set; }
[JsonRequired]
public string Password { get; set; } = null!;

[JsonPropertyName("requestUser")]
public bool RequestUser { get; set; } = true;

[JsonPropertyName("clientToken")]
public required string ClientToken { get; set; }
[JsonRequired]
public string ClientToken { get; set; } = null!;
}

public class YggdrasilRefreshRequest
{
[JsonPropertyName("accessToken")]
public required string AccessToken { get; set; }
[JsonRequired]
public string AccessToken { get; set; } = null!;

[JsonPropertyName("clientToken")]
public required string ClientToken { get; set; }
[JsonRequired]
public string ClientToken { get; set; } = null!;

[JsonPropertyName("requestUser")]
public bool RequestUser { get; set; } = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ public async Task<YggdrasilAccount[]> LoginAsync(string email, string password)

using var response = await _httpClient.PostAsync(
$"{_serverUrl}/authserver/authenticate",
new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"));
new StringContent(
JsonSerializer.Serialize(request, AuthenticationJsonSerializerContext.Default.YggdrasilLoginRequest),
Encoding.UTF8,
"application/json")
);

return await ParseResponseAsync(response);
}
Expand All @@ -65,7 +69,10 @@ public async Task<YggdrasilAccount[]> RefreshAsync(YggdrasilAccount account)

using var response = await _httpClient.PostAsync(
$"{_serverUrl}/authserver/refresh",
new StringContent(JsonSerializer.Serialize(request), Encoding.UTF8, "application/json"));
new StringContent(JsonSerializer.Serialize(request, AuthenticationJsonSerializerContext.Default.YggdrasilRefreshRequest),
Encoding.UTF8,
"application/json")
);

return await ParseResponseAsync(response);
}
Expand All @@ -78,12 +85,12 @@ private async Task<YggdrasilAccount[]> ParseResponseAsync(HttpResponseMessage re
{
response = await responseMessage
.EnsureSuccessStatusCode().Content
.ReadFromJsonAsync<YggdrasilResponseModel>();
.ReadFromJsonAsync(AuthenticationJsonSerializerContext.Default.YggdrasilResponseModel);

if (response?.AvailableProfiles is null)
throw new FormatException("Response does not contain any profile");
}
catch (Exception e) // when (e is JsonException || e is FormatException)
catch (Exception)
{
throw new YggdrasilAuthenticationException(responseMessage.Content.ReadAsString());
}
Expand Down
Loading
Loading