Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 41 additions & 5 deletions GenOnlineService/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,18 @@ public static class Constants
}
public class RoomMember
{
public RoomMember(Int64 a_UserID, string strName, bool admin)
public RoomMember(Int64 a_UserID, string strName, bool admin, string platform)
{
UserID = a_UserID;
Name = strName;
IsAdmin = admin;
Platform = platform;
}

public Int64 UserID { get; set; } = -1;
public String Name { get; set; } = String.Empty;
public bool IsAdmin { get; set; } = false;
public String Platform { get; set; } = Platforms.Unknown;
}

public enum EPendingLoginState
Expand Down Expand Up @@ -188,13 +190,45 @@ public enum EKnownClients
};
}

// The platform is self-reported by the client and echoed back to every other
// member of a lobby, so it is clamped to a known set rather than passed through.
public static class Platforms
{
public const string Unknown = "unknown";
public const string Windows = "windows";
public const string MacOS = "macos";

private static readonly HashSet<string> Known = new(StringComparer.OrdinalIgnoreCase)
{
Windows,
MacOS
};

public static string Normalize(string? platform)
{
if (String.IsNullOrWhiteSpace(platform))
{
return Unknown;
}

string trimmed = platform.Trim();

if (!Known.Contains(trimmed))
{
return Unknown;
}

return trimmed.ToLowerInvariant();
}
}



