Skip to content

Commit

Permalink
Implement NpTicket Game Authentication (#141)
Browse files Browse the repository at this point in the history
  • Loading branch information
turecross321 committed Aug 29, 2023
1 parent 0a85293 commit e12faea
Show file tree
Hide file tree
Showing 31 changed files with 377 additions and 275 deletions.
8 changes: 1 addition & 7 deletions SoundShapesServer/Configuration/GameServerConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace SoundShapesServer.Configuration;

public class GameServerConfig : Config
{
public override int CurrentConfigVersion => 4;
public override int CurrentConfigVersion => 5;
public override int Version { get; set; }

protected override void Migrate(int oldVer, dynamic oldConfig)
Expand All @@ -14,11 +14,6 @@ protected override void Migrate(int oldVer, dynamic oldConfig)
{
RequireAuthentication = (bool)oldConfig.ApiAuthentication;
}

if (CurrentConfigVersion < 4)
{
RateLimitSettings.Bucket = RateLimitSettings.DefaultBucket;
}
}

public string EulaText { get; set; } = "Welcome back to Sound Shapes!";
Expand All @@ -31,5 +26,4 @@ protected override void Migrate(int oldVer, dynamic oldConfig)
public string EmailHost { get; set; } = "smtp.gmail.com";
public int EmailHostPort { get; set; } = 587;
public bool EmailSsl { get; set; } = true;
public RateLimitSettings RateLimitSettings = new (30, 400, 0, RateLimitSettings.DefaultBucket);
}
104 changes: 104 additions & 0 deletions SoundShapesServer/Database/GameDatabaseContext.GameIps.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
using SoundShapesServer.Helpers;
using SoundShapesServer.Types;
using SoundShapesServer.Types.Sessions;
using SoundShapesServer.Types.Users;

namespace SoundShapesServer.Database;

public partial class GameDatabaseContext
{
private GameIp CreateIpAddress(GameUser user, string ipAddress)
{
GameIp gameIp = new(ipAddress, user);

_realm.Write(() =>
{
_realm.Add(gameIp);
});

return gameIp;
}

public GameIp GetIpFromAddress(GameUser user, string ipAddress)
{
_realm.Refresh();

GameIp? ip = user.IpAddresses.FirstOrDefault(i => i.IpAddress == ipAddress);
return ip ?? CreateIpAddress(user, ipAddress);
}
public bool AuthorizeIpAddress(GameIp gameIp, bool oneTime)
{
if (gameIp.Authorized) return false;

_realm.Write(() =>
{
gameIp.Authorized = true;
gameIp.OneTimeUse = oneTime;
gameIp.ModificationDate = DateTimeOffset.UtcNow;
foreach (GameSession session in gameIp.Sessions.Where(s=>s._SessionType == (int)SessionType.GameUnAuthorized))
{
session.SessionType = SessionType.Game;
}
});

_realm.Refresh();

return true;
}

public void RemoveIpAddress(GameIp gameIp)
{
_realm.Write(() =>
{
// Remove all sessions with ip address
foreach (GameSession session in gameIp.Sessions)
{
_realm.Remove(session);
}
_realm.Remove(gameIp);
});

_realm.Refresh();
}

public void UseOneTimeIpAddress(GameIp gameIp)
{
_realm.Write(() =>
{
gameIp.Authorized = false;
gameIp.OneTimeUse = false;
gameIp.ModificationDate = DateTimeOffset.UtcNow;
});
}

public (GameIp[], int) GetPaginatedIps(GameUser user, bool? authorized, int from, int count)
{
IQueryable<GameIp> filteredAddresses = GetIps(user, authorized);
GameIp[] paginatedAddresses = PaginationHelper.PaginateIpAddresses(filteredAddresses, from, count);

return (paginatedAddresses, filteredAddresses.Count());
}

private IQueryable<GameIp> GetIps(GameUser user, bool? authorized)
{
IQueryable<GameIp> addresses = _realm.All<GameIp>().Where(i => i.User == user);
IQueryable<GameIp> filteredAddresses = FilterIpAddresses(addresses, authorized);

return filteredAddresses;
}

private static IQueryable<GameIp> FilterIpAddresses(IQueryable<GameIp> addresses,
bool? authorized)
{
IQueryable<GameIp> response = addresses;

if (authorized != null)
{
response = response.Where(i => i.Authorized == authorized);
}

return response;
}
}
106 changes: 0 additions & 106 deletions SoundShapesServer/Database/GameDatabaseContext.IpAuthorizations.cs

This file was deleted.

11 changes: 3 additions & 8 deletions SoundShapesServer/Database/GameDatabaseContext.Sessions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public partial class GameDatabaseContext
public const int DefaultSessionExpirySeconds = Globals.OneDayInSeconds;
private const int SimultaneousSessionsLimit = 3;

