mirror of
https://github.com/Empostor/Empostor.git
synced 2026-10-20 01:46:07 +00:00
Ume & Relay Api Add
This commit is contained in:
1 parent
d763ecd8c5
commit
6527e2e292
8 files changed
+271
-9
No files matched your search
@@ -150,6 +150,7 @@
|
|||||||
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
"System.Runtime.CompilerServices.Unsafe": "4.5.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
".NETStandard,Version=v2.0/win-x64": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,8 @@ public enum AuthApiMode
|
|||||||
Innersloth,
|
Innersloth,
|
||||||
Niko,
|
Niko,
|
||||||
Both,
|
Both,
|
||||||
|
Relay,
|
||||||
|
Ume,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AuthApiConfig
|
public class AuthApiConfig
|
||||||
@@ -16,4 +18,12 @@ public class AuthApiConfig
|
|||||||
public string NikoApiKey { get; set; } = "";
|
public string NikoApiKey { get; set; } = "";
|
||||||
|
|
||||||
public string NikoApiBaseUrl { get; set; } = "https://au-verify.niko233.top";
|
public string NikoApiBaseUrl { get; set; } = "https://au-verify.niko233.top";
|
||||||
|
|
||||||
|
public string RelayApiBaseUrl { get; set; } = "http://localhost:5100";
|
||||||
|
|
||||||
|
public string RelayApiKey { get; set; } = "";
|
||||||
|
|
||||||
|
public string UmeApiBaseUrl { get; set; } = "https://auverify.hayashiume.top";
|
||||||
|
|
||||||
|
public string UmeApiKey { get; set; } = "sk-empostor-globalapikey";
|
||||||
}
|
}
|
||||||
@@ -34,6 +34,12 @@
|
|||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.NET.ILLink.Tasks": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[8.0.27, )",
|
||||||
|
"resolved": "8.0.27",
|
||||||
|
"contentHash": "rQi9TxifHRnXP7lVRZH05DxD2/XGbJp12q0ozcbrlBlBnyyzssFTH/2vLhtKWUp2CT1qVscTrcYTFiwTyKPKRg=="
|
||||||
|
},
|
||||||
"StyleCop.Analyzers": {
|
"StyleCop.Analyzers": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[1.2.0-beta.556, )",
|
"requested": "[1.2.0-beta.556, )",
|
||||||
@@ -139,6 +145,7 @@
|
|||||||
"NextFast.Hazel.Abstractions": {
|
"NextFast.Hazel.Abstractions": {
|
||||||
"type": "Project"
|
"type": "Project"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"net8.0/win-x64": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,12 +155,52 @@ public sealed class TokenController : ControllerBase
|
|||||||
|
|
||||||
string? friendCode = null;
|
string? friendCode = null;
|
||||||
|
|
||||||
if (mode == AuthApiMode.Niko || mode == AuthApiMode.Both)
|
if (mode == AuthApiMode.Relay)
|
||||||
|
{
|
||||||
|
friendCode = await FetchFromRelayAsync(eosToken, productUserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(friendCode) && mode == AuthApiMode.Ume)
|
||||||
|
{
|
||||||
|
friendCode = await FetchFromUmeAsync(eosToken, productUserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(friendCode) && mode == AuthApiMode.Niko)
|
||||||
{
|
{
|
||||||
friendCode = await FetchFromNikoAsync(eosToken, productUserId);
|
friendCode = await FetchFromNikoAsync(eosToken, productUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(friendCode) && (mode == AuthApiMode.Innersloth || mode == AuthApiMode.Both))
|
if (string.IsNullOrEmpty(friendCode) && mode == AuthApiMode.Both)
|
||||||
|
{
|
||||||
|
var nikoKeyIsCustom = !string.IsNullOrEmpty(_authApiConfig.NikoApiKey)
|
||||||
|
&& _authApiConfig.NikoApiKey != "niko-request-api-key";
|
||||||
|
|
||||||
|
if (nikoKeyIsCustom)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("[TokenController] Both mode: trying Niko first (custom key)");
|
||||||
|
friendCode = await FetchFromNikoAsync(eosToken, productUserId);
|
||||||
|
if (string.IsNullOrEmpty(friendCode))
|
||||||
|
{
|
||||||
|
friendCode = await FetchFromUmeAsync(eosToken, productUserId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogDebug("[TokenController] Both mode: trying Ume first (default Niko key)");
|
||||||
|
friendCode = await FetchFromUmeAsync(eosToken, productUserId);
|
||||||
|
if (string.IsNullOrEmpty(friendCode))
|
||||||
|
{
|
||||||
|
friendCode = await FetchFromNikoAsync(eosToken, productUserId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(friendCode))
|
||||||
|
{
|
||||||
|
friendCode = await FetchFromInnerslothAsync(eosToken, productUserId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(friendCode) && mode == AuthApiMode.Innersloth)
|
||||||
{
|
{
|
||||||
friendCode = await FetchFromInnerslothAsync(eosToken, productUserId);
|
friendCode = await FetchFromInnerslothAsync(eosToken, productUserId);
|
||||||
}
|
}
|
||||||
@@ -172,8 +212,10 @@ public sealed class TokenController : ControllerBase
|
|||||||
"[TokenController] FriendCode fetch failed for PUID={Puid}, using fallback: {FC}",
|
"[TokenController] FriendCode fetch failed for PUID={Puid}, using fallback: {FC}",
|
||||||
productUserId, friendCode);
|
productUserId, friendCode);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
SaveFriendCodeToCache(productUserId, friendCode);
|
{
|
||||||
|
SaveFriendCodeToCache(productUserId, friendCode);
|
||||||
|
}
|
||||||
|
|
||||||
return friendCode;
|
return friendCode;
|
||||||
}
|
}
|
||||||
@@ -357,6 +399,15 @@ public sealed class TokenController : ControllerBase
|
|||||||
if (!string.IsNullOrEmpty(result.FriendCode)
|
if (!string.IsNullOrEmpty(result.FriendCode)
|
||||||
&& (result.VerifyStatus == "HttpPending" || result.VerifyStatus == "Verified"))
|
&& (result.VerifyStatus == "HttpPending" || result.VerifyStatus == "Verified"))
|
||||||
{
|
{
|
||||||
|
if (!string.IsNullOrEmpty(result.Puid)
|
||||||
|
&& !string.Equals(result.Puid, productUserId, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"[TokenController] Niko PUID mismatch: expected={Expected} got={Got}",
|
||||||
|
productUserId, result.Puid);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
_nikoFriendCodeConfirmed = true;
|
_nikoFriendCodeConfirmed = true;
|
||||||
_logger.LogInformation(
|
_logger.LogInformation(
|
||||||
"[TokenController] FriendCode fetched from Niko: PUID={Puid} FC={FC} Status={Status}",
|
"[TokenController] FriendCode fetched from Niko: PUID={Puid} FC={FC} Status={Status}",
|
||||||
@@ -430,6 +481,154 @@ public sealed class TokenController : ControllerBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<string?> FetchFromRelayAsync(string eosToken, string productUserId)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_authApiConfig.RelayApiBaseUrl)
|
||||||
|
|| string.IsNullOrEmpty(_authApiConfig.RelayApiKey))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("[TokenController] RelayApi config incomplete, skipping relay");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var client = _httpClientFactory.CreateClient("relay");
|
||||||
|
var body = JsonSerializer.SerializeToUtf8Bytes(new RelayVerifyRequest
|
||||||
|
{
|
||||||
|
EosToken = eosToken,
|
||||||
|
ProductUserId = productUserId,
|
||||||
|
});
|
||||||
|
|
||||||
|
var req = new HttpRequestMessage(HttpMethod.Post,
|
||||||
|
$"{_authApiConfig.RelayApiBaseUrl.TrimEnd('/')}/api/verify")
|
||||||
|
{
|
||||||
|
Content = new ByteArrayContent(body),
|
||||||
|
};
|
||||||
|
req.Headers.Authorization =
|
||||||
|
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _authApiConfig.RelayApiKey);
|
||||||
|
req.Content.Headers.TryAddWithoutValidation("Content-Type", "application/json");
|
||||||
|
|
||||||
|
var resp = await client.SendAsync(req);
|
||||||
|
if (!resp.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"[TokenController] Relay returned {Status} for PUID={Puid}",
|
||||||
|
resp.StatusCode, productUserId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var json = await resp.Content.ReadAsStringAsync();
|
||||||
|
var result = JsonSerializer.Deserialize<RelayVerifyResult>(json);
|
||||||
|
if (result == null || string.IsNullOrEmpty(result.FriendCode))
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"[TokenController] Relay response missing FriendCode for PUID={Puid}",
|
||||||
|
productUserId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(result.ProductUserId)
|
||||||
|
|| !string.Equals(result.ProductUserId, productUserId, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"[TokenController] Relay PUID mismatch: expected={Expected} got={Got}",
|
||||||
|
productUserId, result.ProductUserId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"[TokenController] FriendCode from Relay: PUID={Puid} FC={FC}",
|
||||||
|
productUserId, result.FriendCode);
|
||||||
|
return result.FriendCode;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "[TokenController] Exception calling Relay for PUID={Puid}", productUserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string?> FetchFromUmeAsync(string eosToken, string productUserId)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_authApiConfig.UmeApiBaseUrl)
|
||||||
|
|| string.IsNullOrEmpty(_authApiConfig.UmeApiKey))
|
||||||
|
{
|
||||||
|
_logger.LogWarning("[TokenController] UmeApi config incomplete, skipping Ume");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var client = _httpClientFactory.CreateClient("ume");
|
||||||
|
var body = JsonSerializer.SerializeToUtf8Bytes(new UmeVerifyRequest
|
||||||
|
{
|
||||||
|
ApiKey = _authApiConfig.UmeApiKey,
|
||||||
|
EosToken = eosToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
var req = new HttpRequestMessage(HttpMethod.Post,
|
||||||
|
$"{_authApiConfig.UmeApiBaseUrl.TrimEnd('/')}/api/verify")
|
||||||
|
{
|
||||||
|
Content = new ByteArrayContent(body),
|
||||||
|
};
|
||||||
|
req.Content.Headers.TryAddWithoutValidation("Content-Type", "application/json");
|
||||||
|
|
||||||
|
var resp = await client.SendAsync(req);
|
||||||
|
if (!resp.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"[TokenController] Ume returned {Status} for PUID={Puid}",
|
||||||
|
resp.StatusCode, productUserId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var json = await resp.Content.ReadAsStringAsync();
|
||||||
|
_logger.LogInformation("[TokenController] Ume raw response: {Json}", json);
|
||||||
|
using var doc = JsonDocument.Parse(json);
|
||||||
|
var root = doc.RootElement;
|
||||||
|
|
||||||
|
var status = root.TryGetProperty("VerifyStatus", out var s) ? s.GetString() : null;
|
||||||
|
if (status != "Verified")
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"[TokenController] Ume VerifyStatus={Status} for PUID={Puid}",
|
||||||
|
status, productUserId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var friendCode = root.TryGetProperty("FriendCode", out var fc) ? fc.GetString() : null;
|
||||||
|
if (string.IsNullOrEmpty(friendCode))
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"[TokenController] Ume response missing FriendCode for PUID={Puid}",
|
||||||
|
productUserId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var returnedPuid = root.TryGetProperty("ProductUserId", out var rp) ? rp.GetString() : null;
|
||||||
|
if (string.IsNullOrEmpty(returnedPuid)
|
||||||
|
|| !string.Equals(returnedPuid, productUserId, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"[TokenController] Ume PUID mismatch: expected={Expected} got={Got}",
|
||||||
|
productUserId, returnedPuid);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.LogInformation(
|
||||||
|
"[TokenController] FriendCode from Ume: PUID={Puid} FC={FC}",
|
||||||
|
productUserId, friendCode);
|
||||||
|
return friendCode;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "[TokenController] Exception calling Ume for PUID={Puid}", productUserId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private static string GenerateMatchmakerToken(string productUserId)
|
private static string GenerateMatchmakerToken(string productUserId)
|
||||||
{
|
{
|
||||||
var salt = RandomNumberGenerator.GetBytes(16);
|
var salt = RandomNumberGenerator.GetBytes(16);
|
||||||
@@ -523,5 +722,32 @@ public sealed class TokenController : ControllerBase
|
|||||||
[JsonPropertyName("verifycode")]
|
[JsonPropertyName("verifycode")]
|
||||||
public required string VerifyCode { get; init; }
|
public required string VerifyCode { get; init; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class RelayVerifyRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("EosToken")]
|
||||||
|
public required string EosToken { get; init; }
|
||||||
|
|
||||||
|
[JsonPropertyName("ProductUserId")]
|
||||||
|
public required string ProductUserId { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class RelayVerifyResult
|
||||||
|
{
|
||||||
|
[JsonPropertyName("FriendCode")]
|
||||||
|
public string? FriendCode { get; init; }
|
||||||
|
|
||||||
|
[JsonPropertyName("ProductUserId")]
|
||||||
|
public string? ProductUserId { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class UmeVerifyRequest
|
||||||
|
{
|
||||||
|
[JsonPropertyName("ApiKey")]
|
||||||
|
public required string ApiKey { get; init; }
|
||||||
|
|
||||||
|
[JsonPropertyName("EosToken")]
|
||||||
|
public required string EosToken { get; init; }
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@@ -47,12 +47,12 @@ namespace Empostor.Server.Net
|
|||||||
// NOTE: If this warning annoys you, set your PublicIp to "localhost"
|
// NOTE: If this warning annoys you, set your PublicIp to "localhost"
|
||||||
_logger.LogError("Your PublicIp is set to the default value of 127.0.0.1.");
|
_logger.LogError("Your PublicIp is set to the default value of 127.0.0.1.");
|
||||||
_logger.LogError("To allow people on other devices to connect to your server, change this value to your Public IP address");
|
_logger.LogError("To allow people on other devices to connect to your server, change this value to your Public IP address");
|
||||||
_logger.LogError("For more info on how to do this see https://github.com/Empostor/Empostor/blob/master/docs/Server-configuration.md");
|
_logger.LogError("For more info on how to do this see https://empostor.github.io/Server-configuration");
|
||||||
}
|
}
|
||||||
else if (_httpServerConfig.ListenIp == "0.0.0.0" && runningOutsideContainer)
|
else if (_httpServerConfig.ListenIp == "0.0.0.0" && runningOutsideContainer)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Since Among Us 16.0.5 it is required to support HTTPS for players to connect, we recommend setting up a reverse proxy:");
|
_logger.LogWarning("Since Among Us 16.0.5 it is required to support HTTPS for players to connect, we recommend setting up a reverse proxy:");
|
||||||
_logger.LogWarning("See https://github.com/Empostor/Empostor/blob/master/docs/Http-server.md for instructions");
|
_logger.LogWarning("See https://empostor.github.io/Http-server for instructions");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,14 @@ namespace Empostor.Server
|
|||||||
"UnityPlayer/2022.3.44f1 (UnityWebRequest/1.0, libcurl/7.84.0-DEV)");
|
"UnityPlayer/2022.3.44f1 (UnityWebRequest/1.0, libcurl/7.84.0-DEV)");
|
||||||
client.DefaultRequestHeaders.Add("X-Unity-Version", "2022.3.44f1");
|
client.DefaultRequestHeaders.Add("X-Unity-Version", "2022.3.44f1");
|
||||||
});
|
});
|
||||||
|
services.AddHttpClient("relay", client =>
|
||||||
|
{
|
||||||
|
client.Timeout = TimeSpan.FromSeconds(15);
|
||||||
|
});
|
||||||
|
services.AddHttpClient("ume", client =>
|
||||||
|
{
|
||||||
|
client.Timeout = TimeSpan.FromSeconds(15);
|
||||||
|
});
|
||||||
|
|
||||||
services.AddSingleton<ICompatibilityManager, CompatibilityManager>();
|
services.AddSingleton<ICompatibilityManager, CompatibilityManager>();
|
||||||
services.AddSingleton<ClientManager>();
|
services.AddSingleton<ClientManager>();
|
||||||
|
|||||||
@@ -39,7 +39,11 @@
|
|||||||
"AuthApi": {
|
"AuthApi": {
|
||||||
"Mode": "Both",
|
"Mode": "Both",
|
||||||
"NikoApiKey": "niko-request-api-key",
|
"NikoApiKey": "niko-request-api-key",
|
||||||
"NikoApiBaseUrl": "https://au-verify.niko233.top"
|
"NikoApiBaseUrl": "https://au-verify.niko233.top",
|
||||||
|
"RelayApiBaseUrl": "http://localhost:5100",
|
||||||
|
"RelayApiKey": "empostor-relay-api-key-change-me",
|
||||||
|
"UmeApiBaseUrl": "https://auverify.hayashiume.top",
|
||||||
|
"UmeApiKey": "sk-empostor-globalapikey"
|
||||||
},
|
},
|
||||||
"Admin": {
|
"Admin": {
|
||||||
"Password": "CHANGE-ME",
|
"Password": "CHANGE-ME",
|
||||||
|
|||||||
@@ -58,6 +58,12 @@
|
|||||||
"resolved": "8.0.1",
|
"resolved": "8.0.1",
|
||||||
"contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA=="
|
"contentHash": "X21b8D6z58EG34OMLH955750mFaEaGs5xLGe9Vyi3059Cgb3sk+p2k/JlQXaieEBRrk+SVlFzDei3Q6PdVzJOA=="
|
||||||
},
|
},
|
||||||
|
"Microsoft.NET.ILLink.Tasks": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[8.0.27, )",
|
||||||
|
"resolved": "8.0.27",
|
||||||
|
"contentHash": "rQi9TxifHRnXP7lVRZH05DxD2/XGbJp12q0ozcbrlBlBnyyzssFTH/2vLhtKWUp2CT1qVscTrcYTFiwTyKPKRg=="
|
||||||
|
},
|
||||||
"Serilog.Extensions.Hosting": {
|
"Serilog.Extensions.Hosting": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[8.0.0, )",
|
"requested": "[8.0.0, )",
|
||||||
|
|||||||
Reference in new issue
Block a user