// TODO
static class WebSocketManager
{
public static int g_PeakConnectionCount = 0;
public static async Task<UserWebSocketInstance> CreateSession(AppDbContext _db, EUserSessionType sessionType, bool bIsReconnect, Int64 ownerID, KnownClients.EKnownClients client_id, string ipAddr, string strContinent, string strCountry, double dLatitude, double dLongitude, bool bIsAdmin)
public static async Task<UserWebSocketInstance> CreateSession(AppDbContext _db, EUserSessionType sessionType, bool bIsReconnect, Int64 ownerID, KnownClients.EKnownClients client_id, string ipAddr, string strContinent, string strCountry, double dLatitude, double dLongitude, bool bIsAdmin, string platform)
{
string strDisplayName = await Database.Users.GetDisplayName(_db, ownerID);

Expand Down Expand Up @@ -266,7 +300,7 @@ public static async Task<UserWebSocketInstance> CreateSession(AppDbContext _db,
// get stats
PlayerStats GameStats = await Database.UserStats.GetPlayerStats(_db, ownerID);

userCacheData = new UserSession(ownerID, sessionType, client_id, strContinent, strCountry, dLatitude, dLongitude);
userCacheData = new UserSession(ownerID, sessionType, client_id, strContinent, strCountry, dLatitude, dLongitude, platform);
m_dictUserSessions[sessionType][ownerID] = userCacheData;

// TODO_SOCIAL: Move this to a class
Expand Down Expand Up @@ -781,7 +815,7 @@ public static async Task TickRoomMemberList()
}


memberListUpdate.members.Add(new RoomMember(sess.m_UserID, strDisplayName, sharedUserData.IsAdmin()));
memberListUpdate.members.Add(new RoomMember(sess.m_UserID, strDisplayName, sharedUserData.IsAdmin(), sess.Platform));

// also add to list of users who need this update, since they were in there
lstUsersToSend.Add(sess.m_UserID);
Expand Down Expand Up @@ -899,6 +933,7 @@ public class UserSession
private string m_strMiddlewareUserID = String.Empty;

public KnownClients.EKnownClients m_client_id = KnownClients.EKnownClients.unknown;
public string Platform { get; private set; } = Platforms.Unknown;
DateTime m_CreateTime = DateTime.Now;
public DateTime GetCreationTime()
{
Expand Down Expand Up @@ -936,14 +971,15 @@ public TimeSpan GetDuration()
return DateTime.Now - m_CreateTime;
}

public UserSession(Int64 ownerID, EUserSessionType sessionType, KnownClients.EKnownClients client_id, string strContinent, string strCountry, double dLatitude, double dLongitude)
public UserSession(Int64 ownerID, EUserSessionType sessionType, KnownClients.EKnownClients client_id, string strContinent, string strCountry, double dLatitude, double dLongitude, string platform)
{
m_sessionType = sessionType;
m_client_id = client_id;
m_strContinent = strContinent;
m_strCountry = strCountry;
m_dLatitude = dLatitude;
m_dLongitude = dLongitude;
Platform = platform;

m_UserID = ownerID;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,10 @@ public async Task<APIResult> Post_InternalHandler(string jsonData, string ipAddr
string exe_crc = data.ContainsKey("exe_crc") ? data["exe_crc"].ToString() : "NONE";
Helpers.RegisterInitialPlayerExeCRC(user_id, exe_crc);

var sessiontoken = Program.g_tokenGenerator.GenerateToken(strDisplayName, user_id, ipAddr, Program.JwtTokenGenerator.ETokenType.Session, knownClientID, sessionType, bIsAdmin);
var refreshtoken = Program.g_tokenGenerator.GenerateToken(strDisplayName, user_id, ipAddr, Program.JwtTokenGenerator.ETokenType.Refresh, knownClientID, sessionType, false, out string refreshJti);
string platform = data.ContainsKey("platform") ? data["platform"].ToString() : Platforms.Unknown;

var sessiontoken = Program.g_tokenGenerator.GenerateToken(strDisplayName, user_id, ipAddr, Program.JwtTokenGenerator.ETokenType.Session, knownClientID, sessionType, bIsAdmin, platform);
var refreshtoken = Program.g_tokenGenerator.GenerateToken(strDisplayName, user_id, ipAddr, Program.JwtTokenGenerator.ETokenType.Refresh, knownClientID, sessionType, false, platform, out string refreshJti);

// rotation: only this refresh token is accepted from now on
await TokenRevocationManager.OnTokensIssued(user_id, sessionType, refreshJti);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ public async Task<APIResult> Post_InternalHandler(string jsonData, string ipAddr
string exe_crc = data.ContainsKey("exe_crc") ? data["exe_crc"].ToString() : "NONE";
Helpers.RegisterInitialPlayerExeCRC(user_id, exe_crc);

string platform = data.ContainsKey("platform") ? data["platform"].ToString() : Platforms.Unknown;

string strDisplayName = await Database.Users.GetDisplayName(db, user_id);
await SessionHelpers.SetUsedLoggedIn(user_id, clientID, sessionType);

Expand All @@ -152,8 +154,8 @@ public async Task<APIResult> Post_InternalHandler(string jsonData, string ipAddr

// extend token
// TODO_TODAY_JWT: just get clientID from token
var sessiontoken = Program.g_tokenGenerator.GenerateToken(strDisplayName, user_id, ipAddr, Program.JwtTokenGenerator.ETokenType.Session, clientID, sessionType, bIsAdmin);
var refreshtoken = Program.g_tokenGenerator.GenerateToken(strDisplayName, user_id, ipAddr, Program.JwtTokenGenerator.ETokenType.Refresh, clientID, sessionType, false, out string refreshJti);
var sessiontoken = Program.g_tokenGenerator.GenerateToken(strDisplayName, user_id, ipAddr, Program.JwtTokenGenerator.ETokenType.Session, clientID, sessionType, bIsAdmin, platform);
var refreshtoken = Program.g_tokenGenerator.GenerateToken(strDisplayName, user_id, ipAddr, Program.JwtTokenGenerator.ETokenType.Refresh, clientID, sessionType, false, platform, out string refreshJti);

// rotation: only this refresh token is accepted from now on
await TokenRevocationManager.OnTokensIssued(user_id, sessionType, refreshJti);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,11 @@ public async Task<APIResult> Post_InternalHandler(string ipAddr)
string strDisplayName = await Database.Users.GetDisplayName(db, user_id);
bool bIsAdmin = await Database.Users.IsUserAdmin(db, user_id);

var sessiontoken = Program.g_tokenGenerator.GenerateToken(strDisplayName, user_id, ipAddr, Program.JwtTokenGenerator.ETokenType.Session, clientID, sessionType, bIsAdmin);
var refreshtoken = Program.g_tokenGenerator.GenerateToken(strDisplayName, user_id, ipAddr, Program.JwtTokenGenerator.ETokenType.Refresh, clientID, sessionType, false, out string refreshJti);
// carried over from the token being rotated, so the platform survives a refresh
string platform = TokenHelper.GetPlatform(this);

var sessiontoken = Program.g_tokenGenerator.GenerateToken(strDisplayName, user_id, ipAddr, Program.JwtTokenGenerator.ETokenType.Session, clientID, sessionType, bIsAdmin, platform);
var refreshtoken = Program.g_tokenGenerator.GenerateToken(strDisplayName, user_id, ipAddr, Program.JwtTokenGenerator.ETokenType.Refresh, clientID, sessionType, false, platform, out string refreshJti);

// rotation: only this refresh token is accepted from now on
await TokenRevocationManager.OnTokensIssued(user_id, sessionType, refreshJti);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ public async Task Get([FromHeader(Name = "is-reconnect")] bool bIsReconnect)
}

EUserSessionType sessType = TokenHelper.GetSessionType(this);
string platform = TokenHelper.GetPlatform(this);

await using var db = await _dbFactory.CreateDbContextAsync();
UserWebSocketInstance wsSess = await WebSocketManager.CreateSession(
Expand All @@ -157,7 +158,8 @@ public async Task Get([FromHeader(Name = "is-reconnect")] bool bIsReconnect)
ipCountry,
dLatitude,
dLongitude,
bIsAdmin);
bIsAdmin,
platform);

// if null, it was probably a reconnect and they need to fully reconnect, so return an error instead
if (wsSess == null)
Expand Down
2 changes: 2 additions & 0 deletions GenOnlineService/LobbyManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1298,6 +1298,7 @@ public void UpdateSlotIndex(UInt16 index)
public EPlayerType SlotState { get; private set; } = 0;
public UInt16 SlotIndex { get; private set; } = 0;
public string Region { get; private set; } = "Unknown";
public string Platform { get; private set; } = Platforms.Unknown;
public string MiddlewareUserID { get; private set; } = String.Empty;

[JsonIgnore] // cant serialize refs
Expand Down Expand Up @@ -1339,6 +1340,7 @@ public LobbyMember(Lobby owningLobby, UserSession? owningSession, Int64 UserID_i

IsReady = false;
Region = owningSession == null ? "Unknown" : owningSession.GetFullContinentName();
Platform = owningSession == null ? Platforms.Unknown : owningSession.Platform;
}

public bool IsHuman() { return SlotState == EPlayerType.SLOT_PLAYER; }
Expand Down
18 changes: 15 additions & 3 deletions GenOnlineService/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,16 @@ public static EUserSessionType GetSessionType(ControllerBase controller)
return EUserSessionType.None;
}

public static string GetPlatform(ControllerBase controller)
{
var first = controller.User.FindFirst(Program.JwtTokenGenerator.PlatformClaim);

if (first == null)
return Platforms.Unknown;

return Platforms.Normalize(first.Value);
}

public static string GetDisplayName(ControllerBase controller)
{
// TODO: Handle not finding claims, it is a critical error
Expand Down Expand Up @@ -710,13 +720,14 @@ public enum ETokenType
}

public const string TokenGenerationClaim = "tgen";
public const string PlatformClaim = "platform";

public string GenerateToken(string displayname, Int64 userID, string ipAddr, ETokenType tokenType, KnownClients.EKnownClients knownClientID, EUserSessionType sessionType, bool bIsAdmin)
public string GenerateToken(string displayname, Int64 userID, string ipAddr, ETokenType tokenType, KnownClients.EKnownClients knownClientID, EUserSessionType sessionType, bool bIsAdmin, string platform)
{
return GenerateToken(displayname, userID, ipAddr, tokenType, knownClientID, sessionType, bIsAdmin, out _);
return GenerateToken(displayname, userID, ipAddr, tokenType, knownClientID, sessionType, bIsAdmin, platform, out _);
}

public string GenerateToken(string displayname, Int64 userID, string ipAddr, ETokenType tokenType, KnownClients.EKnownClients knownClientID, EUserSessionType sessionType, bool bIsAdmin, out string jti)
public string GenerateToken(string displayname, Int64 userID, string ipAddr, ETokenType tokenType, KnownClients.EKnownClients knownClientID, EUserSessionType sessionType, bool bIsAdmin, string platform, out string jti)
{
var jwtSettings = _configuration.GetSection("JwtSettings");

Expand Down Expand Up @@ -745,6 +756,7 @@ public string GenerateToken(string displayname, Int64 userID, string ipAddr, ETo
new Claim(JwtRegisteredClaimNames.Typ, ((int)tokenType).ToString()),
new Claim("client_id", ((int)knownClientID).ToString()),
new Claim("session_type", ((int)sessionType).ToString()),
new Claim(PlatformClaim, Platforms.Normalize(platform)),

// Token generation, checked against the revocation manager on every request so
// that bans/logouts can invalidate tokens before they naturally expire.
Expand Down
Loading