public GameSession CreateSession(GameUser user, SessionType sessionType, PlatformType platformType, int? expirationSeconds = null, string? id = null, IpAuthorization? ip = null)
public GameSession CreateSession(GameUser user, SessionType sessionType, PlatformType platformType, bool? genuineTicket = null, int? expirationSeconds = null, string? id = null)
{
double sessionExpirationSeconds = expirationSeconds ?? DefaultSessionExpirySeconds;
id ??= GenerateGuid();
Expand All @@ -20,9 +20,9 @@ public GameSession CreateSession(GameUser user, SessionType sessionType, Platfor
User = user,
SessionType = sessionType,
PlatformType = platformType,
Ip = ip,
ExpiryDate = DateTimeOffset.UtcNow.AddSeconds(sessionExpirationSeconds),
CreationDate = DateTimeOffset.UtcNow
CreationDate = DateTimeOffset.UtcNow,
GenuineNpTicket = genuineTicket
};

IEnumerable<GameSession> sessionsToDelete = _realm.All<GameSession>()
Expand All @@ -47,11 +47,6 @@ public GameSession CreateSession(GameUser user, SessionType sessionType, Platfor
return session;
}

private IEnumerable<GameSession> GetSessionsWithIp(IpAuthorization ip)
{
return _realm.All<GameSession>().Where(s => s.Ip == ip);
}

public void RemoveSession(GameSession session)
{
_realm.Write(() =>
Expand Down
15 changes: 15 additions & 0 deletions SoundShapesServer/Database/GameDatabaseContext.Users.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using Bunkum.HttpServer.Storage;
using SoundShapesServer.Requests.Api;
using SoundShapesServer.Types;
using SoundShapesServer.Types.Events;
using SoundShapesServer.Types.Levels;
using SoundShapesServer.Types.Relations;
using SoundShapesServer.Types.Sessions;
using SoundShapesServer.Types.Users;
using static SoundShapesServer.Helpers.PaginationHelper;

Expand Down Expand Up @@ -160,6 +162,19 @@ public void SetFeaturedLevel(GameUser user, GameLevel level)
user.FeaturedLevel = level;
});
}

public void SetUserGameAuthenticationSettings(GameUser user, ApiSetGameAuthenticationSettingsRequest request)
{
_realm.Write(() =>
{
if (user.AllowIpAuthentication && !request.AllowIpAuthentication)
_realm.RemoveRange(user.IpAddresses);
user.AllowPsnAuthentication = request.AllowPsnAuthentication;
user.AllowRpcnAuthentication = request.AllowRpcnAuthentication;
user.AllowIpAuthentication = request.AllowIpAuthentication;
});
}

public GameUser? GetUserWithUsername(string username, bool includeDeleted = false)
{
Expand Down
25 changes: 18 additions & 7 deletions SoundShapesServer/Database/GameDatabaseProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace SoundShapesServer.Database;

public class GameDatabaseProvider : RealmDatabaseProvider<GameDatabaseContext>
{
protected override ulong SchemaVersion => 59;
protected override ulong SchemaVersion => 62;

protected override List<Type> SchemaTypes => new()
{
Expand All @@ -27,7 +27,7 @@ public class GameDatabaseProvider : RealmDatabaseProvider<GameDatabaseContext>
typeof(LevelPlayRelation),
typeof(LevelUniquePlayRelation),
typeof(GameUser),
typeof(IpAuthorization),
typeof(GameIp),
typeof(GameSession),
typeof(GameLevel),
typeof(NewsEntry),
Expand Down Expand Up @@ -92,12 +92,12 @@ protected override void Migrate(Migration migration, ulong oldVersion)

IQueryable<dynamic> oldLevels = migration.OldRealm.DynamicApi.All("GameLevel");
IQueryable<GameLevel> newLevels = migration.NewRealm.All<GameLevel>();
for (int i = 0; i < newLevels.Count(); i++)
if (oldVersion < 59)
{
GameLevel newLevel = newLevels.ElementAt(i);

if (oldVersion < 59)
for (int i = 0; i < newLevels.Count(); i++)
{
GameLevel newLevel = newLevels.ElementAt(i);

Console.WriteLine("Performing Level UploadPlatform Migration. This may take a while. (" + i + "/" + newLevels.Count() + ")");
// Implemented UploadPlatform
newLevel.UploadPlatform = PlatformType.Unknown;
Expand All @@ -123,7 +123,7 @@ protected override void Migrate(Migration migration, ulong oldVersion)
{
GameSession newSession = newSessions.ElementAt(i);

if (oldVersion < 40)
if (oldVersion < 62)
{
migration.NewRealm.Remove(newSession);
}
Expand Down Expand Up @@ -278,5 +278,16 @@ protected override void Migrate(Migration migration, ulong oldVersion)
newLevel.ModificationDate = newLevel.Date;
}
}

IQueryable<GameIp> newIps = migration.NewRealm.All<GameIp>();
for (int i = 0; i < newIps.Count(); i++)
{
GameIp newIp = newIps.ElementAt(i);

if (oldVersion < 62)
{
migration.NewRealm.Remove(newIp);
}
}
}
}
2 changes: 1 addition & 1 deletion SoundShapesServer/Documentation/Errors/ConflictError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ public class ConflictError
public const string AlreadyLikedLevelWhen = "You have already liked this level.";
public const string AlreadyQueuedLevelWhen = "You have already queued this level.";
public const string AlreadyFollowingWhen = "You are already following this user.";
public const string AlreadyAuthorizedIpWhen = "You have already authorized this IP.";
public const string AlreadyAuthenticatedIpWhen = "You have already authenticated this IP.";
}
Loading

0 comments on commit e12faea

Please sign in to comment.