https and auth token rollover

This commit is contained in:
2026-04-25 00:58:07 +05:30
parent 217dacb54c
commit 8bc14d5fff
9 changed files with 1159 additions and 76 deletions
+55 -5
View File
@@ -7,7 +7,8 @@ public static class Cupid
{
private static string serverAddress;
public static string ServerAddress => serverAddress;
public static string CupidURI => "http://" + serverAddress + ":" + port;
private static string cupidBaseUri;
public static string CupidURI => cupidBaseUri;
private static int port;
public static int Port => port;
@@ -24,10 +25,16 @@ public static class Cupid
public static int RoomPort = -1;
public static async Task Init(string _serverAddress, int _port, string _bearerToken)
public static async Task Init(string _serverAddress, int _port, string _bearerToken, string _settingsPassword)
{
serverAddress = _serverAddress;
port = _port;
if (!TryBuildEndpoints(_serverAddress, _port, out serverAddress, out cupidBaseUri, out port))
{
Logger.Log("Cupid: invalid or empty server address.");
bearerToken = _bearerToken ?? "";
settings = null;
return;
}
bearerToken = _bearerToken ?? "";
if (string.IsNullOrEmpty(bearerToken))
@@ -37,7 +44,9 @@ public static class Cupid
return;
}
using (UnityWebRequest www = UnityWebRequest.Get(CupidURI + "/settings"))
string settingsPassword = _settingsPassword ?? "";
string settingsUrl = CupidURI + "/settings?password=" + UnityWebRequest.EscapeURL(settingsPassword);
using (UnityWebRequest www = UnityWebRequest.Get(settingsUrl))
{
www.SetRequestHeader("Authorization", "Bearer " + bearerToken);
var operation = www.SendWebRequest();
@@ -63,6 +72,13 @@ public static class Cupid
return;
}
if (body.Trim() == "403 Unauthorized")
{
Logger.Log("Cupid settings: wrong or missing password query (server rejected /settings).");
settings = null;
return;
}
settings = JsonUtility.FromJson<CupidSettings>(body);
if (settings == null) { throw new NullReferenceException(); }
Logger.Log("Cupid init success");
@@ -76,6 +92,40 @@ public static class Cupid
}
}
/// <summary>
/// Plain host/IP + HTTP port, or an absolute URL (https://host with no port uses 443).
/// Sets <paramref name="hostOnly"/> for game client transport; <paramref name="baseUri"/> has no trailing slash.
/// </summary>
static bool TryBuildEndpoints(string input, int fallbackHttpPort, out string hostOnly, out string baseUri, out int resolvedPort)
{
hostOnly = "";
baseUri = "";
resolvedPort = fallbackHttpPort;
input = (input ?? "").Trim();
if (string.IsNullOrEmpty(input))
return false;
if (input.IndexOf("://", StringComparison.Ordinal) >= 0
&& Uri.TryCreate(input, UriKind.Absolute, out Uri uri)
&& (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps))
{
hostOnly = uri.Host;
string authority = uri.GetLeftPart(UriPartial.Authority);
string path = uri.AbsolutePath;
if (!string.IsNullOrEmpty(path) && path != "/")
baseUri = authority.TrimEnd('/') + path.TrimEnd('/');
else
baseUri = authority;
resolvedPort = uri.Port;
return true;
}
hostOnly = input;
baseUri = "http://" + input + ":" + fallbackHttpPort;
resolvedPort = fallbackHttpPort;
return true;
}
public static string RandomUsername{
get{
+5 -1
View File
@@ -15,8 +15,12 @@ public class CupidLobby : MonoBehaviour
[SerializeField]private GameObject MatchmakingUI;
[SerializeField]private string GameScene;
[Header("Server info (matchmaker port should match server settings.json)")]
[Tooltip("IP/hostname uses HTTP and cupidPort below. Or full URL: https://match.example.com (default 443, no :port in URL) or http://host/path.")]
[SerializeField]private string serverAddress = "xx.xx.xxx.xx";
[Tooltip("HTTP port when server address is not a full URL. Ignored for https:// or http:// URLs unless the URL includes an explicit port.")]
[SerializeField]private int cupidPort = 2612;
[Tooltip("Sent as the password query param on GET /settings (matchmaker settings.json).")]
[SerializeField]private string cupidPassword = "HelloWorld";
[Tooltip("Used when LoginManager is absent or has no token (e.g. Cupid sample scene).")]
[SerializeField]private string bearerTokenFallback = "";
@@ -59,7 +63,7 @@ public class CupidLobby : MonoBehaviour
: bearerTokenFallback;
if (LoginManager.instance != null && LoginManager.CurrentUser != null && !string.IsNullOrEmpty(LoginManager.CurrentUser.username))
m_username = LoginManager.CurrentUser.username;
Cupid.Init(serverAddress, cupidPort, token);
Cupid.Init(serverAddress, cupidPort, token, cupidPassword);
}
bool matchmaking = false;
public void Matchmake()
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+4 -40
View File
@@ -1,41 +1,5 @@
Logger initiated at 4/21/2026 4:53:42 PM
Logger initiated at 4/25/2026 12:28:01 AM
[4/21/2026 4:53:42 PM] Error retreiving settings from server JSON parse error: The document root must not follow by other values.
[4/21/2026 4:53:42 PM] 403 Unauthorized
[4/21/2026 4:53:48 PM] Starting matchmake as warlock
[4/21/2026 4:53:54 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:53:56 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:53:58 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:00 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:03 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:05 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:07 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:09 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:12 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:14 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:16 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:18 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:20 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:22 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:25 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:27 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:29 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:31 PM] Matchmaker poll failed: Received no data in response body:
[4/21/2026 4:54:58 PM] Got into a room
[4/21/2026 4:54:58 PM] {"Players":[{"Name":"warlock","LastSeen":1776770698919,"UserId":4,"l10_wins":0,"l10_losses":0}],"GameName":"soccar","Port":26035,"InitTime":1776770698919,"match_id":89,"your_team":"red"}
[4/21/2026 4:55:00 PM] Got into a room
[4/21/2026 4:55:00 PM] {"Players":[{"Name":"warlock","LastSeen":1776770698919,"UserId":4,"l10_wins":0,"l10_losses":0},{"Name":"warlock2","LastSeen":1776770699584,"UserId":5,"l10_wins":0,"l10_losses":2}],"GameName":"soccar","Port":26035,"InitTime":1776770698919,"match_id":89,"your_team":"red"}
[4/21/2026 4:55:00 PM] Configured dedicated match reporting for match id 89 with secret 38516e39d3406225b7c3015a66e5d25c54e9b2024c0755212122bdcea3e3a328 and internal api base http://vps.playpoolstudios.com:2612
[4/21/2026 4:55:00 PM] Setting cupid to load game scene
[4/21/2026 4:55:00 PM] Loading game scene
[4/21/2026 4:55:07 PM] Starting client at $vps.playpoolstudios.com:26035
[4/21/2026 4:55:23 PM] Selected team changed from Red to Blue
[4/21/2026 4:55:32 PM] Selected team changed from Blue to Red
[4/21/2026 4:55:38 PM] Selected team changed from Red to Blue
[4/21/2026 4:55:40 PM] Selected team changed from Blue to Red
[4/21/2026 4:55:40 PM] Score changed from 0 to 1
[4/21/2026 4:55:43 PM] Selected team changed from Red to Blue
[4/21/2026 4:55:48 PM] Selected team changed from Blue to Red
[4/21/2026 4:55:54 PM] Selected team changed from Red to Blue
[4/21/2026 4:55:56 PM] Score changed from 0 to 1
[4/21/2026 4:55:59 PM] Selected team changed from Blue to Red
[4/25/2026 12:28:01 AM] Cupid init success
[4/25/2026 12:28:06 AM] Starting matchmake as warlock
[4/25/2026 12:28:16 AM] Cancelled matchmaking success
+2 -2
View File
@@ -2228,8 +2228,8 @@ MonoBehaviour:
m_EditorClassIdentifier:
MatchmakingUI: {fileID: 2042874254}
GameScene: Game
serverAddress: vps.playpoolstudios.com
cupidPort: 2612
serverAddress: https://kickkingsapi.playpoolstudios.com
cupidPort: 0
bearerTokenFallback:
--- !u!4 &613204348
Transform:
+53 -5
View File
@@ -13,7 +13,7 @@ using UnityEngine.UI;
public class LoginManager : MonoBehaviour
{
public const string AuthBaseUrl = "http://vps.playpoolstudios.com:2612";
public const string AuthBaseUrl = "https://kickkingsapi.playpoolstudios.com";
const string PlayerPrefsAuthKey = "WalkInvest.AuthToken";
const int MIN_USERNAME_LENGTH = 3;
@@ -93,6 +93,9 @@ public class LoginManager : MonoBehaviour
}
instance = this;
DontDestroyOnLoad(gameObject);
if (string.IsNullOrEmpty(AuthToken))
ClearLocalUserProfile();
}
void Start()
@@ -143,11 +146,43 @@ public class LoginManager : MonoBehaviour
IEnumerator ResumeSessionCoroutine()
{
yield return StartCoroutine(FetchUserDataCoroutine(null, true));
ProceedToMainMenu();
ClearLocalUserProfile();
bool ok = false;
string errMsg = null;
yield return StartCoroutine(FetchUserDataCoroutine((success, err, _) =>
{
ok = success;
errMsg = err;
}, true));
if (ok)
ProceedToMainMenu();
else
{
InvalidateStoredSession();
if (error_txt != null)
error_txt.text = string.IsNullOrEmpty(errMsg) ? "Session expired. Please sign in again." : errMsg;
}
SetBusy(false);
}
/// <summary>Clears cached profile only (token unchanged). Call when leaving a broken state without wiping prefs.</summary>
static void ClearLocalUserProfile()
{
_currentUser = null;
}
/// <summary>Removes auth token from memory and disk and clears cached profile (login screen recovery).</summary>
static void InvalidateStoredSession()
{
AuthToken = "";
ClearLocalUserProfile();
ClearMatchYourTeam();
PlayerPrefs.DeleteKey(PlayerPrefsAuthKey);
PlayerPrefs.Save();
}
static void ProceedToMainMenu()
{
if (LevelLoadManager.instance != null)
@@ -230,6 +265,7 @@ public class LoginManager : MonoBehaviour
{
SetBusy(true);
error_txt.text = "";
ClearLocalUserProfile();
using (var request = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST))
{
@@ -265,8 +301,20 @@ public class LoginManager : MonoBehaviour
PlayerPrefs.SetString(PlayerPrefsAuthKey, resp.token);
PlayerPrefs.Save();
yield return StartCoroutine(FetchUserDataCoroutine(null, true));
ProceedToMainMenu();
bool profileOk = false;
string profileErr = null;
yield return StartCoroutine(FetchUserDataCoroutine((success, err, _) =>
{
profileOk = success;
profileErr = err;
}, true));
if (profileOk)
ProceedToMainMenu();
else if (error_txt != null)
error_txt.text = string.IsNullOrEmpty(profileErr)
? "Signed in but could not load your profile. Check your connection and try again."
: profileErr;
}
else
{
+23 -3
View File
@@ -52,9 +52,17 @@ public class MainMenuManager : MonoBehaviour
ccText.text = "";
rcText.text = "";
LoginManager.instance.GetUserData((success, error, user) => {
if(success){
if (success)
{
OnUserUpdated(user);
}
else
{
if (btnPlay != null)
btnPlay.interactable = false;
if (rcPlayText != null)
rcPlayText.text = string.IsNullOrEmpty(error) ? "Could not load profile. Try again." : error;
}
});
btnBuyUsd5.onClick.AddListener(() => OnBuy(RcPack.Usd5));
@@ -75,11 +83,23 @@ public class MainMenuManager : MonoBehaviour
btnPlay.onClick.AddListener(OnPlay);
}
void OnPlay(){
if(LoginManager.CurrentUser.rc < 21){
void OnPlay()
{
if (LoginManager.CurrentUser == null)
{
Debug.LogError("Play blocked: user profile not loaded.");
return;
}
if (LoginManager.CurrentUser.rc < 21)
{
Debug.LogError("Not enough RC to play");
return;
}
if (CupidLobby.instance == null)
{
Debug.LogError("Play blocked: CupidLobby is missing from this scene.");
return;
}
CupidLobby.instance.Matchmake();
}
+1 -1
View File
@@ -141,7 +141,7 @@ PlayerSettings:
loadStoreDebugModeEnabled: 0
visionOSBundleVersion: 1.0
tvOSBundleVersion: 1.0
bundleVersion: 0.95
bundleVersion: 0.97
preloadedAssets:
- {fileID: -944628639613478452, guid: 2bcd2660ca9b64942af0de543d8d7100, type: 3}
metroInputSource: 0