Skip to content

Commit

Permalink
Make FluentCore AOT compatible (use source generation for JsonSeriali…
Browse files Browse the repository at this point in the history
…zer) (#38)

* Use source generation for Json serailization in Authentication

* Add source generation context for ClientJsonObject

* Add json source generation for installers

* Add json source generation for Resources

* Add json source generation for MinecraftInstance and Launch

* Use JsonObject instead of anonymous type in CurseForgeClient

* Add OptiFine client.json source generation

* Clean up csproj
  • Loading branch information
gaviny82 authored Aug 31, 2024
1 parent 4954791 commit 9ee4f84
Show file tree
Hide file tree
Showing 19 changed files with 267 additions and 106 deletions.
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

0 comments on commit 9ee4f84

Please sign in to comment.