Add configurable authlib-injector API path and HTTP support for Yggdrasil auth

Re-implements the changes from PR #2890, adapted for the current codebase
which uses System.Text.Json.Nodes and HttpClient instead of the legacy
Json.JSONData and hand-rolled SslStream HTTP client.

Changes:
- Settings.cs: Convert AuthlibServer from struct to class with
  [TomlDoNotInlineObject]; convert Host to a property that parses
  'host:port' syntax; add AuthlibInjectorAPIPath (default '/api/yggdrasil')
  for servers that use a different prefix (e.g. Drasl uses '/authlib-injector');
  add UseHttps (default true) so local/dev auth servers without TLS work.

- ConfigComments.resx: Add descriptive inline comments for the new
  AuthlibServer fields (Host, Port, AuthlibInjectorAPIPath, UseHttps).

- ProtocolHandler.cs: Replace three hardcoded '/api/yggdrasil/...' paths
  with AuthlibInjectorAPIPath-based paths (authenticate, refresh, join).
  Replace hand-rolled TcpClient+SslStream HTTP in DoHTTPSRequest with
  HttpClient+SocketsHttpHandler (ConnectCallback routes through ProxyHandler).
  Add useHttps parameter so HTTP-only auth servers are supported.

- KeyUtils.cs: Add AuthServerSupportsProfileKeys() that fetches the
  authlib-injector metadata endpoint and checks feature.enable_profile_key.
  Update GetNewProfileKeys() to skip key fetch when the auth server does not
  support profile keys; build the cert URL dynamically using AuthlibInjectorAPIPath
  for Yggdrasil; always fetch real certs instead of returning a dummy response.
  Remove MakeDummyResponse() which is no longer needed.

Tested against a local Drasl instance with authlib-injector 1.2.7 on a
1.21.11 Minecraft server — full auth flow (login, profile key fetch, session
join) confirmed working end-to-end.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Anon 2026-03-22 23:43:24 +01:00
parent 72ec3122ae
commit ff9aa62702
4 changed files with 188 additions and 142 deletions

View file

@ -495,7 +495,7 @@ namespace MinecraftClient
[TomlInlineComment("$Main.General.method$")]
public LoginMethod Method = LoginMethod.mcc;
[TomlInlineComment("$Main.General.AuthlibServer$")]
public AuthlibServer AuthServer = new(string.Empty);
public AuthlibServer AuthServer = new();
[TomlInlineComment("$Main.General.AuthlibUser$")]
public string AuthUser = "";
@ -709,34 +709,39 @@ namespace MinecraftClient
this.Port = Port;
}
}
public struct AuthlibServer
[TomlDoNotInlineObject]
public class AuthlibServer
{
public string Host = string.Empty;
public int Port = 443;
[NonSerialized]
private string _host = string.Empty;
public AuthlibServer()
[TomlInlineComment("$AuthlibServer.Host$")]
public string Host
{
Host = string.Empty;
Port = 443;
}
public AuthlibServer(string Host)
{
string[] sip = Host.Split(new[] { ":", "" }, StringSplitOptions.None);
this.Host = sip[0];
if (sip.Length > 1)
get => _host;
set
{
try { this.Port = Convert.ToUInt16(sip[1]); }
catch (FormatException) { }
string[] split = value.Split(new[] { ":", "" }, StringSplitOptions.None);
if (split.Length >= 1)
_host = split[0];
if (split.Length >= 2)
{
try { Port = Convert.ToUInt16(split[1]); }
catch (FormatException) { }
}
}
}
public AuthlibServer(string Host, ushort Port)
{
this.Host = Host.Split(new[] { ":", "" }, StringSplitOptions.None)[0];
this.Port = Port;
}
[TomlInlineComment("$AuthlibServer.Port$")]
public int Port = 443;
[TomlInlineComment("$AuthlibServer.AuthlibInjectorAPIPath$")]
public string AuthlibInjectorAPIPath = "/api/yggdrasil";
[TomlInlineComment("$AuthlibServer.UseHttps$")]
public bool UseHttps = true;
}
}
}