mirror of
https://github.com/EpinelPS/EpinelPS.git
synced 2025-12-12 15:04:36 +01:00
implement client side session mangement
This commit is contained in:
@@ -2,6 +2,8 @@
|
||||
using EpinelPS.StaticInfo;
|
||||
using EpinelPS.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using Paseto.Builder;
|
||||
using Paseto;
|
||||
|
||||
namespace EpinelPS.Database
|
||||
{
|
||||
@@ -121,7 +123,7 @@ namespace EpinelPS.Database
|
||||
public NetJukeboxLocation Location;
|
||||
public NetJukeboxBgmType Type;
|
||||
public int TableId;
|
||||
|
||||
|
||||
}
|
||||
public class User
|
||||
{
|
||||
@@ -138,7 +140,7 @@ namespace EpinelPS.Database
|
||||
public bool ProfileIconIsPrism = false;
|
||||
public int ProfileFrame = 25;
|
||||
public bool IsAdmin = false;
|
||||
public bool sickpulls = false;
|
||||
public bool sickpulls = false;
|
||||
public bool IsBanned = false;
|
||||
public DateTime BanStart;
|
||||
public DateTime BanEnd;
|
||||
@@ -168,7 +170,7 @@ namespace EpinelPS.Database
|
||||
public NetWallpaperJukeboxFavorite[] WallpaperFavoriteList = [];
|
||||
public NetWallpaperPlaylist[] WallpaperPlaylistList = [];
|
||||
public NetWallpaperJukebox[] WallpaperJukeboxList = [];
|
||||
|
||||
|
||||
|
||||
public Dictionary<int, NetUserTeamData> UserTeams = new Dictionary<int, NetUserTeamData>();
|
||||
public Dictionary<int, bool> MainQuestData = new();
|
||||
@@ -188,7 +190,7 @@ namespace EpinelPS.Database
|
||||
|
||||
public Dictionary<int, int> TowerProgress = new Dictionary<int, int>();
|
||||
|
||||
public JukeBoxSetting LobbyMusic = new() { Location = NetJukeboxLocation.NetJukeboxLocationLobby, TableId = 2, Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId};
|
||||
public JukeBoxSetting LobbyMusic = new() { Location = NetJukeboxLocation.NetJukeboxLocationLobby, TableId = 2, Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId };
|
||||
public JukeBoxSetting CommanderMusic = new() { Location = NetJukeboxLocation.NetJukeboxLocationCommanderRoom, TableId = 5, Type = NetJukeboxBgmType.NetJukeboxBgmTypeJukeboxTableId };
|
||||
|
||||
// Event data
|
||||
@@ -343,8 +345,9 @@ namespace EpinelPS.Database
|
||||
|
||||
public List<AccessToken> LauncherAccessTokens = [];
|
||||
|
||||
public Dictionary<string, GameClientInfo> GameClientTokens = [];
|
||||
public string ServerName = "<color=\"green\">Private Server</color>";
|
||||
public byte[] LauncherTokenKey = [];
|
||||
public byte[] EncryptionTokenKey = [];
|
||||
}
|
||||
internal class JsonDb
|
||||
{
|
||||
@@ -423,6 +426,24 @@ namespace EpinelPS.Database
|
||||
}
|
||||
Console.WriteLine("Database update completed");
|
||||
}
|
||||
|
||||
if (Instance.LauncherTokenKey.Length == 0)
|
||||
{
|
||||
Console.WriteLine("Launcher token key is null, generating new key");
|
||||
|
||||
var pasetoKey = new PasetoBuilder().Use(ProtocolVersion.V4, Purpose.Local)
|
||||
.GenerateSymmetricKey();
|
||||
Instance.LauncherTokenKey = pasetoKey.Key.ToArray();
|
||||
}
|
||||
if (Instance.EncryptionTokenKey.Length == 0)
|
||||
{
|
||||
Console.WriteLine("EncryptionTokenKey is null, generating new key");
|
||||
|
||||
var pasetoKey = new PasetoBuilder().Use(ProtocolVersion.V4, Purpose.Local)
|
||||
.GenerateSymmetricKey();
|
||||
Instance.EncryptionTokenKey = pasetoKey.Key.ToArray();
|
||||
}
|
||||
|
||||
Save();
|
||||
|
||||
ValidateDb();
|
||||
@@ -437,9 +458,9 @@ namespace EpinelPS.Database
|
||||
private static void ValidateDb()
|
||||
{
|
||||
// check if character level is valid
|
||||
foreach (var item in Instance.Users)
|
||||
foreach (var user in Instance.Users)
|
||||
{
|
||||
foreach (var c in item.Characters)
|
||||
foreach (var c in user.Characters)
|
||||
{
|
||||
if (c.Level > 1000)
|
||||
{
|
||||
@@ -447,6 +468,26 @@ namespace EpinelPS.Database
|
||||
c.Level = 1000;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if RepresentationTeamData exists and has slots
|
||||
if (user.RepresentationTeamData != null && user.RepresentationTeamData.Slots != null)
|
||||
{
|
||||
// Iterate through RepresentationTeamData slots
|
||||
foreach (var slot in user.RepresentationTeamData.Slots)
|
||||
{
|
||||
// Find the character in user's character list that matches the slot's Tid
|
||||
var correspondingCharacter = user.Characters.FirstOrDefault(c => c.Tid == slot.Tid);
|
||||
|
||||
if (correspondingCharacter != null)
|
||||
{
|
||||
// Update the CSN value if it differs
|
||||
if (slot.Csn != correspondingCharacter.Csn)
|
||||
{
|
||||
slot.Csn = correspondingCharacter.Csn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,44 +502,44 @@ namespace EpinelPS.Database
|
||||
File.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "/db.json", JsonConvert.SerializeObject(Instance, Formatting.Indented));
|
||||
}
|
||||
}
|
||||
public static int CurrentJukeboxBgm(int position)
|
||||
{
|
||||
var activeJukeboxBgm = new List<int>();
|
||||
//important first position holds lobby bgm id and second commanders room bgm id
|
||||
foreach (var user in Instance.Users)
|
||||
{
|
||||
if (user.JukeboxBgm == null || user.JukeboxBgm.Count == 0)
|
||||
{
|
||||
// this if statemet only exists becaus some weird black magic copies default value over and over
|
||||
//in the file when its set in public List<int> JukeboxBgm = new List<int>();
|
||||
//delete when or if it gets fixed
|
||||
|
||||
user.JukeboxBgm = new List<int> { 2,5 };
|
||||
}
|
||||
public static int CurrentJukeboxBgm(int position)
|
||||
{
|
||||
var activeJukeboxBgm = new List<int>();
|
||||
//important first position holds lobby bgm id and second commanders room bgm id
|
||||
foreach (var user in Instance.Users)
|
||||
{
|
||||
if (user.JukeboxBgm == null || user.JukeboxBgm.Count == 0)
|
||||
{
|
||||
// this if statemet only exists becaus some weird black magic copies default value over and over
|
||||
//in the file when its set in public List<int> JukeboxBgm = new List<int>();
|
||||
//delete when or if it gets fixed
|
||||
|
||||
activeJukeboxBgm.AddRange(user.JukeboxBgm);
|
||||
}
|
||||
user.JukeboxBgm = new List<int> { 2, 5 };
|
||||
}
|
||||
|
||||
if (activeJukeboxBgm.Count == 0)
|
||||
{
|
||||
return 8995001;
|
||||
}
|
||||
activeJukeboxBgm.AddRange(user.JukeboxBgm);
|
||||
}
|
||||
|
||||
position = (position == 2 && activeJukeboxBgm.Count > 1) ? 2 : 1;
|
||||
return activeJukeboxBgm[position - 1];
|
||||
}
|
||||
if (activeJukeboxBgm.Count == 0)
|
||||
{
|
||||
return 8995001;
|
||||
}
|
||||
|
||||
public static bool IsSickPulls(User selectedUser)
|
||||
{
|
||||
if (selectedUser != null)
|
||||
{
|
||||
return selectedUser.sickpulls;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"User with ID {selectedUser.ID} not found");
|
||||
}
|
||||
}
|
||||
position = (position == 2 && activeJukeboxBgm.Count > 1) ? 2 : 1;
|
||||
return activeJukeboxBgm[position - 1];
|
||||
}
|
||||
|
||||
public static bool IsSickPulls(User selectedUser)
|
||||
{
|
||||
if (selectedUser != null)
|
||||
{
|
||||
return selectedUser.sickpulls;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"User with ID {selectedUser.ID} not found");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
using EpinelPS.Database;
|
||||
using EpinelPS.Utils;
|
||||
using Google.Protobuf;
|
||||
using Paseto.Builder;
|
||||
using Paseto;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace EpinelPS.LobbyServer
|
||||
{
|
||||
@@ -64,7 +67,7 @@ namespace EpinelPS.LobbyServer
|
||||
/// </summary>
|
||||
/// <param name="publicKey"></param>
|
||||
/// <returns></returns>
|
||||
public static GameClientInfo GenGameClientTok(ByteString publicKey, string authToken)
|
||||
public static GameClientInfo GenGameClientTok(ByteString publicKey, ulong userid)
|
||||
{
|
||||
var token = Rng.RandomString(381);
|
||||
|
||||
@@ -75,25 +78,23 @@ namespace EpinelPS.LobbyServer
|
||||
info.Keys = box;
|
||||
info.ClientAuthToken = token;
|
||||
|
||||
// look up user id
|
||||
foreach (var user in JsonDb.Instance.LauncherAccessTokens)
|
||||
{
|
||||
if (user.Token == authToken)
|
||||
{
|
||||
info.UserId = user.UserID;
|
||||
}
|
||||
}
|
||||
if (info.UserId == 0)
|
||||
if (userid == 0)
|
||||
throw new Exception("expected user account");
|
||||
|
||||
JsonDb.Instance.GameClientTokens.Add(token, info);
|
||||
JsonDb.Save();
|
||||
info.UserId = userid;
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public static GameClientInfo? GetInfo(string token)
|
||||
{
|
||||
return JsonDb.Instance.GameClientTokens[token];
|
||||
var encryptionToken = new PasetoBuilder().Use(ProtocolVersion.V4, Purpose.Local)
|
||||
.WithKey(JsonDb.Instance.LauncherTokenKey, Encryption.SymmetricKey)
|
||||
.Decode(token, new PasetoTokenValidationParameters() { ValidateLifetime = true });
|
||||
|
||||
var p = ((System.Text.Json.JsonElement)encryptionToken.Paseto.Payload["data"]).GetString();
|
||||
|
||||
return JsonConvert.DeserializeObject<GameClientInfo>(p);
|
||||
}
|
||||
|
||||
public static void Init()
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
using Google.Protobuf;
|
||||
using EpinelPS.Database;
|
||||
using EpinelPS.Utils;
|
||||
using Newtonsoft.Json;
|
||||
using Paseto.Builder;
|
||||
using Paseto;
|
||||
using System.Security.Cryptography;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace EpinelPS.LobbyServer
|
||||
{
|
||||
@@ -41,13 +46,13 @@ namespace EpinelPS.LobbyServer
|
||||
public async Task HandleAsync(string authToken)
|
||||
{
|
||||
this.UsedAuthToken = authToken;
|
||||
foreach (var item in JsonDb.Instance.GameClientTokens)
|
||||
{
|
||||
if (item.Key == authToken)
|
||||
{
|
||||
UserId = item.Value.UserId;
|
||||
}
|
||||
}
|
||||
|
||||
var encryptionToken = new PasetoBuilder().Use(ProtocolVersion.V4, Purpose.Local)
|
||||
.WithKey(JsonDb.Instance.LauncherTokenKey, Encryption.SymmetricKey)
|
||||
.Decode(authToken, new PasetoTokenValidationParameters() { ValidateLifetime = true});
|
||||
|
||||
UserId = ((System.Text.Json.JsonElement)encryptionToken.Paseto.Payload["userid"]).GetUInt64();
|
||||
|
||||
if (UserId == 0) throw new Exception("403");
|
||||
await HandleAsync();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace EpinelPS.LobbyServer.Msgs.Auth
|
||||
{
|
||||
var req = await ReadData<ReqLogout>();
|
||||
|
||||
JsonDb.Instance.GameClientTokens.Remove(UsedAuthToken);
|
||||
// TODO remove UsedAuthToken
|
||||
|
||||
await WriteDataAsync(new ResLogout());
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
using EpinelPS.Utils;
|
||||
using Google.Protobuf;
|
||||
using Google.Protobuf.WellKnownTypes;
|
||||
using Microsoft.AspNetCore.DataProtection.KeyManagement;
|
||||
using Paseto.Builder;
|
||||
using Paseto;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace EpinelPS.LobbyServer.Msgs.Auth
|
||||
{
|
||||
@@ -22,17 +26,33 @@ namespace EpinelPS.LobbyServer.Msgs.Auth
|
||||
}
|
||||
}
|
||||
if (UserId == 0) throw new BadHttpRequestException("unknown auth token", 403);
|
||||
|
||||
var user = GetUser();
|
||||
|
||||
var rsp = LobbyHandler.GenGameClientTok(req.ClientPublicKey, UserId);
|
||||
|
||||
var token = new PasetoBuilder().Use(ProtocolVersion.V4, Purpose.Local)
|
||||
.WithKey(JsonDb.Instance.LauncherTokenKey, Encryption.SymmetricKey)
|
||||
.AddClaim("userid", UserId)
|
||||
.IssuedAt(DateTime.UtcNow)
|
||||
.Expiration(DateTime.UtcNow.AddDays(2))
|
||||
.Encode();
|
||||
|
||||
var encryptionToken = new PasetoBuilder().Use(ProtocolVersion.V4, Purpose.Local)
|
||||
.WithKey(JsonDb.Instance.LauncherTokenKey, Encryption.SymmetricKey)
|
||||
.AddClaim("data", JsonConvert.SerializeObject(rsp))
|
||||
.IssuedAt(DateTime.UtcNow)
|
||||
.Expiration(DateTime.UtcNow.AddDays(2))
|
||||
.Encode();
|
||||
|
||||
|
||||
var response = new ResEnterServer();
|
||||
var rsp = LobbyHandler.GenGameClientTok(req.ClientPublicKey, req.AuthToken);
|
||||
response.GameClientToken = rsp.ClientAuthToken;
|
||||
|
||||
response.GameClientToken = token;
|
||||
response.FeatureDataInfo = new NetFeatureDataInfo() { UseFeatureData = true };
|
||||
response.Identifier = new NetLegacyUserIdentifier() { Server = 21769, Usn = (long)user.ID };
|
||||
response.Identifier = new NetLegacyUserIdentifier() { Server = 1000, Usn = (long)user.ID };
|
||||
response.ShouldRestartAfter = Duration.FromTimeSpan(TimeSpan.FromSeconds(86400));
|
||||
|
||||
response.EncryptionToken = ByteString.CopyFromUtf8(rsp.ClientAuthToken);
|
||||
response.EncryptionToken = ByteString.CopyFromUtf8(encryptionToken);
|
||||
await WriteDataAsync(response);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,32 +29,6 @@ namespace EpinelPS
|
||||
Console.WriteLine("Initialize handlers");
|
||||
LobbyHandler.Init();
|
||||
|
||||
foreach (var user in JsonDb.Instance.Users)
|
||||
{
|
||||
// Check if RepresentationTeamData exists and has slots
|
||||
if (user.RepresentationTeamData != null && user.RepresentationTeamData.Slots != null)
|
||||
{
|
||||
// Iterate through RepresentationTeamData slots
|
||||
foreach (var slot in user.RepresentationTeamData.Slots)
|
||||
{
|
||||
// Find the character in user's character list that matches the slot's Tid
|
||||
var correspondingCharacter = user.Characters.FirstOrDefault(c => c.Tid == slot.Tid);
|
||||
|
||||
if (correspondingCharacter != null)
|
||||
{
|
||||
// Update the CSN value if it differs
|
||||
if (slot.Csn != correspondingCharacter.Csn)
|
||||
{
|
||||
slot.Csn = correspondingCharacter.Csn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save the updated data
|
||||
JsonDb.Save();
|
||||
|
||||
Console.WriteLine("Starting ASP.NET core on ports 80/443");
|
||||
new Thread(() =>
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user