https and auth token rollover
This commit is contained in:
@@ -7,7 +7,8 @@ public static class Cupid
|
|||||||
{
|
{
|
||||||
private static string serverAddress;
|
private static string serverAddress;
|
||||||
public static string ServerAddress => 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;
|
private static int port;
|
||||||
public static int Port => port;
|
public static int Port => port;
|
||||||
@@ -24,10 +25,16 @@ public static class Cupid
|
|||||||
public static int RoomPort = -1;
|
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;
|
if (!TryBuildEndpoints(_serverAddress, _port, out serverAddress, out cupidBaseUri, out port))
|
||||||
port = _port;
|
{
|
||||||
|
Logger.Log("Cupid: invalid or empty server address.");
|
||||||
|
bearerToken = _bearerToken ?? "";
|
||||||
|
settings = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bearerToken = _bearerToken ?? "";
|
bearerToken = _bearerToken ?? "";
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(bearerToken))
|
if (string.IsNullOrEmpty(bearerToken))
|
||||||
@@ -37,7 +44,9 @@ public static class Cupid
|
|||||||
return;
|
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);
|
www.SetRequestHeader("Authorization", "Bearer " + bearerToken);
|
||||||
var operation = www.SendWebRequest();
|
var operation = www.SendWebRequest();
|
||||||
@@ -63,6 +72,13 @@ public static class Cupid
|
|||||||
return;
|
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);
|
settings = JsonUtility.FromJson<CupidSettings>(body);
|
||||||
if (settings == null) { throw new NullReferenceException(); }
|
if (settings == null) { throw new NullReferenceException(); }
|
||||||
Logger.Log("Cupid init success");
|
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{
|
public static string RandomUsername{
|
||||||
get{
|
get{
|
||||||
|
|||||||
@@ -15,8 +15,12 @@ public class CupidLobby : MonoBehaviour
|
|||||||
[SerializeField]private GameObject MatchmakingUI;
|
[SerializeField]private GameObject MatchmakingUI;
|
||||||
[SerializeField]private string GameScene;
|
[SerializeField]private string GameScene;
|
||||||
[Header("Server info (matchmaker port should match server settings.json)")]
|
[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";
|
[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;
|
[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).")]
|
[Tooltip("Used when LoginManager is absent or has no token (e.g. Cupid sample scene).")]
|
||||||
[SerializeField]private string bearerTokenFallback = "";
|
[SerializeField]private string bearerTokenFallback = "";
|
||||||
|
|
||||||
@@ -59,7 +63,7 @@ public class CupidLobby : MonoBehaviour
|
|||||||
: bearerTokenFallback;
|
: bearerTokenFallback;
|
||||||
if (LoginManager.instance != null && LoginManager.CurrentUser != null && !string.IsNullOrEmpty(LoginManager.CurrentUser.username))
|
if (LoginManager.instance != null && LoginManager.CurrentUser != null && !string.IsNullOrEmpty(LoginManager.CurrentUser.username))
|
||||||
m_username = LoginManager.CurrentUser.username;
|
m_username = LoginManager.CurrentUser.username;
|
||||||
Cupid.Init(serverAddress, cupidPort, token);
|
Cupid.Init(serverAddress, cupidPort, token, cupidPassword);
|
||||||
}
|
}
|
||||||
bool matchmaking = false;
|
bool matchmaking = false;
|
||||||
public void Matchmake()
|
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
@@ -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/25/2026 12:28:01 AM] Cupid init success
|
||||||
[4/21/2026 4:53:42 PM] 403 Unauthorized
|
[4/25/2026 12:28:06 AM] Starting matchmake as warlock
|
||||||
[4/21/2026 4:53:48 PM] Starting matchmake as warlock
|
[4/25/2026 12:28:16 AM] Cancelled matchmaking success
|
||||||
[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
|
|
||||||
|
|||||||
@@ -2228,8 +2228,8 @@ MonoBehaviour:
|
|||||||
m_EditorClassIdentifier:
|
m_EditorClassIdentifier:
|
||||||
MatchmakingUI: {fileID: 2042874254}
|
MatchmakingUI: {fileID: 2042874254}
|
||||||
GameScene: Game
|
GameScene: Game
|
||||||
serverAddress: vps.playpoolstudios.com
|
serverAddress: https://kickkingsapi.playpoolstudios.com
|
||||||
cupidPort: 2612
|
cupidPort: 0
|
||||||
bearerTokenFallback:
|
bearerTokenFallback:
|
||||||
--- !u!4 &613204348
|
--- !u!4 &613204348
|
||||||
Transform:
|
Transform:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ using UnityEngine.UI;
|
|||||||
|
|
||||||
public class LoginManager : MonoBehaviour
|
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 string PlayerPrefsAuthKey = "WalkInvest.AuthToken";
|
||||||
|
|
||||||
const int MIN_USERNAME_LENGTH = 3;
|
const int MIN_USERNAME_LENGTH = 3;
|
||||||
@@ -93,6 +93,9 @@ public class LoginManager : MonoBehaviour
|
|||||||
}
|
}
|
||||||
instance = this;
|
instance = this;
|
||||||
DontDestroyOnLoad(gameObject);
|
DontDestroyOnLoad(gameObject);
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(AuthToken))
|
||||||
|
ClearLocalUserProfile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Start()
|
void Start()
|
||||||
@@ -143,11 +146,43 @@ public class LoginManager : MonoBehaviour
|
|||||||
|
|
||||||
IEnumerator ResumeSessionCoroutine()
|
IEnumerator ResumeSessionCoroutine()
|
||||||
{
|
{
|
||||||
yield return StartCoroutine(FetchUserDataCoroutine(null, true));
|
ClearLocalUserProfile();
|
||||||
ProceedToMainMenu();
|
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);
|
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()
|
static void ProceedToMainMenu()
|
||||||
{
|
{
|
||||||
if (LevelLoadManager.instance != null)
|
if (LevelLoadManager.instance != null)
|
||||||
@@ -230,6 +265,7 @@ public class LoginManager : MonoBehaviour
|
|||||||
{
|
{
|
||||||
SetBusy(true);
|
SetBusy(true);
|
||||||
error_txt.text = "";
|
error_txt.text = "";
|
||||||
|
ClearLocalUserProfile();
|
||||||
|
|
||||||
using (var request = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST))
|
using (var request = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST))
|
||||||
{
|
{
|
||||||
@@ -265,8 +301,20 @@ public class LoginManager : MonoBehaviour
|
|||||||
PlayerPrefs.SetString(PlayerPrefsAuthKey, resp.token);
|
PlayerPrefs.SetString(PlayerPrefsAuthKey, resp.token);
|
||||||
PlayerPrefs.Save();
|
PlayerPrefs.Save();
|
||||||
|
|
||||||
yield return StartCoroutine(FetchUserDataCoroutine(null, true));
|
bool profileOk = false;
|
||||||
ProceedToMainMenu();
|
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
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,9 +52,17 @@ public class MainMenuManager : MonoBehaviour
|
|||||||
ccText.text = "";
|
ccText.text = "";
|
||||||
rcText.text = "";
|
rcText.text = "";
|
||||||
LoginManager.instance.GetUserData((success, error, user) => {
|
LoginManager.instance.GetUserData((success, error, user) => {
|
||||||
if(success){
|
if (success)
|
||||||
|
{
|
||||||
OnUserUpdated(user);
|
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));
|
btnBuyUsd5.onClick.AddListener(() => OnBuy(RcPack.Usd5));
|
||||||
@@ -75,11 +83,23 @@ public class MainMenuManager : MonoBehaviour
|
|||||||
btnPlay.onClick.AddListener(OnPlay);
|
btnPlay.onClick.AddListener(OnPlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnPlay(){
|
void OnPlay()
|
||||||
if(LoginManager.CurrentUser.rc < 21){
|
{
|
||||||
|
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");
|
Debug.LogError("Not enough RC to play");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (CupidLobby.instance == null)
|
||||||
|
{
|
||||||
|
Debug.LogError("Play blocked: CupidLobby is missing from this scene.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
CupidLobby.instance.Matchmake();
|
CupidLobby.instance.Matchmake();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ PlayerSettings:
|
|||||||
loadStoreDebugModeEnabled: 0
|
loadStoreDebugModeEnabled: 0
|
||||||
visionOSBundleVersion: 1.0
|
visionOSBundleVersion: 1.0
|
||||||
tvOSBundleVersion: 1.0
|
tvOSBundleVersion: 1.0
|
||||||
bundleVersion: 0.95
|
bundleVersion: 0.97
|
||||||
preloadedAssets:
|
preloadedAssets:
|
||||||
- {fileID: -944628639613478452, guid: 2bcd2660ca9b64942af0de543d8d7100, type: 3}
|
- {fileID: -944628639613478452, guid: 2bcd2660ca9b64942af0de543d8d7100, type: 3}
|
||||||
metroInputSource: 0
|
metroInputSource: 0
|
||||||
|
|||||||
Reference in New Issue
Block a user