Convert to new namespace stuff and implicit usings
This commit is contained in:
@@ -3,54 +3,53 @@ using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Prospect.Launcher.Invoke;
|
||||
|
||||
namespace Prospect.Launcher
|
||||
namespace Prospect.Launcher;
|
||||
|
||||
public static class Inject
|
||||
{
|
||||
public static class Inject
|
||||
{
|
||||
const int PROCESS_CREATE_THREAD = 0x0002;
|
||||
const int PROCESS_QUERY_INFORMATION = 0x0400;
|
||||
const int PROCESS_VM_OPERATION = 0x0008;
|
||||
const int PROCESS_VM_WRITE = 0x0020;
|
||||
const int PROCESS_VM_READ = 0x0010;
|
||||
const int PROCESS_CREATE_THREAD = 0x0002;
|
||||
const int PROCESS_QUERY_INFORMATION = 0x0400;
|
||||
const int PROCESS_VM_OPERATION = 0x0008;
|
||||
const int PROCESS_VM_WRITE = 0x0020;
|
||||
const int PROCESS_VM_READ = 0x0010;
|
||||
|
||||
const uint MEM_COMMIT = 0x00001000;
|
||||
const uint MEM_RESERVE = 0x00002000;
|
||||
const uint PAGE_READWRITE = 4;
|
||||
const uint MEM_COMMIT = 0x00001000;
|
||||
const uint MEM_RESERVE = 0x00002000;
|
||||
const uint PAGE_READWRITE = 4;
|
||||
|
||||
// https://codingvision.net/c-inject-a-dll-into-a-process-w-createremotethread
|
||||
public static unsafe bool Library(uint processId, string path)
|
||||
// https://codingvision.net/c-inject-a-dll-into-a-process-w-createremotethread
|
||||
public static unsafe bool Library(uint processId, string path)
|
||||
{
|
||||
IntPtr procHandle = Kernel32.OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, (int)processId);
|
||||
|
||||
var loadLibraryAddr = Kernel32.GetProcAddress(Kernel32.GetModuleHandle("kernel32.dll"), "LoadLibraryA");
|
||||
if (loadLibraryAddr == IntPtr.Zero)
|
||||
{
|
||||
IntPtr procHandle = Kernel32.OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, false, (int)processId);
|
||||
|
||||
var loadLibraryAddr = Kernel32.GetProcAddress(Kernel32.GetModuleHandle("kernel32.dll"), "LoadLibraryA");
|
||||
if (loadLibraryAddr == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Failed GetProcAddress.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var allocMemAddress = Kernel32.VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((path.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
if (allocMemAddress == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Failed VirtualAllocEx.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var libraryBytes = Encoding.Default.GetBytes(path);
|
||||
|
||||
fixed (byte* pLibraryBytes = libraryBytes)
|
||||
{
|
||||
Kernel32.WriteProcessMemory(procHandle, allocMemAddress, pLibraryBytes, libraryBytes.Length + 1, out _);
|
||||
}
|
||||
|
||||
var threadHandle = Kernel32.CreateRemoteThread(procHandle, IntPtr.Zero, 0, loadLibraryAddr, allocMemAddress, 0, IntPtr.Zero);
|
||||
if (threadHandle == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Failed CreateRemoteThread.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
Console.WriteLine("Failed GetProcAddress.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var allocMemAddress = Kernel32.VirtualAllocEx(procHandle, IntPtr.Zero, (uint)((path.Length + 1) * Marshal.SizeOf(typeof(char))), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||
if (allocMemAddress == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Failed VirtualAllocEx.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var libraryBytes = Encoding.Default.GetBytes(path);
|
||||
|
||||
fixed (byte* pLibraryBytes = libraryBytes)
|
||||
{
|
||||
Kernel32.WriteProcessMemory(procHandle, allocMemAddress, pLibraryBytes, libraryBytes.Length + 1, out _);
|
||||
}
|
||||
|
||||
var threadHandle = Kernel32.CreateRemoteThread(procHandle, IntPtr.Zero, 0, loadLibraryAddr, allocMemAddress, 0, IntPtr.Zero);
|
||||
if (threadHandle == IntPtr.Zero)
|
||||
{
|
||||
Console.WriteLine("Failed CreateRemoteThread.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2,52 +2,51 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Prospect.Launcher.Invoke.Structs;
|
||||
|
||||
namespace Prospect.Launcher.Invoke
|
||||
namespace Prospect.Launcher.Invoke;
|
||||
|
||||
internal static class Kernel32
|
||||
{
|
||||
internal static class Kernel32
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
|
||||
public static extern bool CreateProcess(string lpApplicationName,
|
||||
string lpCommandLine, IntPtr lpProcessAttributes,
|
||||
IntPtr lpThreadAttributes,
|
||||
bool bInheritHandles, ProcessCreationFlags dwCreationFlags,
|
||||
IntPtr lpEnvironment, string lpCurrentDirectory,
|
||||
ref StartupInfo lpStartupInfo,
|
||||
out ProcessInformation lpProcessInformation);
|
||||
[DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
|
||||
public static extern bool CreateProcess(string lpApplicationName,
|
||||
string lpCommandLine, IntPtr lpProcessAttributes,
|
||||
IntPtr lpThreadAttributes,
|
||||
bool bInheritHandles, ProcessCreationFlags dwCreationFlags,
|
||||
IntPtr lpEnvironment, string lpCurrentDirectory,
|
||||
ref StartupInfo lpStartupInfo,
|
||||
out ProcessInformation lpProcessInformation);
|
||||
|
||||
public static bool CreateProcess(
|
||||
string lpApplicationName,
|
||||
string lpCommandLine,
|
||||
ProcessCreationFlags dwCreationFlags,
|
||||
ref StartupInfo lpStartupInfo,
|
||||
out ProcessInformation lpProcessInformation) => CreateProcess(lpApplicationName, lpCommandLine, IntPtr.Zero,
|
||||
IntPtr.Zero, false, dwCreationFlags, IntPtr.Zero, null, ref lpStartupInfo, out lpProcessInformation);
|
||||
public static bool CreateProcess(
|
||||
string lpApplicationName,
|
||||
string lpCommandLine,
|
||||
ProcessCreationFlags dwCreationFlags,
|
||||
ref StartupInfo lpStartupInfo,
|
||||
out ProcessInformation lpProcessInformation) => CreateProcess(lpApplicationName, lpCommandLine, IntPtr.Zero,
|
||||
IntPtr.Zero, false, dwCreationFlags, IntPtr.Zero, null, ref lpStartupInfo, out lpProcessInformation);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern unsafe bool WriteProcessMemory(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpBaseAddress,
|
||||
byte* lpBuffer,
|
||||
Int32 nSize,
|
||||
out IntPtr lpNumberOfBytesWritten
|
||||
);
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern unsafe bool WriteProcessMemory(
|
||||
IntPtr hProcess,
|
||||
IntPtr lpBaseAddress,
|
||||
byte* lpBuffer,
|
||||
Int32 nSize,
|
||||
out IntPtr lpNumberOfBytesWritten
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr GetModuleHandle(string lpModuleName);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
|
||||
|
||||
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
[DllImport("kernel32", CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = true)]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
|
||||
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
||||
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
|
||||
public static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr CreateRemoteThread(IntPtr hProcess, IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern uint ResumeThread(IntPtr hThread);
|
||||
}
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern uint ResumeThread(IntPtr hThread);
|
||||
}
|
||||
@@ -1,26 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace Prospect.Launcher.Invoke.Structs
|
||||
namespace Prospect.Launcher.Invoke.Structs;
|
||||
|
||||
[Flags]
|
||||
internal enum ProcessCreationFlags : uint
|
||||
{
|
||||
[Flags]
|
||||
internal enum ProcessCreationFlags : uint
|
||||
{
|
||||
ZERO_FLAG = 0x00000000,
|
||||
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
|
||||
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
|
||||
CREATE_NEW_CONSOLE = 0x00000010,
|
||||
CREATE_NEW_PROCESS_GROUP = 0x00000200,
|
||||
CREATE_NO_WINDOW = 0x08000000,
|
||||
CREATE_PROTECTED_PROCESS = 0x00040000,
|
||||
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
|
||||
CREATE_SEPARATE_WOW_VDM = 0x00001000,
|
||||
CREATE_SHARED_WOW_VDM = 0x00001000,
|
||||
CREATE_SUSPENDED = 0x00000004,
|
||||
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
|
||||
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
|
||||
DEBUG_PROCESS = 0x00000001,
|
||||
DETACHED_PROCESS = 0x00000008,
|
||||
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
|
||||
INHERIT_PARENT_AFFINITY = 0x00010000
|
||||
}
|
||||
ZERO_FLAG = 0x00000000,
|
||||
CREATE_BREAKAWAY_FROM_JOB = 0x01000000,
|
||||
CREATE_DEFAULT_ERROR_MODE = 0x04000000,
|
||||
CREATE_NEW_CONSOLE = 0x00000010,
|
||||
CREATE_NEW_PROCESS_GROUP = 0x00000200,
|
||||
CREATE_NO_WINDOW = 0x08000000,
|
||||
CREATE_PROTECTED_PROCESS = 0x00040000,
|
||||
CREATE_PRESERVE_CODE_AUTHZ_LEVEL = 0x02000000,
|
||||
CREATE_SEPARATE_WOW_VDM = 0x00001000,
|
||||
CREATE_SHARED_WOW_VDM = 0x00001000,
|
||||
CREATE_SUSPENDED = 0x00000004,
|
||||
CREATE_UNICODE_ENVIRONMENT = 0x00000400,
|
||||
DEBUG_ONLY_THIS_PROCESS = 0x00000002,
|
||||
DEBUG_PROCESS = 0x00000001,
|
||||
DETACHED_PROCESS = 0x00000008,
|
||||
EXTENDED_STARTUPINFO_PRESENT = 0x00080000,
|
||||
INHERIT_PARENT_AFFINITY = 0x00010000
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Prospect.Launcher.Invoke.Structs
|
||||
namespace Prospect.Launcher.Invoke.Structs;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ProcessInformation
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct ProcessInformation
|
||||
{
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public uint dwProcessId;
|
||||
public uint dwThreadId;
|
||||
}
|
||||
public IntPtr hProcess;
|
||||
public IntPtr hThread;
|
||||
public uint dwProcessId;
|
||||
public uint dwThreadId;
|
||||
}
|
||||
@@ -1,28 +1,27 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Prospect.Launcher.Invoke.Structs
|
||||
namespace Prospect.Launcher.Invoke.Structs;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct StartupInfo
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct StartupInfo
|
||||
{
|
||||
public uint cb;
|
||||
public string lpReserved;
|
||||
public string lpDesktop;
|
||||
public string lpTitle;
|
||||
public uint dwX;
|
||||
public uint dwY;
|
||||
public uint dwXSize;
|
||||
public uint dwYSize;
|
||||
public uint dwXCountChars;
|
||||
public uint dwYCountChars;
|
||||
public uint dwFillAttribute;
|
||||
public uint dwFlags;
|
||||
public short wShowWindow;
|
||||
public short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
public uint cb;
|
||||
public string lpReserved;
|
||||
public string lpDesktop;
|
||||
public string lpTitle;
|
||||
public uint dwX;
|
||||
public uint dwY;
|
||||
public uint dwXSize;
|
||||
public uint dwYSize;
|
||||
public uint dwXCountChars;
|
||||
public uint dwYCountChars;
|
||||
public uint dwFillAttribute;
|
||||
public uint dwFlags;
|
||||
public short wShowWindow;
|
||||
public short cbReserved2;
|
||||
public IntPtr lpReserved2;
|
||||
public IntPtr hStdInput;
|
||||
public IntPtr hStdOutput;
|
||||
public IntPtr hStdError;
|
||||
}
|
||||
@@ -4,75 +4,74 @@ using System.IO;
|
||||
using Prospect.Launcher.Invoke;
|
||||
using Prospect.Launcher.Invoke.Structs;
|
||||
|
||||
namespace Prospect.Launcher
|
||||
namespace Prospect.Launcher;
|
||||
|
||||
internal static class Program
|
||||
{
|
||||
internal static class Program
|
||||
/// <summary>
|
||||
/// Steam AppId.
|
||||
/// - https://steamdb.info/app/480/
|
||||
/// - https://steamdb.info/app/1600360/
|
||||
/// </summary>
|
||||
private const string AppId = "480";
|
||||
|
||||
/// <summary>
|
||||
/// Executable name of the game.
|
||||
/// </summary>
|
||||
private const string FileName = "Prospect-Win64-Shipping.exe";
|
||||
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
/// <summary>
|
||||
/// Steam AppId.
|
||||
/// - https://steamdb.info/app/480/
|
||||
/// - https://steamdb.info/app/1600360/
|
||||
/// </summary>
|
||||
private const string AppId = "480";
|
||||
|
||||
/// <summary>
|
||||
/// Executable name of the game.
|
||||
/// </summary>
|
||||
private const string FileName = "Prospect-Win64-Shipping.exe";
|
||||
|
||||
private static void Main(string[] args)
|
||||
if (args.Length != 1)
|
||||
{
|
||||
if (args.Length != 1)
|
||||
{
|
||||
Console.WriteLine("Usage: ./Prospect.Launcher <Game directory>");
|
||||
return;
|
||||
}
|
||||
|
||||
var gamePath = Path.Combine(args[0], "Prospect", "Binaries", "Win64");
|
||||
var gameBinary = Path.Combine(gamePath, FileName);
|
||||
var gameArgs = new List<string>();
|
||||
|
||||
// 2EA46 = Default
|
||||
// A22AB = The Cycle Playtest
|
||||
gameArgs.Add("-empty");
|
||||
gameArgs.Add("-log");
|
||||
gameArgs.Add("-windowed");
|
||||
gameArgs.Add("-noeac");
|
||||
gameArgs.Add("-nointro");
|
||||
gameArgs.Add("-steam_auth");
|
||||
gameArgs.Add("PF_TITLEID=A22AB");
|
||||
|
||||
// Ensure "steam_appid.txt" exists, to fix steam authentication.
|
||||
var steamAppId = Path.Combine(gamePath, "steam_appid.txt");
|
||||
|
||||
File.WriteAllText(steamAppId, AppId);
|
||||
|
||||
// Spawn.
|
||||
var startupInfo = new StartupInfo();
|
||||
|
||||
if (!Kernel32.CreateProcess(gameBinary, string.Join(' ', gameArgs), ProcessCreationFlags.CREATE_SUSPENDED, ref startupInfo, out var processInfo))
|
||||
{
|
||||
Console.WriteLine("Failed to spawn game.");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Spawned.");
|
||||
|
||||
// Inject DLL.
|
||||
var agentPath = Path.Combine(AppContext.BaseDirectory, "Prospect.Agent.dll");
|
||||
|
||||
if (!Inject.Library(processInfo.dwProcessId, agentPath))
|
||||
{
|
||||
Console.WriteLine("Failed to inject library.");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Injected.");
|
||||
|
||||
// Resume.
|
||||
Kernel32.ResumeThread(processInfo.hThread);
|
||||
|
||||
Console.WriteLine("Resumed.");
|
||||
Console.WriteLine("Usage: ./Prospect.Launcher <Game directory>");
|
||||
return;
|
||||
}
|
||||
|
||||
var gamePath = Path.Combine(args[0], "Prospect", "Binaries", "Win64");
|
||||
var gameBinary = Path.Combine(gamePath, FileName);
|
||||
var gameArgs = new List<string>();
|
||||
|
||||
// 2EA46 = Default
|
||||
// A22AB = The Cycle Playtest
|
||||
gameArgs.Add("-empty");
|
||||
gameArgs.Add("-log");
|
||||
gameArgs.Add("-windowed");
|
||||
gameArgs.Add("-noeac");
|
||||
gameArgs.Add("-nointro");
|
||||
gameArgs.Add("-steam_auth");
|
||||
gameArgs.Add("PF_TITLEID=A22AB");
|
||||
|
||||
// Ensure "steam_appid.txt" exists, to fix steam authentication.
|
||||
var steamAppId = Path.Combine(gamePath, "steam_appid.txt");
|
||||
|
||||
File.WriteAllText(steamAppId, AppId);
|
||||
|
||||
// Spawn.
|
||||
var startupInfo = new StartupInfo();
|
||||
|
||||
if (!Kernel32.CreateProcess(gameBinary, string.Join(' ', gameArgs), ProcessCreationFlags.CREATE_SUSPENDED, ref startupInfo, out var processInfo))
|
||||
{
|
||||
Console.WriteLine("Failed to spawn game.");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Spawned.");
|
||||
|
||||
// Inject DLL.
|
||||
var agentPath = Path.Combine(AppContext.BaseDirectory, "Prospect.Agent.dll");
|
||||
|
||||
if (!Inject.Library(processInfo.dwProcessId, agentPath))
|
||||
{
|
||||
Console.WriteLine("Failed to inject library.");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine("Injected.");
|
||||
|
||||
// Resume.
|
||||
Kernel32.ResumeThread(processInfo.hThread);
|
||||
|
||||
Console.WriteLine("Resumed.");
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace Prospect.Server.Api.Config
|
||||
namespace Prospect.Server.Api.Config;
|
||||
|
||||
public class DatabaseSettings
|
||||
{
|
||||
public class DatabaseSettings
|
||||
{
|
||||
public string ConnectionString { get; set; }
|
||||
public string DatabaseName { get; set; }
|
||||
}
|
||||
public string ConnectionString { get; set; }
|
||||
public string DatabaseName { get; set; }
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace Prospect.Server.Api.Config
|
||||
namespace Prospect.Server.Api.Config;
|
||||
|
||||
public class PlayFabSettings
|
||||
{
|
||||
public class PlayFabSettings
|
||||
{
|
||||
public string PublisherId { get; set; }
|
||||
public string TitleId { get; set; }
|
||||
}
|
||||
public string PublisherId { get; set; }
|
||||
public string TitleId { get; set; }
|
||||
}
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Prospect.Server.Api.Config;
|
||||
@@ -15,256 +12,258 @@ using Prospect.Server.Api.Services.Database.Models;
|
||||
using Prospect.Server.Api.Services.UserData;
|
||||
using Prospect.Server.Steam;
|
||||
|
||||
namespace Prospect.Server.Api.Controllers
|
||||
namespace Prospect.Server.Api.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[Route("Client")]
|
||||
public class ClientController : Controller
|
||||
{
|
||||
[ApiController]
|
||||
[Route("Client")]
|
||||
public class ClientController : Controller
|
||||
{
|
||||
private readonly PlayFabSettings _settings;
|
||||
private readonly AuthTokenService _authTokenService;
|
||||
private readonly DbUserService _userService;
|
||||
private readonly DbEntityService _entityService;
|
||||
private readonly UserDataService _userDataService;
|
||||
private readonly TitleDataService _titleDataService;
|
||||
|
||||
public ClientController(IOptions<PlayFabSettings> settings,
|
||||
AuthTokenService authTokenService,
|
||||
DbUserService userService,
|
||||
DbEntityService entityService,
|
||||
UserDataService userDataService,
|
||||
TitleDataService titleDataService)
|
||||
{
|
||||
_settings = settings.Value;
|
||||
_authTokenService = authTokenService;
|
||||
_userService = userService;
|
||||
_entityService = entityService;
|
||||
_userDataService = userDataService;
|
||||
_titleDataService = titleDataService;
|
||||
}
|
||||
private const int AppIdDefault = 480;
|
||||
private const int AppIdCycleBeta = 1600361;
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("LoginWithSteam")]
|
||||
[Produces("application/json")]
|
||||
public async Task<IActionResult> LoginWithSteam(ClientLoginWithSteamRequest request)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(request.SteamTicket))
|
||||
{
|
||||
var ticket = AppTicket.Parse(request.SteamTicket);
|
||||
if (ticket.IsValid && ticket.HasValidSignature)
|
||||
{
|
||||
var userSteamId = ticket.SteamId.ToString();
|
||||
|
||||
var user = await _userService.FindOrCreateAsync(PlayFabUserAuthType.Steam, userSteamId);
|
||||
var entity = await _entityService.FindOrCreateAsync(user.Id);
|
||||
|
||||
var userTicket = _authTokenService.GenerateUser(entity);
|
||||
var entityTicket = _authTokenService.GenerateEntity(entity);
|
||||
private readonly PlayFabSettings _settings;
|
||||
private readonly AuthTokenService _authTokenService;
|
||||
private readonly DbUserService _userService;
|
||||
private readonly DbEntityService _entityService;
|
||||
private readonly UserDataService _userDataService;
|
||||
private readonly TitleDataService _titleDataService;
|
||||
|
||||
await _userDataService.InitAsync(user.Id);
|
||||
public ClientController(IOptions<PlayFabSettings> settings,
|
||||
AuthTokenService authTokenService,
|
||||
DbUserService userService,
|
||||
DbEntityService entityService,
|
||||
UserDataService userDataService,
|
||||
TitleDataService titleDataService)
|
||||
{
|
||||
_settings = settings.Value;
|
||||
_authTokenService = authTokenService;
|
||||
_userService = userService;
|
||||
_entityService = entityService;
|
||||
_userDataService = userDataService;
|
||||
_titleDataService = titleDataService;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("LoginWithSteam")]
|
||||
[Produces("application/json")]
|
||||
public async Task<IActionResult> LoginWithSteam(ClientLoginWithSteamRequest request)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(request.SteamTicket))
|
||||
{
|
||||
var ticket = AppTicket.Parse(request.SteamTicket);
|
||||
if (ticket.IsValid && ticket.HasValidSignature && (ticket.AppId == AppIdDefault || ticket.AppId == AppIdCycleBeta))
|
||||
{
|
||||
var userSteamId = ticket.SteamId.ToString();
|
||||
|
||||
return Ok(new ClientResponse<FServerLoginResult>
|
||||
var user = await _userService.FindOrCreateAsync(PlayFabUserAuthType.Steam, userSteamId);
|
||||
var entity = await _entityService.FindOrCreateAsync(user.Id);
|
||||
|
||||
var userTicket = _authTokenService.GenerateUser(entity);
|
||||
var entityTicket = _authTokenService.GenerateEntity(entity);
|
||||
|
||||
await _userDataService.InitAsync(user.Id);
|
||||
|
||||
return Ok(new ClientResponse<FServerLoginResult>
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FServerLoginResult
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FServerLoginResult
|
||||
EntityToken = new FEntityTokenResponse
|
||||
{
|
||||
EntityToken = new FEntityTokenResponse
|
||||
Entity = new FEntityKey
|
||||
{
|
||||
Entity = new FEntityKey
|
||||
{
|
||||
Id = entity.Id,
|
||||
Type = "title_player_account",
|
||||
TypeString = "title_player_account"
|
||||
},
|
||||
EntityToken = entityTicket,
|
||||
TokenExpiration = DateTime.UtcNow.AddDays(6), // TODO:
|
||||
Id = entity.Id,
|
||||
Type = "title_player_account",
|
||||
TypeString = "title_player_account"
|
||||
},
|
||||
InfoResultPayload = new FGetPlayerCombinedInfoResultPayload
|
||||
EntityToken = entityTicket,
|
||||
TokenExpiration = DateTime.UtcNow.AddDays(6), // TODO:
|
||||
},
|
||||
InfoResultPayload = new FGetPlayerCombinedInfoResultPayload
|
||||
{
|
||||
CharacterInventories = new List<object>(),
|
||||
PlayerProfile = new FPlayerProfileModel
|
||||
{
|
||||
CharacterInventories = new List<object>(),
|
||||
PlayerProfile = new FPlayerProfileModel
|
||||
{
|
||||
DisplayName = user.DisplayName,
|
||||
PlayerId = user.Id,
|
||||
PublisherId = _settings.PublisherId,
|
||||
TitleId = _settings.TitleId
|
||||
},
|
||||
UserDataVersion = 0,
|
||||
UserInventory = new List<object>(),
|
||||
UserReadOnlyDataVersion = 0
|
||||
DisplayName = user.DisplayName,
|
||||
PlayerId = user.Id,
|
||||
PublisherId = _settings.PublisherId,
|
||||
TitleId = _settings.TitleId
|
||||
},
|
||||
LastLoginTime = DateTime.UtcNow, // TODO:
|
||||
NewlyCreated = false, // TODO:
|
||||
PlayFabId = user.Id,
|
||||
SessionTicket = userTicket,
|
||||
SettingsForUser = new FUserSettings
|
||||
{
|
||||
GatherDeviceInfo = true,
|
||||
GatherFocusInfo = true,
|
||||
NeedsAttribution = false,
|
||||
},
|
||||
TreatmentAssignment = new FTreatmentAssignment
|
||||
{
|
||||
Variables = new List<FVariable>(),
|
||||
Variants = new List<string>()
|
||||
}
|
||||
UserDataVersion = 0,
|
||||
UserInventory = new List<object>(),
|
||||
UserReadOnlyDataVersion = 0
|
||||
},
|
||||
LastLoginTime = DateTime.UtcNow, // TODO:
|
||||
NewlyCreated = false, // TODO:
|
||||
PlayFabId = user.Id,
|
||||
SessionTicket = userTicket,
|
||||
SettingsForUser = new FUserSettings
|
||||
{
|
||||
GatherDeviceInfo = true,
|
||||
GatherFocusInfo = true,
|
||||
NeedsAttribution = false,
|
||||
},
|
||||
TreatmentAssignment = new FTreatmentAssignment
|
||||
{
|
||||
Variables = new List<FVariable>(),
|
||||
Variants = new List<string>()
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return BadRequest(new ClientResponse
|
||||
{
|
||||
Code = 400,
|
||||
Status = "BadRequest",
|
||||
Error = "InvalidSteamTicket",
|
||||
ErrorCode = 1010,
|
||||
ErrorMessage = "Steam API AuthenticateUserTicket error response .."
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("AddGenericID")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public IActionResult AddGenericId(FAddGenericIDRequest request)
|
||||
return BadRequest(new ClientResponse
|
||||
{
|
||||
return Ok(new ClientResponse<object>
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new object()
|
||||
});
|
||||
}
|
||||
Code = 400,
|
||||
Status = "BadRequest",
|
||||
Error = "InvalidSteamTicket",
|
||||
ErrorCode = 1010,
|
||||
ErrorMessage = "Steam API AuthenticateUserTicket error response .."
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("UpdateUserTitleDisplayName")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public IActionResult UpdateUserTitleDisplayName(FUpdateUserTitleDisplayNameRequest request)
|
||||
[HttpPost("AddGenericID")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public IActionResult AddGenericId(FAddGenericIDRequest request)
|
||||
{
|
||||
return Ok(new ClientResponse<object>
|
||||
{
|
||||
return Ok(new ClientResponse<FUpdateUserTitleDisplayNameResult>
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FUpdateUserTitleDisplayNameResult
|
||||
{
|
||||
DisplayName = request.DisplayName
|
||||
}
|
||||
});
|
||||
}
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new {}
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("UpdateUserData")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public async Task<IActionResult> UpdateUserData(FUpdateUserDataRequest request)
|
||||
[HttpPost("UpdateUserTitleDisplayName")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public IActionResult UpdateUserTitleDisplayName(FUpdateUserTitleDisplayNameRequest request)
|
||||
{
|
||||
return Ok(new ClientResponse<FUpdateUserTitleDisplayNameResult>
|
||||
{
|
||||
var userId = User.FindAuthUserId();
|
||||
await _userDataService.UpdateAsync(userId, request.PlayFabId, request.Data);
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FUpdateUserTitleDisplayNameResult
|
||||
{
|
||||
DisplayName = request.DisplayName
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("UpdateUserData")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public async Task<IActionResult> UpdateUserData(FUpdateUserDataRequest request)
|
||||
{
|
||||
var userId = User.FindAuthUserId();
|
||||
await _userDataService.UpdateAsync(userId, request.PlayFabId, request.Data);
|
||||
|
||||
return Ok(new ClientResponse<FUpdateUserDataResult>
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FUpdateUserDataResult
|
||||
{
|
||||
DataVersion = 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("GetUserData")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public async Task<IActionResult> GetUserData(FGetUserDataRequest request)
|
||||
return Ok(new ClientResponse<FUpdateUserDataResult>
|
||||
{
|
||||
var userId = User.FindAuthUserId();
|
||||
var userData = await _userDataService.FindAsync(userId, request.PlayFabId, request.Keys);
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FUpdateUserDataResult
|
||||
{
|
||||
DataVersion = 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("GetUserData")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public async Task<IActionResult> GetUserData(FGetUserDataRequest request)
|
||||
{
|
||||
var userId = User.FindAuthUserId();
|
||||
var userData = await _userDataService.FindAsync(userId, request.PlayFabId, request.Keys);
|
||||
|
||||
return Ok(new ClientResponse<FGetUserDataResult>
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FGetUserDataResult
|
||||
{
|
||||
Data = userData,
|
||||
DataVersion = 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("GetUserReadOnlyData")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public IActionResult GetUserReadOnlyData(FGetUserDataRequest request)
|
||||
return Ok(new ClientResponse<FGetUserDataResult>
|
||||
{
|
||||
return Ok(new ClientResponse<FGetUserDataResult>
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FGetUserDataResult
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FGetUserDataResult
|
||||
{
|
||||
Data = new Dictionary<string, FUserDataRecord>(),
|
||||
DataVersion = 0
|
||||
}
|
||||
});
|
||||
}
|
||||
Data = userData,
|
||||
DataVersion = 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("GetUserInventory")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public IActionResult GetUserReadOnlyData(FGetUserInventoryRequest request)
|
||||
[HttpPost("GetUserReadOnlyData")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public IActionResult GetUserReadOnlyData(FGetUserDataRequest request)
|
||||
{
|
||||
return Ok(new ClientResponse<FGetUserDataResult>
|
||||
{
|
||||
return Ok(new ClientResponse<FGetUserInventoryResult>
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FGetUserDataResult
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FGetUserInventoryResult
|
||||
{
|
||||
Inventory = new List<FItemInstance>
|
||||
{
|
||||
// new FItemInstance
|
||||
// {
|
||||
// ItemId = "Helmet_03",
|
||||
// ItemInstanceId = "0102030405060708",
|
||||
// ItemClass = "Helmet",
|
||||
// PurchaseDate = DateTime.Now.AddDays(-1),
|
||||
// CatalogVersion = "StaticItems",
|
||||
// DisplayName = "Helmet",
|
||||
// UnitPrice = 0,
|
||||
// CustomData = new Dictionary<string, string>
|
||||
// {
|
||||
// ["insurance"] = "None",
|
||||
// ["mods"] = "{\"m\":[]}",
|
||||
// ["vanity_misc_data"] = "{\"v\":\"\",\"s\":\"\",\"l\":3,\"a\":1,\"d\":300}"
|
||||
// }
|
||||
// }
|
||||
},
|
||||
VirtualCurrency = new Dictionary<string, int>
|
||||
{
|
||||
["AE"] = 0,
|
||||
["AS"] = 0,
|
||||
["AU"] = int.MaxValue,
|
||||
["SC"] = int.MaxValue
|
||||
},
|
||||
VirtualCurrencyRechargeTimes = new Dictionary<string, FVirtualCurrencyRechargeTime>()
|
||||
}
|
||||
});
|
||||
}
|
||||
Data = new Dictionary<string, FUserDataRecord>(),
|
||||
DataVersion = 0
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("GetTitleData")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public IActionResult GetTitleData(FGetTitleDataRequest request)
|
||||
[HttpPost("GetUserInventory")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public IActionResult GetUserReadOnlyData(FGetUserInventoryRequest request)
|
||||
{
|
||||
return Ok(new ClientResponse<FGetUserInventoryResult>
|
||||
{
|
||||
return Ok(new ClientResponse<FGetTitleDataResult>
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FGetUserInventoryResult
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FGetTitleDataResult()
|
||||
Inventory = new List<FItemInstance>
|
||||
{
|
||||
Data = _titleDataService.Find(request.Keys)
|
||||
}
|
||||
});
|
||||
}
|
||||
// new FItemInstance
|
||||
// {
|
||||
// ItemId = "Helmet_03",
|
||||
// ItemInstanceId = "0102030405060708",
|
||||
// ItemClass = "Helmet",
|
||||
// PurchaseDate = DateTime.Now.AddDays(-1),
|
||||
// CatalogVersion = "StaticItems",
|
||||
// DisplayName = "Helmet",
|
||||
// UnitPrice = 0,
|
||||
// CustomData = new Dictionary<string, string>
|
||||
// {
|
||||
// ["insurance"] = "None",
|
||||
// ["mods"] = "{\"m\":[]}",
|
||||
// ["vanity_misc_data"] = "{\"v\":\"\",\"s\":\"\",\"l\":3,\"a\":1,\"d\":300}"
|
||||
// }
|
||||
// }
|
||||
},
|
||||
VirtualCurrency = new Dictionary<string, int>
|
||||
{
|
||||
["AE"] = 0,
|
||||
["AS"] = 0,
|
||||
["AU"] = int.MaxValue,
|
||||
["SC"] = int.MaxValue
|
||||
},
|
||||
VirtualCurrencyRechargeTimes = new Dictionary<string, FVirtualCurrencyRechargeTime>()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[HttpPost("GetTitleData")]
|
||||
[Produces("application/json")]
|
||||
[Authorize(AuthenticationSchemes = UserAuthenticationOptions.DefaultScheme)]
|
||||
public IActionResult GetTitleData(FGetTitleDataRequest request)
|
||||
{
|
||||
return Ok(new ClientResponse<FGetTitleDataResult>
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FGetTitleDataResult()
|
||||
{
|
||||
Data = _titleDataService.Find(request.Keys)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,306 +1,302 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Prospect.Server.Api.Models.Client;
|
||||
using Prospect.Server.Api.Models.CloudScript;
|
||||
using Prospect.Server.Api.Models.CloudScript.Data;
|
||||
using Prospect.Server.Api.Services.Auth.Entity;
|
||||
using Prospect.Server.Api.Services.Auth.Extensions;
|
||||
|
||||
namespace Prospect.Server.Api.Controllers
|
||||
namespace Prospect.Server.Api.Controllers;
|
||||
|
||||
[Route("CloudScript")]
|
||||
[ApiController]
|
||||
[Authorize(AuthenticationSchemes = EntityAuthenticationOptions.DefaultScheme)]
|
||||
public class CloudScriptController : Controller
|
||||
{
|
||||
[Route("CloudScript")]
|
||||
[ApiController]
|
||||
[Authorize(AuthenticationSchemes = EntityAuthenticationOptions.DefaultScheme)]
|
||||
public class CloudScriptController : Controller
|
||||
private readonly ILogger<CloudScriptController> _logger;
|
||||
|
||||
public CloudScriptController(ILogger<CloudScriptController> logger)
|
||||
{
|
||||
private readonly ILogger<CloudScriptController> _logger;
|
||||
|
||||
public CloudScriptController(ILogger<CloudScriptController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpPost("ExecuteFunction")]
|
||||
[Produces("application/json")]
|
||||
public IActionResult ExecuteFunction(FExecuteFunctionRequest request)
|
||||
[HttpPost("ExecuteFunction")]
|
||||
[Produces("application/json")]
|
||||
public IActionResult ExecuteFunction(FExecuteFunctionRequest request)
|
||||
{
|
||||
_logger.LogInformation("Executing function {Function}", request.FunctionName);
|
||||
|
||||
object result = null;
|
||||
|
||||
switch (request.FunctionName)
|
||||
{
|
||||
_logger.LogInformation("Executing function {Function}", request.FunctionName);
|
||||
|
||||
object result = null;
|
||||
|
||||
switch (request.FunctionName)
|
||||
{
|
||||
case "RequestMaintenanceModeState":
|
||||
result = new
|
||||
{
|
||||
enabled = false
|
||||
};
|
||||
break;
|
||||
case "GetCharacterVanity":
|
||||
result = new
|
||||
case "RequestMaintenanceModeState":
|
||||
result = new
|
||||
{
|
||||
enabled = false
|
||||
};
|
||||
break;
|
||||
case "GetCharacterVanity":
|
||||
result = new
|
||||
{
|
||||
userId = User.FindAuthUserId(),
|
||||
error = (object) null,
|
||||
returnVanity = new
|
||||
{
|
||||
userId = User.FindAuthUserId(),
|
||||
error = (object) null,
|
||||
returnVanity = new
|
||||
head_item = new
|
||||
{
|
||||
userId = User.FindAuthUserId(),
|
||||
head_item = new
|
||||
{
|
||||
id = "Black02M_Head1",
|
||||
materialIndex = 0,
|
||||
},
|
||||
boots_item = new
|
||||
{
|
||||
id = "StarterOutfit01_Boots_M",
|
||||
materialIndex = 0,
|
||||
},
|
||||
chest_item = new
|
||||
{
|
||||
id = "StarterOutfit01_Chest_M",
|
||||
materialIndex = 0,
|
||||
},
|
||||
glove_item = new
|
||||
{
|
||||
id = "StarterOutfit01_Gloves_M",
|
||||
materialIndex = 0,
|
||||
},
|
||||
base_suit_item = new
|
||||
{
|
||||
id = "StarterOutfit01M_BaseSuit",
|
||||
materialIndex = 0,
|
||||
},
|
||||
melee_weapon_item = new
|
||||
{
|
||||
id = "Melee_Omega",
|
||||
materialIndex = 0,
|
||||
},
|
||||
body_type = 1,
|
||||
archetype_id = "TheProspector",
|
||||
slot_index = 0
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "SetMatchAllowJoin":
|
||||
result = new
|
||||
{
|
||||
sessionId = (object)null,
|
||||
success = false
|
||||
};
|
||||
break;
|
||||
case "GetFriendList":
|
||||
// TODO: ?
|
||||
result = new
|
||||
{
|
||||
|
||||
};
|
||||
break;
|
||||
case "GetPlayerSets":
|
||||
result = new
|
||||
{
|
||||
success = true,
|
||||
entries = new []
|
||||
{
|
||||
new
|
||||
{
|
||||
setData = new
|
||||
{
|
||||
id = "",
|
||||
userId = User.FindAuthUserId(),
|
||||
kit = "",
|
||||
shield = "",
|
||||
helmet = "",
|
||||
weaponOne = "",
|
||||
weaponTwo = "",
|
||||
bag = "",
|
||||
bagItemsAsJsonStr = "",
|
||||
safeItemsAsJsonStr = ""
|
||||
},
|
||||
items = Array.Empty<object>()
|
||||
}
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "RequestFactionProgression":
|
||||
result = new
|
||||
{
|
||||
factions = new []
|
||||
{
|
||||
new
|
||||
{
|
||||
factionId = "ICA",
|
||||
currentProgression = 0
|
||||
},
|
||||
new
|
||||
{
|
||||
factionId = "Korolev",
|
||||
currentProgression = 0
|
||||
},
|
||||
new
|
||||
{
|
||||
factionId = "Osiris",
|
||||
currentProgression = 0
|
||||
},
|
||||
id = "Black02M_Head1",
|
||||
materialIndex = 0,
|
||||
},
|
||||
userId = User.FindAuthUserId(),
|
||||
error = ""
|
||||
};
|
||||
break;
|
||||
case "GetPlayersInventoriesLimits":
|
||||
result = new
|
||||
{
|
||||
success = true,
|
||||
entries = new []
|
||||
boots_item = new
|
||||
{
|
||||
new {
|
||||
id = "StarterOutfit01_Boots_M",
|
||||
materialIndex = 0,
|
||||
},
|
||||
chest_item = new
|
||||
{
|
||||
id = "StarterOutfit01_Chest_M",
|
||||
materialIndex = 0,
|
||||
},
|
||||
glove_item = new
|
||||
{
|
||||
id = "StarterOutfit01_Gloves_M",
|
||||
materialIndex = 0,
|
||||
},
|
||||
base_suit_item = new
|
||||
{
|
||||
id = "StarterOutfit01M_BaseSuit",
|
||||
materialIndex = 0,
|
||||
},
|
||||
melee_weapon_item = new
|
||||
{
|
||||
id = "Melee_Omega",
|
||||
materialIndex = 0,
|
||||
},
|
||||
body_type = 1,
|
||||
archetype_id = "TheProspector",
|
||||
slot_index = 0
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "SetMatchAllowJoin":
|
||||
result = new
|
||||
{
|
||||
sessionId = (object)null,
|
||||
success = false
|
||||
};
|
||||
break;
|
||||
case "GetFriendList":
|
||||
// TODO: ?
|
||||
result = new
|
||||
{
|
||||
|
||||
};
|
||||
break;
|
||||
case "GetPlayerSets":
|
||||
result = new
|
||||
{
|
||||
success = true,
|
||||
entries = new []
|
||||
{
|
||||
new
|
||||
{
|
||||
setData = new
|
||||
{
|
||||
id = "",
|
||||
userId = User.FindAuthUserId(),
|
||||
inventoryStashLimit = 75,
|
||||
inventoryBagLimit = 300,
|
||||
inventorySafeLimit = 5
|
||||
}
|
||||
kit = "",
|
||||
shield = "",
|
||||
helmet = "",
|
||||
weaponOne = "",
|
||||
weaponTwo = "",
|
||||
bag = "",
|
||||
bagItemsAsJsonStr = "",
|
||||
safeItemsAsJsonStr = ""
|
||||
},
|
||||
items = Array.Empty<object>()
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "UpdateRetentionBonus":
|
||||
result = new
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "RequestFactionProgression":
|
||||
result = new
|
||||
{
|
||||
factions = new []
|
||||
{
|
||||
playerData = new
|
||||
new
|
||||
{
|
||||
daysClaimed = 0,
|
||||
lastClaimTime = new
|
||||
{
|
||||
seconds = 1635033600
|
||||
}
|
||||
factionId = "ICA",
|
||||
currentProgression = 0
|
||||
},
|
||||
userId = User.FindAuthUserId(),
|
||||
error = (object)null
|
||||
};
|
||||
break;
|
||||
case "GetCraftingInProgressData":
|
||||
result = new FYGetCraftingInProgressDataResult
|
||||
{
|
||||
UserId = User.FindAuthUserId(),
|
||||
Error = null,
|
||||
ItemCurrentlyBeingCrafted = new FYItemCurrentlyBeingCrafted
|
||||
new
|
||||
{
|
||||
ItemId = null,
|
||||
ItemRarity = -1,
|
||||
PurchaseAmount = -1,
|
||||
UtcTimestampWhenCraftingStarted = new FYTimestamp
|
||||
{
|
||||
Seconds = 0
|
||||
}
|
||||
factionId = "Korolev",
|
||||
currentProgression = 0
|
||||
},
|
||||
new
|
||||
{
|
||||
factionId = "Osiris",
|
||||
currentProgression = 0
|
||||
},
|
||||
},
|
||||
userId = User.FindAuthUserId(),
|
||||
error = ""
|
||||
};
|
||||
break;
|
||||
case "GetPlayersInventoriesLimits":
|
||||
result = new
|
||||
{
|
||||
success = true,
|
||||
entries = new []
|
||||
{
|
||||
new {
|
||||
userId = User.FindAuthUserId(),
|
||||
inventoryStashLimit = 75,
|
||||
inventoryBagLimit = 300,
|
||||
inventorySafeLimit = 5
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "RequestPlayerContracts":
|
||||
result = new FYGetPlayerContractsResult
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "UpdateRetentionBonus":
|
||||
result = new
|
||||
{
|
||||
playerData = new
|
||||
{
|
||||
UserId = User.FindAuthUserId(),
|
||||
Error = null,
|
||||
ActiveContracts = new List<FYActiveContractPlayerData>(),
|
||||
FactionsContracts = new FYFactionsContractsData
|
||||
daysClaimed = 0,
|
||||
lastClaimTime = new
|
||||
{
|
||||
Boards = new List<FYFactionContractsData>
|
||||
seconds = 1635033600
|
||||
}
|
||||
},
|
||||
userId = User.FindAuthUserId(),
|
||||
error = (object)null
|
||||
};
|
||||
break;
|
||||
case "GetCraftingInProgressData":
|
||||
result = new FYGetCraftingInProgressDataResult
|
||||
{
|
||||
UserId = User.FindAuthUserId(),
|
||||
Error = null,
|
||||
ItemCurrentlyBeingCrafted = new FYItemCurrentlyBeingCrafted
|
||||
{
|
||||
ItemId = null,
|
||||
ItemRarity = -1,
|
||||
PurchaseAmount = -1,
|
||||
UtcTimestampWhenCraftingStarted = new FYTimestamp
|
||||
{
|
||||
Seconds = 0
|
||||
}
|
||||
}
|
||||
};
|
||||
break;
|
||||
case "RequestPlayerContracts":
|
||||
result = new FYGetPlayerContractsResult
|
||||
{
|
||||
UserId = User.FindAuthUserId(),
|
||||
Error = null,
|
||||
ActiveContracts = new List<FYActiveContractPlayerData>(),
|
||||
FactionsContracts = new FYFactionsContractsData
|
||||
{
|
||||
Boards = new List<FYFactionContractsData>
|
||||
{
|
||||
new FYFactionContractsData
|
||||
{
|
||||
new FYFactionContractsData
|
||||
FactionId = "ICA",
|
||||
Contracts = new List<FYFactionContractData>
|
||||
{
|
||||
FactionId = "ICA",
|
||||
Contracts = new List<FYFactionContractData>
|
||||
new FYFactionContractData
|
||||
{
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Easy-ICA-Gather-1",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
},
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Medium-ICA-Uplink-1",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
},
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Hard-ICA-Uplink-1",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
}
|
||||
}
|
||||
},
|
||||
new FYFactionContractsData
|
||||
{
|
||||
FactionId = "Korolev",
|
||||
Contracts = new List<FYFactionContractData>
|
||||
ContractId = "NEW-Easy-ICA-Gather-1",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
},
|
||||
new FYFactionContractData
|
||||
{
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Easy-KOR-Mine-4",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
},
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Medium-KOR-Mine-1",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
},
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Hard-KOR-PvP-6",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
}
|
||||
}
|
||||
},
|
||||
new FYFactionContractsData
|
||||
{
|
||||
FactionId = "Osiris",
|
||||
Contracts = new List<FYFactionContractData>
|
||||
ContractId = "NEW-Medium-ICA-Uplink-1",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
},
|
||||
new FYFactionContractData
|
||||
{
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Easy-Osiris-Brightcaps-1",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
},
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Medium-Osiris-Gather-1",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
},
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Hard-Osiris-Gather-7",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
}
|
||||
ContractId = "NEW-Hard-ICA-Uplink-1",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
}
|
||||
}
|
||||
},
|
||||
LastBoardRefreshTimeUtc = new FYTimestamp
|
||||
new FYFactionContractsData
|
||||
{
|
||||
Seconds = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds()
|
||||
FactionId = "Korolev",
|
||||
Contracts = new List<FYFactionContractData>
|
||||
{
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Easy-KOR-Mine-4",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
},
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Medium-KOR-Mine-1",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
},
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Hard-KOR-PvP-6",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
}
|
||||
}
|
||||
},
|
||||
new FYFactionContractsData
|
||||
{
|
||||
FactionId = "Osiris",
|
||||
Contracts = new List<FYFactionContractData>
|
||||
{
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Easy-Osiris-Brightcaps-1",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
},
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Medium-Osiris-Gather-1",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
},
|
||||
new FYFactionContractData
|
||||
{
|
||||
ContractId = "NEW-Hard-Osiris-Gather-7",
|
||||
ContractIsLockedDueToLowFactionReputation = false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
RefreshHours24UtcFromBackend = 12
|
||||
};
|
||||
break;
|
||||
default:
|
||||
_logger.LogWarning("Missing function {Function}", request.FunctionName);
|
||||
LastBoardRefreshTimeUtc = new FYTimestamp
|
||||
{
|
||||
Seconds = (int)DateTimeOffset.UtcNow.ToUnixTimeSeconds()
|
||||
}
|
||||
},
|
||||
RefreshHours24UtcFromBackend = 12
|
||||
};
|
||||
break;
|
||||
default:
|
||||
_logger.LogWarning("Missing function {Function}", request.FunctionName);
|
||||
|
||||
result = new
|
||||
{
|
||||
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
return Ok(new ClientResponse<FExecuteFunctionResult>
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FExecuteFunctionResult
|
||||
result = new
|
||||
{
|
||||
ExecutionTimeMilliseconds = 12,
|
||||
FunctionName = request.FunctionName,
|
||||
FunctionResult = result
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
return Ok(new ClientResponse<FExecuteFunctionResult>
|
||||
{
|
||||
Code = 200,
|
||||
Status = "OK",
|
||||
Data = new FExecuteFunctionResult
|
||||
{
|
||||
ExecutionTimeMilliseconds = 12,
|
||||
FunctionName = request.FunctionName,
|
||||
FunctionResult = result
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,22 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Converters
|
||||
{
|
||||
// By default System.Text.Json outputs and we want:
|
||||
// Output: 2021-11-04T04:58:20.4232184Z
|
||||
// Want : 2021-10-24T02:54:56.652Z
|
||||
public class DateTimeConverter : JsonConverter<DateTime>
|
||||
{
|
||||
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
Debug.Assert(typeToConvert == typeof(DateTime));
|
||||
return DateTime.Parse(reader.GetString());
|
||||
}
|
||||
namespace Prospect.Server.Api.Converters;
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK"));
|
||||
}
|
||||
// By default System.Text.Json outputs and we want:
|
||||
// Output: 2021-11-04T04:58:20.4232184Z
|
||||
// Want : 2021-10-24T02:54:56.652Z
|
||||
public class DateTimeConverter : JsonConverter<DateTime>
|
||||
{
|
||||
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
Debug.Assert(typeToConvert == typeof(DateTime));
|
||||
return DateTime.Parse(reader.GetString());
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fffK"));
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,22 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Exceptions
|
||||
namespace Prospect.Server.Api.Exceptions;
|
||||
|
||||
public class ProspectException : Exception
|
||||
{
|
||||
public class ProspectException : Exception
|
||||
public ProspectException()
|
||||
{
|
||||
public ProspectException()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
protected ProspectException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
protected ProspectException(SerializationInfo info, StreamingContext context) : base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public ProspectException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
public ProspectException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public ProspectException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
public ProspectException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,64 +1,59 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Prospect.Server.Api.Middleware
|
||||
namespace Prospect.Server.Api.Middleware;
|
||||
|
||||
public class RequestLoggerMiddleware
|
||||
{
|
||||
public class RequestLoggerMiddleware
|
||||
private readonly ILogger<RequestLoggerMiddleware> _logger;
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
public RequestLoggerMiddleware(ILogger<RequestLoggerMiddleware> logger, RequestDelegate next)
|
||||
{
|
||||
private readonly ILogger<RequestLoggerMiddleware> _logger;
|
||||
private readonly RequestDelegate _next;
|
||||
_logger = logger;
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public RequestLoggerMiddleware(ILogger<RequestLoggerMiddleware> logger, RequestDelegate next)
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
var body = await RequestAsync(context.Request);
|
||||
|
||||
if (context.Request.Method == "POST")
|
||||
{
|
||||
_logger = logger;
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
var body = await RequestAsync(context.Request);
|
||||
|
||||
if (context.Request.Method == "POST")
|
||||
var requestId = "NULL";
|
||||
|
||||
if (context.Request.Headers.TryGetValue("X-RequestID", out var requestIdValues))
|
||||
{
|
||||
var requestId = "NULL";
|
||||
|
||||
if (context.Request.Headers.TryGetValue("X-RequestID", out var requestIdValues))
|
||||
{
|
||||
requestId = requestIdValues.ToString();
|
||||
}
|
||||
|
||||
_logger.LogDebug("URL {Url} RequestId {RequestId} Body {Body}", context.Request.GetDisplayUrl(), requestId, body);
|
||||
requestId = requestIdValues.ToString();
|
||||
}
|
||||
|
||||
_logger.LogDebug("URL {Url} RequestId {RequestId} Body {Body}", context.Request.GetDisplayUrl(), requestId, body);
|
||||
}
|
||||
|
||||
await _next(context);
|
||||
}
|
||||
await _next(context);
|
||||
}
|
||||
|
||||
private static async Task<string> RequestAsync(HttpRequest request)
|
||||
private static async Task<string> RequestAsync(HttpRequest request)
|
||||
{
|
||||
request.EnableBuffering();
|
||||
|
||||
try
|
||||
{
|
||||
request.EnableBuffering();
|
||||
|
||||
try
|
||||
using (var reader = new StreamReader(request.Body, Encoding.UTF8, false, 4096, true))
|
||||
{
|
||||
using (var reader = new StreamReader(request.Body, Encoding.UTF8, false, 4096, true))
|
||||
var body = await reader.ReadToEndAsync();
|
||||
if (body.StartsWith("{"))
|
||||
{
|
||||
var body = await reader.ReadToEndAsync();
|
||||
if (body.StartsWith("{"))
|
||||
{
|
||||
return JsonConvert.SerializeObject(JsonConvert.DeserializeObject(body), Formatting.Indented);
|
||||
}
|
||||
|
||||
return body;
|
||||
return JsonConvert.SerializeObject(JsonConvert.DeserializeObject(body), Formatting.Indented);
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
finally
|
||||
{
|
||||
request.Body.Position = 0;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
request.Body.Position = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,58 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class ClientLoginWithSteamRequest
|
||||
{
|
||||
public class ClientLoginWithSteamRequest
|
||||
{
|
||||
[JsonPropertyName("CreateAccount")]
|
||||
public bool CreateAccount { get; set; }
|
||||
[JsonPropertyName("CreateAccount")]
|
||||
public bool CreateAccount { get; set; }
|
||||
|
||||
[JsonPropertyName("CustomTags")]
|
||||
public JsonDocument CustomTags { get; set; }
|
||||
[JsonPropertyName("CustomTags")]
|
||||
public JsonDocument CustomTags { get; set; }
|
||||
|
||||
[JsonPropertyName("EncryptedRequest")]
|
||||
public string EncryptedRequest { get; set; }
|
||||
[JsonPropertyName("EncryptedRequest")]
|
||||
public string EncryptedRequest { get; set; }
|
||||
|
||||
[JsonPropertyName("InfoRequestParameters")]
|
||||
public InfoParameters InfoRequestParameters { get; set; }
|
||||
[JsonPropertyName("InfoRequestParameters")]
|
||||
public InfoParameters InfoRequestParameters { get; set; }
|
||||
|
||||
[JsonPropertyName("PlayerSecret")]
|
||||
public string PlayerSecret { get; set; }
|
||||
[JsonPropertyName("PlayerSecret")]
|
||||
public string PlayerSecret { get; set; }
|
||||
|
||||
[JsonPropertyName("SteamTicket")]
|
||||
public string SteamTicket { get; set; }
|
||||
}
|
||||
[JsonPropertyName("SteamTicket")]
|
||||
public string SteamTicket { get; set; }
|
||||
}
|
||||
|
||||
public class InfoParameters
|
||||
{
|
||||
[JsonPropertyName("GetCharacterInventories")]
|
||||
public bool GetCharacterInventories { get; set; }
|
||||
public class InfoParameters
|
||||
{
|
||||
[JsonPropertyName("GetCharacterInventories")]
|
||||
public bool GetCharacterInventories { get; set; }
|
||||
|
||||
[JsonPropertyName("GetCharacterList")]
|
||||
public bool GetCharacterList { get; set; }
|
||||
[JsonPropertyName("GetCharacterList")]
|
||||
public bool GetCharacterList { get; set; }
|
||||
|
||||
[JsonPropertyName("GetPlayerProfile")]
|
||||
public bool GetPlayerProfile { get; set; }
|
||||
[JsonPropertyName("GetPlayerProfile")]
|
||||
public bool GetPlayerProfile { get; set; }
|
||||
|
||||
[JsonPropertyName("GetPlayerStatistics")]
|
||||
public bool GetPlayerStatistics { get; set; }
|
||||
[JsonPropertyName("GetPlayerStatistics")]
|
||||
public bool GetPlayerStatistics { get; set; }
|
||||
|
||||
[JsonPropertyName("GetTitleData")]
|
||||
public bool GetTitleData { get; set; }
|
||||
[JsonPropertyName("GetTitleData")]
|
||||
public bool GetTitleData { get; set; }
|
||||
|
||||
[JsonPropertyName("GetUserAccountInfo")]
|
||||
public bool GetUserAccountInfo { get; set; }
|
||||
[JsonPropertyName("GetUserAccountInfo")]
|
||||
public bool GetUserAccountInfo { get; set; }
|
||||
|
||||
[JsonPropertyName("GetUserData")]
|
||||
public bool GetUserData { get; set; }
|
||||
[JsonPropertyName("GetUserData")]
|
||||
public bool GetUserData { get; set; }
|
||||
|
||||
[JsonPropertyName("GetUserInventory")]
|
||||
public bool GetUserInventory { get; set; }
|
||||
[JsonPropertyName("GetUserInventory")]
|
||||
public bool GetUserInventory { get; set; }
|
||||
|
||||
[JsonPropertyName("GetUserReadOnlyData")]
|
||||
public bool GetUserReadOnlyData { get; set; }
|
||||
[JsonPropertyName("GetUserReadOnlyData")]
|
||||
public bool GetUserReadOnlyData { get; set; }
|
||||
|
||||
[JsonPropertyName("GetUserVirtualCurrency")]
|
||||
public bool GetUserVirtualCurrency { get; set; }
|
||||
}
|
||||
[JsonPropertyName("GetUserVirtualCurrency")]
|
||||
public bool GetUserVirtualCurrency { get; set; }
|
||||
}
|
||||
@@ -1,32 +1,31 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class ClientResponse
|
||||
{
|
||||
public class ClientResponse
|
||||
{
|
||||
[JsonPropertyName("code")]
|
||||
public int Code { get; set; }
|
||||
[JsonPropertyName("code")]
|
||||
public int Code { get; set; }
|
||||
|
||||
[JsonPropertyName("status")]
|
||||
public string Status { get; set; }
|
||||
[JsonPropertyName("status")]
|
||||
public string Status { get; set; }
|
||||
|
||||
[JsonPropertyName("error")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Error { get; set; }
|
||||
[JsonPropertyName("error")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Error { get; set; }
|
||||
|
||||
[JsonPropertyName("errorCode")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int ErrorCode { get; set; }
|
||||
[JsonPropertyName("errorCode")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int ErrorCode { get; set; }
|
||||
|
||||
[JsonPropertyName("errorMessage")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
[JsonPropertyName("errorMessage")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string ErrorMessage { get; set; }
|
||||
}
|
||||
|
||||
public class ClientResponse<T> : ClientResponse
|
||||
{
|
||||
[JsonPropertyName("data")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public T Data { get; set; }
|
||||
}
|
||||
public class ClientResponse<T> : ClientResponse
|
||||
{
|
||||
[JsonPropertyName("data")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public T Data { get; set; }
|
||||
}
|
||||
@@ -1,9 +1,8 @@
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public enum CloudScriptRevisionOption
|
||||
{
|
||||
public enum CloudScriptRevisionOption
|
||||
{
|
||||
Live,
|
||||
Latest,
|
||||
Specific
|
||||
}
|
||||
Live,
|
||||
Latest,
|
||||
Specific
|
||||
}
|
||||
@@ -1,23 +1,22 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FEntityKey
|
||||
{
|
||||
public class FEntityKey
|
||||
{
|
||||
/// <summary>
|
||||
/// Unique ID of the entity.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Id")]
|
||||
public string Id { get; set; }
|
||||
/// <summary>
|
||||
/// Unique ID of the entity.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Id")]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Entity type. See https://docs.microsoft.com/gaming/playfab/features/data/entities/available-built-in-entity-types
|
||||
/// </summary>
|
||||
[JsonPropertyName("Type")]
|
||||
public string Type { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Entity type. See https://docs.microsoft.com/gaming/playfab/features/data/entities/available-built-in-entity-types
|
||||
/// </summary>
|
||||
[JsonPropertyName("Type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
// Not in PlayFab SDK
|
||||
[JsonPropertyName("TypeString")]
|
||||
public string TypeString { get; set; }
|
||||
}
|
||||
// Not in PlayFab SDK
|
||||
[JsonPropertyName("TypeString")]
|
||||
public string TypeString { get; set; }
|
||||
}
|
||||
@@ -1,29 +1,27 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FEntityTokenResponse
|
||||
{
|
||||
public class FEntityTokenResponse
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] The entity id and type.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Entity")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FEntityKey Entity { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] The entity id and type.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Entity")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FEntityKey Entity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The token used to set X-EntityToken for all entity based API calls.
|
||||
/// </summary>
|
||||
[JsonPropertyName("EntityToken")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string EntityToken { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] The token used to set X-EntityToken for all entity based API calls.
|
||||
/// </summary>
|
||||
[JsonPropertyName("EntityToken")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string EntityToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The time the token will expire, if it is an expiring token, in UTC.
|
||||
/// </summary>
|
||||
[JsonPropertyName("TokenExpiration")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public DateTime? TokenExpiration { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] The time the token will expire, if it is an expiring token, in UTC.
|
||||
/// </summary>
|
||||
[JsonPropertyName("TokenExpiration")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public DateTime? TokenExpiration { get; set; }
|
||||
}
|
||||
@@ -1,29 +1,28 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FFunctionExecutionError
|
||||
{
|
||||
public class FFunctionExecutionError
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] Error code, such as CloudScriptAzureFunctionsExecutionTimeLimitExceeded, CloudScriptAzureFunctionsArgumentSizeExceeded,
|
||||
/// CloudScriptAzureFunctionsReturnSizeExceeded or CloudScriptAzureFunctionsHTTPRequestError
|
||||
/// </summary>
|
||||
[JsonPropertyName("Error")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Error { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Error code, such as CloudScriptAzureFunctionsExecutionTimeLimitExceeded, CloudScriptAzureFunctionsArgumentSizeExceeded,
|
||||
/// CloudScriptAzureFunctionsReturnSizeExceeded or CloudScriptAzureFunctionsHTTPRequestError
|
||||
/// </summary>
|
||||
[JsonPropertyName("Error")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Details about the error
|
||||
/// </summary>
|
||||
[JsonPropertyName("Message")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Message { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Details about the error
|
||||
/// </summary>
|
||||
[JsonPropertyName("Message")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Point during the execution of the function at which the error occurred, if any
|
||||
/// </summary>
|
||||
[JsonPropertyName("StackTrace")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string StackTrace { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] Point during the execution of the function at which the error occurred, if any
|
||||
/// </summary>
|
||||
[JsonPropertyName("StackTrace")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string StackTrace { get; set; }
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FGenericServiceId
|
||||
{
|
||||
public class FGenericServiceId
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the service for which the player has a unique identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ServiceName")]
|
||||
public string ServiceName { get; set; }
|
||||
/// <summary>
|
||||
/// Name of the service for which the player has a unique identifier.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ServiceName")]
|
||||
public string ServiceName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique identifier of the player in that service.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UserId")]
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Unique identifier of the player in that service.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UserId")]
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
@@ -1,60 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FGetPlayerCombinedInfoResultPayload
|
||||
{
|
||||
public class FGetPlayerCombinedInfoResultPayload
|
||||
{
|
||||
// TSharedPtr<FUserAccountInfo> AccountInfo;
|
||||
// TSharedPtr<FUserAccountInfo> AccountInfo;
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Inventories for each character for the user.
|
||||
/// </summary>
|
||||
[JsonPropertyName("CharacterInventories")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<object> CharacterInventories { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Inventories for each character for the user.
|
||||
/// </summary>
|
||||
[JsonPropertyName("CharacterInventories")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<object> CharacterInventories { get; set; }
|
||||
|
||||
// TArray<FCharacterResult> CharacterList;
|
||||
// TArray<FCharacterResult> CharacterList;
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The profile of the players. This profile is not guaranteed to be up-to-date. For a new player, this profile will not
|
||||
/// exist.
|
||||
/// </summary>
|
||||
[JsonPropertyName("PlayerProfile")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FPlayerProfileModel PlayerProfile { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] The profile of the players. This profile is not guaranteed to be up-to-date. For a new player, this profile will not
|
||||
/// exist.
|
||||
/// </summary>
|
||||
[JsonPropertyName("PlayerProfile")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FPlayerProfileModel PlayerProfile { get; set; }
|
||||
|
||||
// TArray<FStatisticValue> PlayerStatistics;
|
||||
// TArray<FStatisticValue> PlayerStatistics;
|
||||
|
||||
// TMap<FString, FString> TitleData;
|
||||
// TMap<FString, FString> TitleData;
|
||||
|
||||
// TMap<FString, FUserDataRecord> UserData;
|
||||
// TMap<FString, FUserDataRecord> UserData;
|
||||
|
||||
/// <summary>
|
||||
/// The version of the UserData that was returned.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UserDataVersion")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public uint? UserDataVersion { get; set; }
|
||||
/// <summary>
|
||||
/// The version of the UserData that was returned.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UserDataVersion")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public uint? UserDataVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Array of inventory items in the user's current inventory.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UserInventory")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<object> UserInventory { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Array of inventory items in the user's current inventory.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UserInventory")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<object> UserInventory { get; set; }
|
||||
|
||||
// TMap<FString, FUserDataRecord> UserReadOnlyData;
|
||||
// TMap<FString, FUserDataRecord> UserReadOnlyData;
|
||||
|
||||
/// <summary>
|
||||
/// The version of the Read-Only UserData that was returned.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UserReadOnlyDataVersion")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public uint? UserReadOnlyDataVersion { get; set; }
|
||||
/// <summary>
|
||||
/// The version of the Read-Only UserData that was returned.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UserReadOnlyDataVersion")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public uint? UserReadOnlyDataVersion { get; set; }
|
||||
|
||||
// TMap<FString, int32> UserVirtualCurrency;
|
||||
// TMap<FString, int32> UserVirtualCurrency;
|
||||
|
||||
// TMap<FString, FVirtualCurrencyRechargeTime> UserVirtualCurrencyRechargeTimes;
|
||||
}
|
||||
// TMap<FString, FVirtualCurrencyRechargeTime> UserVirtualCurrencyRechargeTimes;
|
||||
}
|
||||
@@ -1,116 +1,113 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FItemInstance
|
||||
{
|
||||
public class FItemInstance
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] Game specific comment associated with this instance when it was added to the user inventory.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Annotation")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Annotation { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Game specific comment associated with this instance when it was added to the user inventory.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Annotation")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Annotation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Array of unique items that were awarded when this catalog item was purchased.
|
||||
/// </summary>
|
||||
[JsonPropertyName("BundleContents")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<string> BundleContents { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Array of unique items that were awarded when this catalog item was purchased.
|
||||
/// </summary>
|
||||
[JsonPropertyName("BundleContents")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<string> BundleContents { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Unique identifier for the parent inventory item, as defined in the catalog, for object which were added from a bundle or
|
||||
/// container.
|
||||
/// </summary>
|
||||
[JsonPropertyName("BundleParent")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string BundleParent { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Unique identifier for the parent inventory item, as defined in the catalog, for object which were added from a bundle or
|
||||
/// container.
|
||||
/// </summary>
|
||||
[JsonPropertyName("BundleParent")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string BundleParent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Catalog version for the inventory item, when this instance was created.
|
||||
/// </summary>
|
||||
[JsonPropertyName("CatalogVersion")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string CatalogVersion { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Catalog version for the inventory item, when this instance was created.
|
||||
/// </summary>
|
||||
[JsonPropertyName("CatalogVersion")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string CatalogVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] A set of custom key-value pairs on the instance of the inventory item, which is not to be confused with the catalog
|
||||
/// item's custom data.
|
||||
/// </summary>
|
||||
[JsonPropertyName("CustomData")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, string> CustomData { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] A set of custom key-value pairs on the instance of the inventory item, which is not to be confused with the catalog
|
||||
/// item's custom data.
|
||||
/// </summary>
|
||||
[JsonPropertyName("CustomData")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, string> CustomData { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] CatalogItem.DisplayName at the time this item was purchased.
|
||||
/// </summary>
|
||||
[JsonPropertyName("DisplayName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string DisplayName { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] CatalogItem.DisplayName at the time this item was purchased.
|
||||
/// </summary>
|
||||
[JsonPropertyName("DisplayName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Timestamp for when this instance will expire.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Expiration")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public DateTime? Expiration { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Timestamp for when this instance will expire.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Expiration")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public DateTime? Expiration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Class name for the inventory item, as defined in the catalog.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ItemClass")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string ItemClass { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Class name for the inventory item, as defined in the catalog.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ItemClass")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string ItemClass { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Unique identifier for the inventory item, as defined in the catalog.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ItemId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string ItemId { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Unique identifier for the inventory item, as defined in the catalog.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ItemId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string ItemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Unique item identifier for this specific instance of the item.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ItemInstanceId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string ItemInstanceId { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Unique item identifier for this specific instance of the item.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ItemInstanceId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string ItemInstanceId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Timestamp for when this instance was purchased.
|
||||
/// </summary>
|
||||
[JsonPropertyName("PurchaseDate")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public DateTime? PurchaseDate { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Timestamp for when this instance was purchased.
|
||||
/// </summary>
|
||||
[JsonPropertyName("PurchaseDate")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public DateTime? PurchaseDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Total number of remaining uses, if this is a consumable item.
|
||||
/// </summary>
|
||||
[JsonPropertyName("RemainingUses")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int? RemainingUses { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Total number of remaining uses, if this is a consumable item.
|
||||
/// </summary>
|
||||
[JsonPropertyName("RemainingUses")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int? RemainingUses { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Currency type for the cost of the catalog item. Not available when granting items.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UnitCurrency")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string UnitCurrency { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Currency type for the cost of the catalog item. Not available when granting items.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UnitCurrency")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string UnitCurrency { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Cost of the catalog item in the given currency. Not available when granting items.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UnitPrice")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public uint? UnitPrice { get; set; }
|
||||
/// <summary>
|
||||
/// Cost of the catalog item in the given currency. Not available when granting items.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UnitPrice")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public uint? UnitPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The number of uses that were added or removed to this item in this call.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UsesIncrementedBy")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int? UsesIncrementedBy { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] The number of uses that were added or removed to this item in this call.
|
||||
/// </summary>
|
||||
[JsonPropertyName("UsesIncrementedBy")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int? UsesIncrementedBy { get; set; }
|
||||
}
|
||||
@@ -1,28 +1,27 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FLogStatement
|
||||
{
|
||||
public class FLogStatement
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] Optional object accompanying the message as contextual information
|
||||
/// </summary>
|
||||
[JsonPropertyName("Data")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public object Data { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Optional object accompanying the message as contextual information
|
||||
/// </summary>
|
||||
[JsonPropertyName("Data")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public object Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] 'Debug', 'Info', or 'Error'
|
||||
/// </summary>
|
||||
[JsonPropertyName("Level")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Level { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] 'Debug', 'Info', or 'Error'
|
||||
/// </summary>
|
||||
[JsonPropertyName("Level")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] undefined
|
||||
/// </summary>
|
||||
[JsonPropertyName("Message")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Message { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] undefined
|
||||
/// </summary>
|
||||
[JsonPropertyName("Message")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Message { get; set; }
|
||||
}
|
||||
@@ -1,35 +1,34 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
{
|
||||
public class FPlayerProfileModel
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] Player display name
|
||||
/// </summary>
|
||||
[JsonPropertyName("DisplayName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] PlayFab player account unique identifier
|
||||
/// </summary>
|
||||
[JsonPropertyName("PlayerId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string PlayerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Publisher this player belongs to
|
||||
/// </summary>
|
||||
[JsonPropertyName("PublisherId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string PublisherId { get; set; }
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Title ID this player profile applies to
|
||||
/// </summary>
|
||||
[JsonPropertyName("TitleId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string TitleId { get; set; }
|
||||
}
|
||||
public class FPlayerProfileModel
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] Player display name
|
||||
/// </summary>
|
||||
[JsonPropertyName("DisplayName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] PlayFab player account unique identifier
|
||||
/// </summary>
|
||||
[JsonPropertyName("PlayerId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string PlayerId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Publisher this player belongs to
|
||||
/// </summary>
|
||||
[JsonPropertyName("PublisherId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string PublisherId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Title ID this player profile applies to
|
||||
/// </summary>
|
||||
[JsonPropertyName("TitleId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string TitleId { get; set; }
|
||||
}
|
||||
@@ -1,29 +1,28 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FScriptExecutionError
|
||||
{
|
||||
public class FScriptExecutionError
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] Error code, such as CloudScriptNotFound, JavascriptException, CloudScriptFunctionArgumentSizeExceeded,
|
||||
/// CloudScriptAPIRequestCountExceeded, CloudScriptAPIRequestError, or CloudScriptHTTPRequestError
|
||||
/// </summary>
|
||||
[JsonPropertyName("Error")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Error { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Error code, such as CloudScriptNotFound, JavascriptException, CloudScriptFunctionArgumentSizeExceeded,
|
||||
/// CloudScriptAPIRequestCountExceeded, CloudScriptAPIRequestError, or CloudScriptHTTPRequestError
|
||||
/// </summary>
|
||||
[JsonPropertyName("Error")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Details about the error
|
||||
/// </summary>
|
||||
[JsonPropertyName("Message")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Message { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Details about the error
|
||||
/// </summary>
|
||||
[JsonPropertyName("Message")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Point during the execution of the script at which the error occurred, if any
|
||||
/// </summary>
|
||||
[JsonPropertyName("StackTrace")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string StackTrace { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] Point during the execution of the script at which the error occurred, if any
|
||||
/// </summary>
|
||||
[JsonPropertyName("StackTrace")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string StackTrace { get; set; }
|
||||
}
|
||||
@@ -1,22 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FTreatmentAssignment
|
||||
{
|
||||
public class FTreatmentAssignment
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] List of the experiment variables.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Variables")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<FVariable> Variables { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] List of the experiment variables.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Variables")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<FVariable> Variables { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] List of the experiment variants.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Variants")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<string> Variants { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] List of the experiment variants.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Variants")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<string> Variants { get; set; }
|
||||
}
|
||||
@@ -1,29 +1,27 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FUserDataRecord
|
||||
{
|
||||
public class FUserDataRecord
|
||||
{
|
||||
/// <summary>
|
||||
/// Timestamp for when this data was last updated.
|
||||
/// </summary>
|
||||
[JsonPropertyName("LastUpdated")]
|
||||
public DateTime LastUpdated { get; set; }
|
||||
/// <summary>
|
||||
/// Timestamp for when this data was last updated.
|
||||
/// </summary>
|
||||
[JsonPropertyName("LastUpdated")]
|
||||
public DateTime LastUpdated { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Indicates whether this data can be read by all users (public) or only the user (private). This is used for GetUserData
|
||||
/// requests being made by one player about another player.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Permission")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public UserDataPermission Permission { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Indicates whether this data can be read by all users (public) or only the user (private). This is used for GetUserData
|
||||
/// requests being made by one player about another player.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Permission")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public UserDataPermission Permission { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Data stored for the specified user data key.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Value")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Value { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] Data stored for the specified user data key.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Value")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Value { get; set; }
|
||||
}
|
||||
@@ -1,25 +1,24 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FUserSettings
|
||||
{
|
||||
public class FUserSettings
|
||||
{
|
||||
/// <summary>
|
||||
/// Boolean for whether this player is eligible for gathering device info.
|
||||
/// </summary>
|
||||
[JsonPropertyName("GatherDeviceInfo")]
|
||||
public bool GatherDeviceInfo { get; set; }
|
||||
/// <summary>
|
||||
/// Boolean for whether this player is eligible for gathering device info.
|
||||
/// </summary>
|
||||
[JsonPropertyName("GatherDeviceInfo")]
|
||||
public bool GatherDeviceInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean for whether this player should report OnFocus play-time tracking.
|
||||
/// </summary>
|
||||
[JsonPropertyName("GatherFocusInfo")]
|
||||
public bool GatherFocusInfo { get; set; }
|
||||
/// <summary>
|
||||
/// Boolean for whether this player should report OnFocus play-time tracking.
|
||||
/// </summary>
|
||||
[JsonPropertyName("GatherFocusInfo")]
|
||||
public bool GatherFocusInfo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean for whether this player is eligible for ad tracking.
|
||||
/// </summary>
|
||||
[JsonPropertyName("NeedsAttribution")]
|
||||
public bool NeedsAttribution { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Boolean for whether this player is eligible for ad tracking.
|
||||
/// </summary>
|
||||
[JsonPropertyName("NeedsAttribution")]
|
||||
public bool NeedsAttribution { get; set; }
|
||||
}
|
||||
@@ -1,20 +1,19 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FVariable
|
||||
{
|
||||
public class FVariable
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the variable.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Name")]
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// Name of the variable.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Value of the variable.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Value")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Value { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] Value of the variable.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Value")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string Value { get; set; }
|
||||
}
|
||||
@@ -1,28 +1,26 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public class FVirtualCurrencyRechargeTime
|
||||
{
|
||||
public class FVirtualCurrencyRechargeTime
|
||||
{
|
||||
/// <summary>
|
||||
/// Maximum value to which the regenerating currency will automatically increment. Note that it can exceed this value
|
||||
/// through use of the AddUserVirtualCurrency API call. However, it will not regenerate automatically until it has fallen
|
||||
/// below this value.
|
||||
/// </summary>
|
||||
[JsonPropertyName("RechargeMax")]
|
||||
public int RechargeMax { get; set; }
|
||||
/// <summary>
|
||||
/// Maximum value to which the regenerating currency will automatically increment. Note that it can exceed this value
|
||||
/// through use of the AddUserVirtualCurrency API call. However, it will not regenerate automatically until it has fallen
|
||||
/// below this value.
|
||||
/// </summary>
|
||||
[JsonPropertyName("RechargeMax")]
|
||||
public int RechargeMax { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Server timestamp in UTC indicating the next time the virtual currency will be incremented.
|
||||
/// </summary>
|
||||
[JsonPropertyName("RechargeTime")]
|
||||
public DateTime RechargeTime { get; set; }
|
||||
/// <summary>
|
||||
/// Server timestamp in UTC indicating the next time the virtual currency will be incremented.
|
||||
/// </summary>
|
||||
[JsonPropertyName("RechargeTime")]
|
||||
public DateTime RechargeTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time remaining (in seconds) before the next recharge increment of the virtual currency.
|
||||
/// </summary>
|
||||
[JsonPropertyName("SecondsToRecharge")]
|
||||
public int SecondsToRecharge { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Time remaining (in seconds) before the next recharge increment of the virtual currency.
|
||||
/// </summary>
|
||||
[JsonPropertyName("SecondsToRecharge")]
|
||||
public int SecondsToRecharge { get; set; }
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace Prospect.Server.Api.Models.Client.Data
|
||||
namespace Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
public enum UserDataPermission
|
||||
{
|
||||
public enum UserDataPermission
|
||||
{
|
||||
Public,
|
||||
Private
|
||||
}
|
||||
Public,
|
||||
Private
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FAddGenericIDRequest
|
||||
{
|
||||
public class FAddGenericIDRequest
|
||||
{
|
||||
[JsonPropertyName("GenericId")]
|
||||
public FGenericServiceId GenericId { get; set; }
|
||||
}
|
||||
[JsonPropertyName("GenericId")]
|
||||
public FGenericServiceId GenericId { get; set; }
|
||||
}
|
||||
@@ -1,85 +1,83 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FExecuteCloudScriptResult
|
||||
{
|
||||
public class FExecuteCloudScriptResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Number of PlayFab API requests issued by the CloudScript function
|
||||
/// </summary>
|
||||
[JsonPropertyName("APIRequestsIssued")]
|
||||
public int APIRequestsIssued { get; set; }
|
||||
/// <summary>
|
||||
/// Number of PlayFab API requests issued by the CloudScript function
|
||||
/// </summary>
|
||||
[JsonPropertyName("APIRequestsIssued")]
|
||||
public int APIRequestsIssued { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Information about the error, if any, that occurred during execution
|
||||
/// </summary>
|
||||
[JsonPropertyName("Error")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FScriptExecutionError Error { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Information about the error, if any, that occurred during execution
|
||||
/// </summary>
|
||||
[JsonPropertyName("Error")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FScriptExecutionError Error { get; set; }
|
||||
|
||||
[JsonPropertyName("ExecutionTimeSeconds")]
|
||||
public double? ExecutionTimeSeconds { get; set; }
|
||||
[JsonPropertyName("ExecutionTimeSeconds")]
|
||||
public double? ExecutionTimeSeconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The name of the function that executed
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string FunctionName { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] The name of the function that executed
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionName")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string FunctionName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The object returned from the CloudScript function, if any
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionResult")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public object FunctionResult { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] The object returned from the CloudScript function, if any
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionResult")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public object FunctionResult { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Flag indicating if the FunctionResult was too large and was subsequently dropped from this event. This only occurs if
|
||||
/// the total event size is larger than 350KB.
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionResultTooLarge")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? FunctionResultTooLarge { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Flag indicating if the FunctionResult was too large and was subsequently dropped from this event. This only occurs if
|
||||
/// the total event size is larger than 350KB.
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionResultTooLarge")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? FunctionResultTooLarge { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of external HTTP requests issued by the CloudScript function
|
||||
/// </summary>
|
||||
[JsonPropertyName("HttpRequestsIssued")]
|
||||
public int HttpRequestsIssued { get; set; }
|
||||
/// <summary>
|
||||
/// Number of external HTTP requests issued by the CloudScript function
|
||||
/// </summary>
|
||||
[JsonPropertyName("HttpRequestsIssued")]
|
||||
public int HttpRequestsIssued { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Entries logged during the function execution. These include both entries logged in the function code using log.info()
|
||||
/// and log.error() and error entries for API and HTTP request failures.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Logs")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<FLogStatement> Logs { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Entries logged during the function execution. These include both entries logged in the function code using log.info()
|
||||
/// and log.error() and error entries for API and HTTP request failures.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Logs")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<FLogStatement> Logs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Flag indicating if the logs were too large and were subsequently dropped from this event. This only occurs if the total
|
||||
/// event size is larger than 350KB after the FunctionResult was removed.
|
||||
/// </summary>
|
||||
[JsonPropertyName("LogsTooLarge")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? LogsTooLarge { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Flag indicating if the logs were too large and were subsequently dropped from this event. This only occurs if the total
|
||||
/// event size is larger than 350KB after the FunctionResult was removed.
|
||||
/// </summary>
|
||||
[JsonPropertyName("LogsTooLarge")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? LogsTooLarge { get; set; }
|
||||
|
||||
[JsonPropertyName("MemoryConsumedBytes")]
|
||||
public uint MemoryConsumedBytes { get; set; }
|
||||
[JsonPropertyName("MemoryConsumedBytes")]
|
||||
public uint MemoryConsumedBytes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Processor time consumed while executing the function. This does not include time spent waiting on API calls or HTTP
|
||||
/// requests.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ProcessorTimeSeconds")]
|
||||
public double ProcessorTimeSeconds { get; set; }
|
||||
/// <summary>
|
||||
/// Processor time consumed while executing the function. This does not include time spent waiting on API calls or HTTP
|
||||
/// requests.
|
||||
/// </summary>
|
||||
[JsonPropertyName("ProcessorTimeSeconds")]
|
||||
public double ProcessorTimeSeconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The revision of the CloudScript that executed
|
||||
/// </summary>
|
||||
[JsonPropertyName("Revision")]
|
||||
public int Revision { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The revision of the CloudScript that executed
|
||||
/// </summary>
|
||||
[JsonPropertyName("Revision")]
|
||||
public int Revision { get; set; }
|
||||
}
|
||||
@@ -1,60 +1,58 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FExecuteCloudScriptServerRequest
|
||||
{
|
||||
public class FExecuteCloudScriptServerRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.).
|
||||
/// </summary>
|
||||
[JsonPropertyName("CustomTags")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, string> CustomTags { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.).
|
||||
/// </summary>
|
||||
[JsonPropertyName("CustomTags")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, string> CustomTags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the CloudScript function to execute
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionName")]
|
||||
public string FunctionName { get; set; }
|
||||
/// <summary>
|
||||
/// The name of the CloudScript function to execute
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionName")]
|
||||
public string FunctionName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Object that is passed in to the function as the first argument
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionParameter")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string FunctionParameter { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Object that is passed in to the function as the first argument
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionParameter")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string FunctionParameter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Generate a 'player_executed_cloudscript' PlayStream event containing the results of the function execution and other
|
||||
/// contextual information. This event will show up in the PlayStream debugger console for the player in Game Manager.
|
||||
/// </summary>
|
||||
[JsonPropertyName("GeneratePlayStreamEvent")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? GeneratePlayStreamEvent { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Generate a 'player_executed_cloudscript' PlayStream event containing the results of the function execution and other
|
||||
/// contextual information. This event will show up in the PlayStream debugger console for the player in Game Manager.
|
||||
/// </summary>
|
||||
[JsonPropertyName("GeneratePlayStreamEvent")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? GeneratePlayStreamEvent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique user identifier for the player on whose behalf the script is being run
|
||||
/// </summary>
|
||||
[JsonPropertyName("PlayFabId")]
|
||||
public string PlayFabId { get; set; }
|
||||
/// <summary>
|
||||
/// The unique user identifier for the player on whose behalf the script is being run
|
||||
/// </summary>
|
||||
[JsonPropertyName("PlayFabId")]
|
||||
public string PlayFabId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Option for which revision of the CloudScript to execute. 'Latest' executes the most recently created revision, 'Live'
|
||||
/// executes the current live, published revision, and 'Specific' executes the specified revision. The default value is
|
||||
/// 'Specific', if the SpeificRevision parameter is specified, otherwise it is 'Live'.
|
||||
/// </summary>
|
||||
[JsonPropertyName("RevisionSelection")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public CloudScriptRevisionOption? RevisionSelection { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Option for which revision of the CloudScript to execute. 'Latest' executes the most recently created revision, 'Live'
|
||||
/// executes the current live, published revision, and 'Specific' executes the specified revision. The default value is
|
||||
/// 'Specific', if the SpeificRevision parameter is specified, otherwise it is 'Live'.
|
||||
/// </summary>
|
||||
[JsonPropertyName("RevisionSelection")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public CloudScriptRevisionOption? RevisionSelection { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The specivic revision to execute, when RevisionSelection is set to 'Specific'
|
||||
/// </summary>
|
||||
[JsonPropertyName("SpecificRevision")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int? SpecificRevision { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] The specivic revision to execute, when RevisionSelection is set to 'Specific'
|
||||
/// </summary>
|
||||
[JsonPropertyName("SpecificRevision")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public int? SpecificRevision { get; set; }
|
||||
}
|
||||
@@ -1,44 +1,42 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FExecuteFunctionRequest
|
||||
{
|
||||
public class FExecuteFunctionRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.).
|
||||
/// </summary>
|
||||
[JsonPropertyName("CustomTags")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, string> CustomTags { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.).
|
||||
/// </summary>
|
||||
[JsonPropertyName("CustomTags")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, string> CustomTags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The entity to perform this action on.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Entity")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FEntityKey Entity { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] The entity to perform this action on.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Entity")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FEntityKey Entity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the CloudScript function to execute
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionName")]
|
||||
public string FunctionName { get; set; }
|
||||
/// <summary>
|
||||
/// The name of the CloudScript function to execute
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionName")]
|
||||
public string FunctionName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Object that is passed in to the function as the FunctionArgument field of the FunctionExecutionContext data structure
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionParameter")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string FunctionParameter { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Object that is passed in to the function as the FunctionArgument field of the FunctionExecutionContext data structure
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionParameter")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string FunctionParameter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Generate a 'entity_executed_cloudscript_function' PlayStream event containing the results of the function execution and
|
||||
/// other contextual information. This event will show up in the PlayStream debugger console for the player in Game Manager.
|
||||
/// </summary>
|
||||
[JsonPropertyName("GeneratePlayStreamEvent")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? GeneratePlayStreamEvent { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] Generate a 'entity_executed_cloudscript_function' PlayStream event containing the results of the function execution and
|
||||
/// other contextual information. This event will show up in the PlayStream debugger console for the player in Game Manager.
|
||||
/// </summary>
|
||||
[JsonPropertyName("GeneratePlayStreamEvent")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? GeneratePlayStreamEvent { get; set; }
|
||||
}
|
||||
@@ -1,41 +1,40 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
{
|
||||
public class FExecuteFunctionResult
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] Error from the CloudScript Azure Function.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Error")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FFunctionExecutionError Error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The amount of time the function took to execute
|
||||
/// </summary>
|
||||
[JsonPropertyName("ExecutionTimeMilliseconds")]
|
||||
public int ExecutionTimeMilliseconds { get; set; }
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The name of the function that executed
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionName")]
|
||||
public string FunctionName { get; set; }
|
||||
public class FExecuteFunctionResult
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] Error from the CloudScript Azure Function.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Error")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FFunctionExecutionError Error { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The object returned from the function, if any
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionResult")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public object FunctionResult { get; set; }
|
||||
/// <summary>
|
||||
/// The amount of time the function took to execute
|
||||
/// </summary>
|
||||
[JsonPropertyName("ExecutionTimeMilliseconds")]
|
||||
public int ExecutionTimeMilliseconds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The name of the function that executed
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionName")]
|
||||
public string FunctionName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Flag indicating if the FunctionResult was too large and was subsequently dropped from this event.
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionResultTooLarge")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? FunctionResultTooLarge { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] The object returned from the function, if any
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionResult")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public object FunctionResult { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Flag indicating if the FunctionResult was too large and was subsequently dropped from this event.
|
||||
/// </summary>
|
||||
[JsonPropertyName("FunctionResultTooLarge")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public bool? FunctionResultTooLarge { get; set; }
|
||||
}
|
||||
@@ -1,21 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FGetTitleDataRequest
|
||||
{
|
||||
public class FGetTitleDataRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] Specific keys to search for in the title data (leave null to get all keys)
|
||||
/// </summary>
|
||||
[JsonPropertyName("Keys")]
|
||||
public List<string> Keys { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Specific keys to search for in the title data (leave null to get all keys)
|
||||
/// </summary>
|
||||
[JsonPropertyName("Keys")]
|
||||
public List<string> Keys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Name of the override. This value is ignored when used by the game client; otherwise, the overrides are applied
|
||||
/// automatically to the title data.
|
||||
/// </summary>
|
||||
[JsonPropertyName("OverrideLabel")]
|
||||
public string OverrideLabel { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] Name of the override. This value is ignored when used by the game client; otherwise, the overrides are applied
|
||||
/// automatically to the title data.
|
||||
/// </summary>
|
||||
[JsonPropertyName("OverrideLabel")]
|
||||
public string OverrideLabel { get; set; }
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FGetTitleDataResult
|
||||
{
|
||||
public class FGetTitleDataResult
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] a dictionary object of key / value pairs
|
||||
/// </summary>
|
||||
[JsonPropertyName("Data")]
|
||||
public Dictionary<string, string> Data { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] a dictionary object of key / value pairs
|
||||
/// </summary>
|
||||
[JsonPropertyName("Data")]
|
||||
public Dictionary<string, string> Data { get; set; }
|
||||
}
|
||||
@@ -1,28 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FGetUserDataRequest
|
||||
{
|
||||
public class FGetUserDataRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] The version that currently exists according to the caller. The call will return the data for all of the keys if the
|
||||
/// version in the system is greater than this.
|
||||
/// </summary>
|
||||
[JsonPropertyName("IfChangedFromDataVersion")]
|
||||
public List<uint> IfChangedFromDataVersion { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] The version that currently exists according to the caller. The call will return the data for all of the keys if the
|
||||
/// version in the system is greater than this.
|
||||
/// </summary>
|
||||
[JsonPropertyName("IfChangedFromDataVersion")]
|
||||
public List<uint> IfChangedFromDataVersion { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] List of unique keys to load from.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Keys")]
|
||||
public List<string> Keys { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] List of unique keys to load from.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Keys")]
|
||||
public List<string> Keys { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Unique PlayFab identifier of the user to load data for. Optional, defaults to yourself if not set. When specified to a
|
||||
/// PlayFab id of another player, then this will only return public keys for that account.
|
||||
/// </summary>
|
||||
[JsonPropertyName("PlayFabId")]
|
||||
public string PlayFabId { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] Unique PlayFab identifier of the user to load data for. Optional, defaults to yourself if not set. When specified to a
|
||||
/// PlayFab id of another player, then this will only return public keys for that account.
|
||||
/// </summary>
|
||||
[JsonPropertyName("PlayFabId")]
|
||||
public string PlayFabId { get; set; }
|
||||
}
|
||||
@@ -1,22 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FGetUserDataResult
|
||||
{
|
||||
public class FGetUserDataResult
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] User specific data for this title.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Data")]
|
||||
public Dictionary<string, FUserDataRecord> Data { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] User specific data for this title.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Data")]
|
||||
public Dictionary<string, FUserDataRecord> Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Indicates the current version of the data that has been set. This is incremented with every set call for that type of
|
||||
/// data (read-only, internal, etc). This version can be provided in Get calls to find updated data.
|
||||
/// </summary>
|
||||
[JsonPropertyName("DataVersion")]
|
||||
public uint DataVersion { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] Indicates the current version of the data that has been set. This is incremented with every set call for that type of
|
||||
/// data (read-only, internal, etc). This version can be provided in Get calls to find updated data.
|
||||
/// </summary>
|
||||
[JsonPropertyName("DataVersion")]
|
||||
public uint DataVersion { get; set; }
|
||||
}
|
||||
@@ -1,15 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FGetUserInventoryRequest
|
||||
{
|
||||
public class FGetUserInventoryRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.).
|
||||
/// </summary>
|
||||
[JsonPropertyName("CustomTags")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, string> CustomTags { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.).
|
||||
/// </summary>
|
||||
[JsonPropertyName("CustomTags")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, string> CustomTags { get; set; }
|
||||
}
|
||||
@@ -1,30 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FGetUserInventoryResult
|
||||
{
|
||||
public class FGetUserInventoryResult
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] Array of inventory items belonging to the user.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Inventory")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<FItemInstance> Inventory { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Array of inventory items belonging to the user.
|
||||
/// </summary>
|
||||
[JsonPropertyName("Inventory")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public List<FItemInstance> Inventory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Array of virtual currency balance(s) belonging to the user.
|
||||
/// </summary>
|
||||
[JsonPropertyName("VirtualCurrency")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, int> VirtualCurrency { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Array of virtual currency balance(s) belonging to the user.
|
||||
/// </summary>
|
||||
[JsonPropertyName("VirtualCurrency")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, int> VirtualCurrency { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Array of virtual currency balance(s) belonging to the user.
|
||||
/// </summary>
|
||||
[JsonPropertyName("VirtualCurrencyRechargeTimes")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, FVirtualCurrencyRechargeTime> VirtualCurrencyRechargeTimes { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] Array of virtual currency balance(s) belonging to the user.
|
||||
/// </summary>
|
||||
[JsonPropertyName("VirtualCurrencyRechargeTimes")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, FVirtualCurrencyRechargeTime> VirtualCurrencyRechargeTimes { get; set; }
|
||||
}
|
||||
@@ -1,64 +1,62 @@
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
{
|
||||
public class FServerLoginResult
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] If LoginTitlePlayerAccountEntity flag is set on the login request the title_player_account will also be logged in and
|
||||
/// returned.
|
||||
/// </summary>
|
||||
[JsonPropertyName("EntityToken")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FEntityTokenResponse EntityToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Results for requested info.
|
||||
/// </summary>
|
||||
[JsonPropertyName("InfoResultPayload")]
|
||||
public FGetPlayerCombinedInfoResultPayload InfoResultPayload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The time of this user's previous login. If there was no previous login, then it's DateTime.MinValue
|
||||
/// </summary>
|
||||
[JsonPropertyName("LastLoginTime")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public DateTime? LastLoginTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the account was newly created on this login.
|
||||
/// </summary>
|
||||
[JsonPropertyName("NewlyCreated")]
|
||||
public bool NewlyCreated { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Player's unique PlayFabId.
|
||||
/// </summary>
|
||||
[JsonPropertyName("PlayFabId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string PlayFabId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Unique token authorizing the user and game at the server level, for the current session.
|
||||
/// </summary>
|
||||
[JsonPropertyName("SessionTicket")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string SessionTicket { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Settings specific to this user.
|
||||
/// </summary>
|
||||
[JsonPropertyName("SettingsForUser")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FUserSettings SettingsForUser { get; set; }
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The experimentation treatments for this user at the time of login.
|
||||
/// </summary>
|
||||
[JsonPropertyName("TreatmentAssignment")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FTreatmentAssignment TreatmentAssignment { get; set; }
|
||||
}
|
||||
public class FServerLoginResult
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] If LoginTitlePlayerAccountEntity flag is set on the login request the title_player_account will also be logged in and
|
||||
/// returned.
|
||||
/// </summary>
|
||||
[JsonPropertyName("EntityToken")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FEntityTokenResponse EntityToken { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Results for requested info.
|
||||
/// </summary>
|
||||
[JsonPropertyName("InfoResultPayload")]
|
||||
public FGetPlayerCombinedInfoResultPayload InfoResultPayload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The time of this user's previous login. If there was no previous login, then it's DateTime.MinValue
|
||||
/// </summary>
|
||||
[JsonPropertyName("LastLoginTime")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public DateTime? LastLoginTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the account was newly created on this login.
|
||||
/// </summary>
|
||||
[JsonPropertyName("NewlyCreated")]
|
||||
public bool NewlyCreated { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Player's unique PlayFabId.
|
||||
/// </summary>
|
||||
[JsonPropertyName("PlayFabId")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string PlayFabId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Unique token authorizing the user and game at the server level, for the current session.
|
||||
/// </summary>
|
||||
[JsonPropertyName("SessionTicket")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public string SessionTicket { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Settings specific to this user.
|
||||
/// </summary>
|
||||
[JsonPropertyName("SettingsForUser")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FUserSettings SettingsForUser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] The experimentation treatments for this user at the time of login.
|
||||
/// </summary>
|
||||
[JsonPropertyName("TreatmentAssignment")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public FTreatmentAssignment TreatmentAssignment { get; set; }
|
||||
}
|
||||
@@ -1,38 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using Prospect.Server.Api.Models.Client.Data;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FUpdateUserDataRequest
|
||||
{
|
||||
public class FUpdateUserDataRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.).
|
||||
/// </summary>
|
||||
[JsonPropertyName("CustomTags")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, string> CustomTags { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.).
|
||||
/// </summary>
|
||||
[JsonPropertyName("CustomTags")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, string> CustomTags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Key-value pairs to be written to the custom data. Note that keys are trimmed of whitespace, are limited in size, and may
|
||||
/// not begin with a '!' character or be null.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Data { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Key-value pairs to be written to the custom data. Note that keys are trimmed of whitespace, are limited in size, and may
|
||||
/// not begin with a '!' character or be null.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Data { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Optional list of Data-keys to remove from UserData. Some SDKs cannot insert null-values into Data due to language
|
||||
/// constraints. Use this to delete the keys directly.
|
||||
/// </summary>
|
||||
public List<string> KeysToRemove { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Optional list of Data-keys to remove from UserData. Some SDKs cannot insert null-values into Data due to language
|
||||
/// constraints. Use this to delete the keys directly.
|
||||
/// </summary>
|
||||
public List<string> KeysToRemove { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// [optional] Permission to be applied to all user data keys written in this request. Defaults to "private" if not set.
|
||||
/// </summary>
|
||||
public UserDataPermission? Permission { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] Permission to be applied to all user data keys written in this request. Defaults to "private" if not set.
|
||||
/// </summary>
|
||||
public UserDataPermission? Permission { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Unique PlayFab assigned ID of the user on whom the operation will be performed.
|
||||
/// </summary>
|
||||
public string PlayFabId { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Unique PlayFab assigned ID of the user on whom the operation will be performed.
|
||||
/// </summary>
|
||||
public string PlayFabId { get; set; }
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FUpdateUserDataResult
|
||||
{
|
||||
public class FUpdateUserDataResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the current version of the data that has been set. This is incremented with every set call for that type of
|
||||
/// data (read-only, internal, etc). This version can be provided in Get calls to find updated data.
|
||||
/// </summary>
|
||||
public uint DataVersion { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Indicates the current version of the data that has been set. This is incremented with every set call for that type of
|
||||
/// data (read-only, internal, etc). This version can be provided in Get calls to find updated data.
|
||||
/// </summary>
|
||||
public uint DataVersion { get; set; }
|
||||
}
|
||||
@@ -1,21 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FUpdateUserTitleDisplayNameRequest
|
||||
{
|
||||
public class FUpdateUserTitleDisplayNameRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.).
|
||||
/// </summary>
|
||||
[JsonPropertyName("CustomTags")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, string> CustomTags { get; set; }
|
||||
/// <summary>
|
||||
/// [optional] The optional custom tags associated with the request (e.g. build number, external trace identifiers, etc.).
|
||||
/// </summary>
|
||||
[JsonPropertyName("CustomTags")]
|
||||
[JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingDefault)]
|
||||
public Dictionary<string, string> CustomTags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// New title display name for the user - must be between 3 and 25 characters.
|
||||
/// </summary>
|
||||
[JsonPropertyName("DisplayName")]
|
||||
public string DisplayName { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// New title display name for the user - must be between 3 and 25 characters.
|
||||
/// </summary>
|
||||
[JsonPropertyName("DisplayName")]
|
||||
public string DisplayName { get; set; }
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
namespace Prospect.Server.Api.Models.Client
|
||||
namespace Prospect.Server.Api.Models.Client;
|
||||
|
||||
public class FUpdateUserTitleDisplayNameResult
|
||||
{
|
||||
public class FUpdateUserTitleDisplayNameResult
|
||||
{
|
||||
/// <summary>
|
||||
/// [optional] Current title display name for the user (this will be the original display name if the rename attempt failed).
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// [optional] Current title display name for the user (this will be the original display name if the rename attempt failed).
|
||||
/// </summary>
|
||||
public string DisplayName { get; set; }
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.CloudScript.Data
|
||||
namespace Prospect.Server.Api.Models.CloudScript.Data;
|
||||
|
||||
public class FYActiveContractPlayerData
|
||||
{
|
||||
public class FYActiveContractPlayerData
|
||||
{
|
||||
[JsonPropertyName("contractId")]
|
||||
public string ContractId { get; set; }
|
||||
[JsonPropertyName("contractId")]
|
||||
public string ContractId { get; set; }
|
||||
|
||||
[JsonPropertyName("progress")]
|
||||
public List<int> Progress { get; set; }
|
||||
}
|
||||
[JsonPropertyName("progress")]
|
||||
public List<int> Progress { get; set; }
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.CloudScript.Data
|
||||
{
|
||||
public class FYFactionContractData
|
||||
{
|
||||
[JsonPropertyName("contractId")]
|
||||
public string ContractId { get; set; }
|
||||
namespace Prospect.Server.Api.Models.CloudScript.Data;
|
||||
|
||||
[JsonPropertyName("contractIsLockedDueToLowFactionReputation")]
|
||||
public bool ContractIsLockedDueToLowFactionReputation { get; set; }
|
||||
}
|
||||
public class FYFactionContractData
|
||||
{
|
||||
[JsonPropertyName("contractId")]
|
||||
public string ContractId { get; set; }
|
||||
|
||||
[JsonPropertyName("contractIsLockedDueToLowFactionReputation")]
|
||||
public bool ContractIsLockedDueToLowFactionReputation { get; set; }
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.CloudScript.Data
|
||||
namespace Prospect.Server.Api.Models.CloudScript.Data;
|
||||
|
||||
public class FYFactionContractsData
|
||||
{
|
||||
public class FYFactionContractsData
|
||||
{
|
||||
[JsonPropertyName("factionId")]
|
||||
public string FactionId { get; set; }
|
||||
[JsonPropertyName("factionId")]
|
||||
public string FactionId { get; set; }
|
||||
|
||||
[JsonPropertyName("contracts")]
|
||||
public List<FYFactionContractData> Contracts { get; set; }
|
||||
}
|
||||
[JsonPropertyName("contracts")]
|
||||
public List<FYFactionContractData> Contracts { get; set; }
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.CloudScript.Data
|
||||
namespace Prospect.Server.Api.Models.CloudScript.Data;
|
||||
|
||||
public class FYFactionsContractsData
|
||||
{
|
||||
public class FYFactionsContractsData
|
||||
{
|
||||
[JsonPropertyName("boards")]
|
||||
public List<FYFactionContractsData> Boards { get; set; }
|
||||
[JsonPropertyName("boards")]
|
||||
public List<FYFactionContractsData> Boards { get; set; }
|
||||
|
||||
[JsonPropertyName("lastBoardRefreshTimeUtc")]
|
||||
public FYTimestamp LastBoardRefreshTimeUtc { get; set; }
|
||||
}
|
||||
[JsonPropertyName("lastBoardRefreshTimeUtc")]
|
||||
public FYTimestamp LastBoardRefreshTimeUtc { get; set; }
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.CloudScript.Data
|
||||
namespace Prospect.Server.Api.Models.CloudScript.Data;
|
||||
|
||||
public class FYItemCurrentlyBeingCrafted
|
||||
{
|
||||
public class FYItemCurrentlyBeingCrafted
|
||||
{
|
||||
[JsonPropertyName("itemId")]
|
||||
public string ItemId { get; set; }
|
||||
[JsonPropertyName("itemId")]
|
||||
public string ItemId { get; set; }
|
||||
|
||||
[JsonPropertyName("itemRarity")]
|
||||
public int ItemRarity { get; set; }
|
||||
[JsonPropertyName("itemRarity")]
|
||||
public int ItemRarity { get; set; }
|
||||
|
||||
[JsonPropertyName("purchaseAmount")]
|
||||
public int PurchaseAmount { get; set; }
|
||||
[JsonPropertyName("purchaseAmount")]
|
||||
public int PurchaseAmount { get; set; }
|
||||
|
||||
[JsonPropertyName("utcTimestampWhenCraftingStarted")]
|
||||
public FYTimestamp UtcTimestampWhenCraftingStarted { get; set; }
|
||||
}
|
||||
[JsonPropertyName("utcTimestampWhenCraftingStarted")]
|
||||
public FYTimestamp UtcTimestampWhenCraftingStarted { get; set; }
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Models.CloudScript.Data
|
||||
namespace Prospect.Server.Api.Models.CloudScript.Data;
|
||||
|
||||
public class FYTimestamp
|
||||
{
|
||||
public class FYTimestamp
|
||||
{
|
||||
[JsonPropertyName("seconds")]
|
||||
public int Seconds { get; set; }
|
||||
}
|
||||
[JsonPropertyName("seconds")]
|
||||
public int Seconds { get; set; }
|
||||
}
|
||||
@@ -1,17 +1,16 @@
|
||||
using System.Text.Json.Serialization;
|
||||
using Prospect.Server.Api.Models.CloudScript.Data;
|
||||
|
||||
namespace Prospect.Server.Api.Models.CloudScript
|
||||
namespace Prospect.Server.Api.Models.CloudScript;
|
||||
|
||||
public class FYGetCraftingInProgressDataResult
|
||||
{
|
||||
public class FYGetCraftingInProgressDataResult
|
||||
{
|
||||
[JsonPropertyName("userId")]
|
||||
public string UserId { get; set; }
|
||||
[JsonPropertyName("userId")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
[JsonPropertyName("error")]
|
||||
public string Error { get; set; }
|
||||
[JsonPropertyName("error")]
|
||||
public string Error { get; set; }
|
||||
|
||||
[JsonPropertyName("itemCurrentlyBeingCrafted")]
|
||||
public FYItemCurrentlyBeingCrafted ItemCurrentlyBeingCrafted { get; set; }
|
||||
}
|
||||
[JsonPropertyName("itemCurrentlyBeingCrafted")]
|
||||
public FYItemCurrentlyBeingCrafted ItemCurrentlyBeingCrafted { get; set; }
|
||||
}
|
||||
@@ -1,24 +1,22 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization;
|
||||
using Prospect.Server.Api.Models.CloudScript.Data;
|
||||
|
||||
namespace Prospect.Server.Api.Models.CloudScript
|
||||
namespace Prospect.Server.Api.Models.CloudScript;
|
||||
|
||||
public class FYGetPlayerContractsResult
|
||||
{
|
||||
public class FYGetPlayerContractsResult
|
||||
{
|
||||
[JsonPropertyName("userId")]
|
||||
public string UserId { get; set; }
|
||||
[JsonPropertyName("userId")]
|
||||
public string UserId { get; set; }
|
||||
|
||||
[JsonPropertyName("error")]
|
||||
public string Error { get; set; }
|
||||
[JsonPropertyName("error")]
|
||||
public string Error { get; set; }
|
||||
|
||||
[JsonPropertyName("activeContracts")]
|
||||
public List<FYActiveContractPlayerData> ActiveContracts { get; set; }
|
||||
[JsonPropertyName("activeContracts")]
|
||||
public List<FYActiveContractPlayerData> ActiveContracts { get; set; }
|
||||
|
||||
[JsonPropertyName("factionsContracts")]
|
||||
public FYFactionsContractsData FactionsContracts { get; set; }
|
||||
[JsonPropertyName("factionsContracts")]
|
||||
public FYFactionsContractsData FactionsContracts { get; set; }
|
||||
|
||||
[JsonPropertyName("refreshHours24UtcFromBackend")]
|
||||
public int RefreshHours24UtcFromBackend { get; set; }
|
||||
}
|
||||
[JsonPropertyName("refreshHours24UtcFromBackend")]
|
||||
public int RefreshHours24UtcFromBackend { get; set; }
|
||||
}
|
||||
@@ -1,46 +1,42 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
|
||||
namespace Prospect.Server.Api
|
||||
namespace Prospect.Server.Api;
|
||||
|
||||
public static class Program
|
||||
{
|
||||
public static class Program
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
public static int Main(string[] args)
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Debug()
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console()
|
||||
.CreateLogger();
|
||||
|
||||
try
|
||||
{
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.MinimumLevel.Debug()
|
||||
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
||||
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console()
|
||||
.CreateLogger();
|
||||
|
||||
try
|
||||
{
|
||||
Log.Information("Starting web host");
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, "Host terminated unexpectedly");
|
||||
return 1;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
Log.Information("Starting web host");
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
return 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Fatal(ex, "Host terminated unexpectedly");
|
||||
return 1;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Log.CloseAndFlush();
|
||||
}
|
||||
|
||||
private static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.UseSerilog()
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
|
||||
private static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.UseSerilog()
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
});
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>true</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
namespace Prospect.Server.Api.Services.Auth
|
||||
namespace Prospect.Server.Api.Services.Auth;
|
||||
|
||||
public static class AuthClaimTypes
|
||||
{
|
||||
public static class AuthClaimTypes
|
||||
{
|
||||
public const string UserId = "user_id";
|
||||
public const string EntityId = "entity_id";
|
||||
public const string Type = "type";
|
||||
}
|
||||
public const string UserId = "user_id";
|
||||
public const string EntityId = "entity_id";
|
||||
public const string Type = "type";
|
||||
}
|
||||
@@ -1,83 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Prospect.Server.Api.Services.Database.Models;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Auth
|
||||
namespace Prospect.Server.Api.Services.Auth;
|
||||
|
||||
public class AuthTokenService
|
||||
{
|
||||
public class AuthTokenService
|
||||
private const string DefaultIssuer = "ProspectApi";
|
||||
private const string DefaultAudience = "Prospect";
|
||||
|
||||
private readonly SymmetricSecurityKey _securityKey;
|
||||
private readonly JwtSecurityTokenHandler _tokenHandler;
|
||||
|
||||
public AuthTokenService(IOptions<AuthTokenSettings> options)
|
||||
{
|
||||
private const string DefaultIssuer = "ProspectApi";
|
||||
private const string DefaultAudience = "Prospect";
|
||||
|
||||
private readonly SymmetricSecurityKey _securityKey;
|
||||
private readonly JwtSecurityTokenHandler _tokenHandler;
|
||||
|
||||
public AuthTokenService(IOptions<AuthTokenSettings> options)
|
||||
{
|
||||
_securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(options.Value.Secret));
|
||||
_tokenHandler = new JwtSecurityTokenHandler();
|
||||
}
|
||||
_securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(options.Value.Secret));
|
||||
_tokenHandler = new JwtSecurityTokenHandler();
|
||||
}
|
||||
|
||||
private string CreateToken(IEnumerable<Claim> claims)
|
||||
private string CreateToken(IEnumerable<Claim> claims)
|
||||
{
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Subject = new ClaimsIdentity(claims),
|
||||
Expires = DateTime.UtcNow.AddDays(7),
|
||||
Issuer = DefaultIssuer,
|
||||
Audience = DefaultAudience,
|
||||
SigningCredentials = new SigningCredentials(_securityKey, SecurityAlgorithms.HmacSha256Signature)
|
||||
};
|
||||
Subject = new ClaimsIdentity(claims),
|
||||
Expires = DateTime.UtcNow.AddDays(7),
|
||||
Issuer = DefaultIssuer,
|
||||
Audience = DefaultAudience,
|
||||
SigningCredentials = new SigningCredentials(_securityKey, SecurityAlgorithms.HmacSha256Signature)
|
||||
};
|
||||
|
||||
var token = _tokenHandler.CreateToken(tokenDescriptor);
|
||||
return _tokenHandler.WriteToken(token);
|
||||
}
|
||||
var token = _tokenHandler.CreateToken(tokenDescriptor);
|
||||
return _tokenHandler.WriteToken(token);
|
||||
}
|
||||
|
||||
public string GenerateUser(PlayFabEntity entity)
|
||||
public string GenerateUser(PlayFabEntity entity)
|
||||
{
|
||||
return CreateToken(new[]
|
||||
{
|
||||
return CreateToken(new[]
|
||||
{
|
||||
new Claim(AuthClaimTypes.UserId, entity.UserId),
|
||||
new Claim(AuthClaimTypes.EntityId, entity.Id),
|
||||
new Claim(AuthClaimTypes.Type, AuthType.User),
|
||||
});
|
||||
}
|
||||
new Claim(AuthClaimTypes.UserId, entity.UserId),
|
||||
new Claim(AuthClaimTypes.EntityId, entity.Id),
|
||||
new Claim(AuthClaimTypes.Type, AuthType.User),
|
||||
});
|
||||
}
|
||||
|
||||
public string GenerateEntity(PlayFabEntity entity)
|
||||
public string GenerateEntity(PlayFabEntity entity)
|
||||
{
|
||||
return CreateToken(new[]
|
||||
{
|
||||
return CreateToken(new[]
|
||||
{
|
||||
new Claim(AuthClaimTypes.UserId, entity.UserId),
|
||||
new Claim(AuthClaimTypes.EntityId, entity.Id),
|
||||
new Claim(AuthClaimTypes.Type, AuthType.Entity),
|
||||
});
|
||||
}
|
||||
new Claim(AuthClaimTypes.UserId, entity.UserId),
|
||||
new Claim(AuthClaimTypes.EntityId, entity.Id),
|
||||
new Claim(AuthClaimTypes.Type, AuthType.Entity),
|
||||
});
|
||||
}
|
||||
|
||||
public ClaimsPrincipal Validate(string token)
|
||||
{
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
public ClaimsPrincipal Validate(string token)
|
||||
{
|
||||
var tokenHandler = new JwtSecurityTokenHandler();
|
||||
|
||||
try
|
||||
try
|
||||
{
|
||||
return tokenHandler.ValidateToken(token, new TokenValidationParameters
|
||||
{
|
||||
return tokenHandler.ValidateToken(token, new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidIssuer = DefaultIssuer,
|
||||
ValidAudience = DefaultAudience,
|
||||
IssuerSigningKey = _securityKey
|
||||
}, out _);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidIssuer = DefaultIssuer,
|
||||
ValidAudience = DefaultAudience,
|
||||
IssuerSigningKey = _securityKey
|
||||
}, out _);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
namespace Prospect.Server.Api.Services.Auth
|
||||
namespace Prospect.Server.Api.Services.Auth;
|
||||
|
||||
public class AuthTokenSettings
|
||||
{
|
||||
public class AuthTokenSettings
|
||||
{
|
||||
public string Secret { get; set; }
|
||||
}
|
||||
public string Secret { get; set; }
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace Prospect.Server.Api.Services.Auth
|
||||
namespace Prospect.Server.Api.Services.Auth;
|
||||
|
||||
public static class AuthType
|
||||
{
|
||||
public static class AuthType
|
||||
{
|
||||
public const string User = "User";
|
||||
public const string Entity = "Entity";
|
||||
}
|
||||
public const string User = "User";
|
||||
public const string Entity = "Entity";
|
||||
}
|
||||
@@ -1,20 +1,18 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Prospect.Server.Api.Services.Auth.Entity;
|
||||
using Prospect.Server.Api.Services.Auth.User;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Auth
|
||||
namespace Prospect.Server.Api.Services.Auth;
|
||||
|
||||
public static class AuthenticationBuilderExtensions
|
||||
{
|
||||
public static class AuthenticationBuilderExtensions
|
||||
public static AuthenticationBuilder AddUserAuthentication(this AuthenticationBuilder authenticationBuilder, Action<UserAuthenticationOptions> options)
|
||||
{
|
||||
public static AuthenticationBuilder AddUserAuthentication(this AuthenticationBuilder authenticationBuilder, Action<UserAuthenticationOptions> options)
|
||||
{
|
||||
return authenticationBuilder.AddScheme<UserAuthenticationOptions, UserAuthenticationHandler>(UserAuthenticationOptions.DefaultScheme, options);
|
||||
}
|
||||
return authenticationBuilder.AddScheme<UserAuthenticationOptions, UserAuthenticationHandler>(UserAuthenticationOptions.DefaultScheme, options);
|
||||
}
|
||||
|
||||
public static AuthenticationBuilder AddEntityAuthentication(this AuthenticationBuilder authenticationBuilder, Action<EntityAuthenticationOptions> options)
|
||||
{
|
||||
return authenticationBuilder.AddScheme<EntityAuthenticationOptions, EntityAuthenticationHandler>(EntityAuthenticationOptions.DefaultScheme, options);
|
||||
}
|
||||
public static AuthenticationBuilder AddEntityAuthentication(this AuthenticationBuilder authenticationBuilder, Action<EntityAuthenticationOptions> options)
|
||||
{
|
||||
return authenticationBuilder.AddScheme<EntityAuthenticationOptions, EntityAuthenticationHandler>(EntityAuthenticationOptions.DefaultScheme, options);
|
||||
}
|
||||
}
|
||||
@@ -1,87 +1,81 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Prospect.Server.Api.Models.Client;
|
||||
using Prospect.Server.Api.Services.Auth.Extensions;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Auth.Entity
|
||||
namespace Prospect.Server.Api.Services.Auth.Entity;
|
||||
|
||||
public class EntityAuthenticationHandler : AuthenticationHandler<EntityAuthenticationOptions>
|
||||
{
|
||||
public class EntityAuthenticationHandler : AuthenticationHandler<EntityAuthenticationOptions>
|
||||
private const string Header = "X-EntityToken";
|
||||
private const string Type = AuthType.Entity;
|
||||
|
||||
private readonly AuthTokenService _authTokenService;
|
||||
|
||||
public EntityAuthenticationHandler(
|
||||
IOptionsMonitor<EntityAuthenticationOptions> options,
|
||||
ILoggerFactory logger,
|
||||
UrlEncoder encoder,
|
||||
ISystemClock clock,
|
||||
AuthTokenService authTokenService) : base(options, logger, encoder, clock)
|
||||
{
|
||||
private const string Header = "X-EntityToken";
|
||||
private const string Type = AuthType.Entity;
|
||||
_authTokenService = authTokenService;
|
||||
}
|
||||
|
||||
private readonly AuthTokenService _authTokenService;
|
||||
|
||||
public EntityAuthenticationHandler(
|
||||
IOptionsMonitor<EntityAuthenticationOptions> options,
|
||||
ILoggerFactory logger,
|
||||
UrlEncoder encoder,
|
||||
ISystemClock clock,
|
||||
AuthTokenService authTokenService) : base(options, logger, encoder, clock)
|
||||
{
|
||||
_authTokenService = authTokenService;
|
||||
}
|
||||
|
||||
private ClientResponse Res { get; set; } = new ClientResponse
|
||||
{
|
||||
Code = 401,
|
||||
Status = "Unauthorized",
|
||||
Error = "NotAuthenticated",
|
||||
ErrorCode = 1074,
|
||||
ErrorMessage = "This API method does not allow anonymous callers."
|
||||
};
|
||||
private ClientResponse Res { get; set; } = new ClientResponse
|
||||
{
|
||||
Code = 401,
|
||||
Status = "Unauthorized",
|
||||
Error = "NotAuthenticated",
|
||||
ErrorCode = 1074,
|
||||
ErrorMessage = "This API method does not allow anonymous callers."
|
||||
};
|
||||
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
if (!Request.Headers.TryGetValue(Header, out var headerValues) || headerValues.Count == 0)
|
||||
{
|
||||
if (!Request.Headers.TryGetValue(Header, out var headerValues) || headerValues.Count == 0)
|
||||
{
|
||||
return Task.FromResult(AuthenticateResult.Fail("No header"));
|
||||
}
|
||||
return Task.FromResult(AuthenticateResult.Fail("No header"));
|
||||
}
|
||||
|
||||
var headerValue = headerValues.FirstOrDefault();
|
||||
var headerValue = headerValues.FirstOrDefault();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(headerValue))
|
||||
{
|
||||
return Task.FromResult(AuthenticateResult.Fail("Empty header value"));
|
||||
}
|
||||
|
||||
Res.Error = "EntityTokenInvalid";
|
||||
Res.ErrorCode = 1335;
|
||||
Res.ErrorMessage = "EntityTokenInvalid";
|
||||
|
||||
var token = _authTokenService.Validate(headerValue);
|
||||
if (token != null)
|
||||
{
|
||||
var identity = new ClaimsIdentity(token.Claims, Options.AuthenticationType);
|
||||
var identities = new List<ClaimsIdentity> { identity };
|
||||
var principal = new ClaimsPrincipal(identities);
|
||||
if (principal.FindAuthType() != Type)
|
||||
{
|
||||
return Task.FromResult(AuthenticateResult.Fail("Invalid auth type"));
|
||||
}
|
||||
|
||||
var ticket = new AuthenticationTicket(principal, Options.Scheme);
|
||||
|
||||
return Task.FromResult(AuthenticateResult.Success(ticket));
|
||||
}
|
||||
|
||||
return Task.FromResult(AuthenticateResult.Fail("Invalid JWT"));
|
||||
}
|
||||
|
||||
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||
if (string.IsNullOrWhiteSpace(headerValue))
|
||||
{
|
||||
Response.StatusCode = 401;
|
||||
Response.ContentType = "application/json";
|
||||
|
||||
await Response.WriteAsync(JsonSerializer.Serialize(Res));
|
||||
return Task.FromResult(AuthenticateResult.Fail("Empty header value"));
|
||||
}
|
||||
|
||||
Res.Error = "EntityTokenInvalid";
|
||||
Res.ErrorCode = 1335;
|
||||
Res.ErrorMessage = "EntityTokenInvalid";
|
||||
|
||||
var token = _authTokenService.Validate(headerValue);
|
||||
if (token != null)
|
||||
{
|
||||
var identity = new ClaimsIdentity(token.Claims, Options.AuthenticationType);
|
||||
var identities = new List<ClaimsIdentity> { identity };
|
||||
var principal = new ClaimsPrincipal(identities);
|
||||
if (principal.FindAuthType() != Type)
|
||||
{
|
||||
return Task.FromResult(AuthenticateResult.Fail("Invalid auth type"));
|
||||
}
|
||||
|
||||
var ticket = new AuthenticationTicket(principal, Options.Scheme);
|
||||
|
||||
return Task.FromResult(AuthenticateResult.Success(ticket));
|
||||
}
|
||||
|
||||
return Task.FromResult(AuthenticateResult.Fail("Invalid JWT"));
|
||||
}
|
||||
|
||||
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||
{
|
||||
Response.StatusCode = 401;
|
||||
Response.ContentType = "application/json";
|
||||
|
||||
await Response.WriteAsync(JsonSerializer.Serialize(Res));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Auth.Entity
|
||||
namespace Prospect.Server.Api.Services.Auth.Entity;
|
||||
|
||||
public class EntityAuthenticationOptions : AuthenticationSchemeOptions
|
||||
{
|
||||
public class EntityAuthenticationOptions : AuthenticationSchemeOptions
|
||||
{
|
||||
public const string DefaultScheme = "EntityAuth";
|
||||
public string Scheme => DefaultScheme;
|
||||
public string AuthenticationType = DefaultScheme;
|
||||
}
|
||||
public const string DefaultScheme = "EntityAuth";
|
||||
public string Scheme => DefaultScheme;
|
||||
public string AuthenticationType = DefaultScheme;
|
||||
}
|
||||
@@ -1,34 +1,33 @@
|
||||
using System.Security.Claims;
|
||||
using Prospect.Server.Api.Exceptions;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Auth.Extensions
|
||||
namespace Prospect.Server.Api.Services.Auth.Extensions;
|
||||
|
||||
public static class ClaimsPrincipalExtensions
|
||||
{
|
||||
public static class ClaimsPrincipalExtensions
|
||||
public static string FindAuthUserId(this ClaimsPrincipal principal)
|
||||
{
|
||||
public static string FindAuthUserId(this ClaimsPrincipal principal)
|
||||
{
|
||||
return Find(principal, AuthClaimTypes.UserId);
|
||||
}
|
||||
return Find(principal, AuthClaimTypes.UserId);
|
||||
}
|
||||
|
||||
public static string FindAuthEntityId(this ClaimsPrincipal principal)
|
||||
{
|
||||
return Find(principal, AuthClaimTypes.EntityId);
|
||||
}
|
||||
public static string FindAuthEntityId(this ClaimsPrincipal principal)
|
||||
{
|
||||
return Find(principal, AuthClaimTypes.EntityId);
|
||||
}
|
||||
|
||||
public static string FindAuthType(this ClaimsPrincipal principal)
|
||||
public static string FindAuthType(this ClaimsPrincipal principal)
|
||||
{
|
||||
return Find(principal, AuthClaimTypes.Type);
|
||||
}
|
||||
|
||||
private static string Find(ClaimsPrincipal principal, string claimType)
|
||||
{
|
||||
var claim = principal.FindFirst(claimType);
|
||||
if (claim == null)
|
||||
{
|
||||
return Find(principal, AuthClaimTypes.Type);
|
||||
throw new ProspectException($"Failed to find claim {claimType}");
|
||||
}
|
||||
|
||||
private static string Find(ClaimsPrincipal principal, string claimType)
|
||||
{
|
||||
var claim = principal.FindFirst(claimType);
|
||||
if (claim == null)
|
||||
{
|
||||
throw new ProspectException($"Failed to find claim {claimType}");
|
||||
}
|
||||
|
||||
return claim.Value;
|
||||
}
|
||||
return claim.Value;
|
||||
}
|
||||
}
|
||||
@@ -1,85 +1,79 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Prospect.Server.Api.Models.Client;
|
||||
using Prospect.Server.Api.Services.Auth.Extensions;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Auth.User
|
||||
namespace Prospect.Server.Api.Services.Auth.User;
|
||||
|
||||
public class UserAuthenticationHandler : AuthenticationHandler<UserAuthenticationOptions>
|
||||
{
|
||||
public class UserAuthenticationHandler : AuthenticationHandler<UserAuthenticationOptions>
|
||||
private const string Header = "X-Authorization";
|
||||
private const string Type = AuthType.User;
|
||||
|
||||
private readonly AuthTokenService _authTokenService;
|
||||
|
||||
public UserAuthenticationHandler(
|
||||
IOptionsMonitor<UserAuthenticationOptions> options,
|
||||
ILoggerFactory logger,
|
||||
UrlEncoder encoder,
|
||||
ISystemClock clock,
|
||||
AuthTokenService authTokenService) : base(options, logger, encoder, clock)
|
||||
{
|
||||
private const string Header = "X-Authorization";
|
||||
private const string Type = AuthType.User;
|
||||
_authTokenService = authTokenService;
|
||||
}
|
||||
|
||||
private readonly AuthTokenService _authTokenService;
|
||||
|
||||
public UserAuthenticationHandler(
|
||||
IOptionsMonitor<UserAuthenticationOptions> options,
|
||||
ILoggerFactory logger,
|
||||
UrlEncoder encoder,
|
||||
ISystemClock clock,
|
||||
AuthTokenService authTokenService) : base(options, logger, encoder, clock)
|
||||
{
|
||||
_authTokenService = authTokenService;
|
||||
}
|
||||
|
||||
private string Failure { get; set; } = "Not Authenticated";
|
||||
private string Failure { get; set; } = "Not Authenticated";
|
||||
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
if (!Request.Headers.TryGetValue(Header, out var headerValues) || headerValues.Count == 0)
|
||||
{
|
||||
if (!Request.Headers.TryGetValue(Header, out var headerValues) || headerValues.Count == 0)
|
||||
{
|
||||
return Task.FromResult(AuthenticateResult.Fail("No header"));
|
||||
}
|
||||
return Task.FromResult(AuthenticateResult.Fail("No header"));
|
||||
}
|
||||
|
||||
var headerValue = headerValues.FirstOrDefault();
|
||||
var headerValue = headerValues.FirstOrDefault();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(headerValue))
|
||||
{
|
||||
return Task.FromResult(AuthenticateResult.Fail("Empty header value"));
|
||||
}
|
||||
|
||||
Failure = "X-Authentication HTTP header contains invalid ticket";
|
||||
|
||||
var token = _authTokenService.Validate(headerValue);
|
||||
if (token != null)
|
||||
{
|
||||
var identity = new ClaimsIdentity(token.Claims, Options.AuthenticationType);
|
||||
var identities = new List<ClaimsIdentity> { identity };
|
||||
var principal = new ClaimsPrincipal(identities);
|
||||
if (principal.FindAuthType() != Type)
|
||||
{
|
||||
return Task.FromResult(AuthenticateResult.Fail("Invalid auth type"));
|
||||
}
|
||||
|
||||
var ticket = new AuthenticationTicket(principal, Options.Scheme);
|
||||
|
||||
return Task.FromResult(AuthenticateResult.Success(ticket));
|
||||
}
|
||||
|
||||
return Task.FromResult(AuthenticateResult.Fail("Invalid JWT"));
|
||||
}
|
||||
|
||||
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||
if (string.IsNullOrWhiteSpace(headerValue))
|
||||
{
|
||||
Response.StatusCode = 401;
|
||||
Response.ContentType = "application/json";
|
||||
|
||||
await Response.WriteAsync(JsonSerializer.Serialize(new ClientResponse
|
||||
{
|
||||
Code = 401,
|
||||
Status = "Unauthorized",
|
||||
Error = "NotAuthenticated",
|
||||
ErrorCode = 1074,
|
||||
ErrorMessage = Failure
|
||||
}));
|
||||
return Task.FromResult(AuthenticateResult.Fail("Empty header value"));
|
||||
}
|
||||
|
||||
Failure = "X-Authentication HTTP header contains invalid ticket";
|
||||
|
||||
var token = _authTokenService.Validate(headerValue);
|
||||
if (token != null)
|
||||
{
|
||||
var identity = new ClaimsIdentity(token.Claims, Options.AuthenticationType);
|
||||
var identities = new List<ClaimsIdentity> { identity };
|
||||
var principal = new ClaimsPrincipal(identities);
|
||||
if (principal.FindAuthType() != Type)
|
||||
{
|
||||
return Task.FromResult(AuthenticateResult.Fail("Invalid auth type"));
|
||||
}
|
||||
|
||||
var ticket = new AuthenticationTicket(principal, Options.Scheme);
|
||||
|
||||
return Task.FromResult(AuthenticateResult.Success(ticket));
|
||||
}
|
||||
|
||||
return Task.FromResult(AuthenticateResult.Fail("Invalid JWT"));
|
||||
}
|
||||
|
||||
protected override async Task HandleChallengeAsync(AuthenticationProperties properties)
|
||||
{
|
||||
Response.StatusCode = 401;
|
||||
Response.ContentType = "application/json";
|
||||
|
||||
await Response.WriteAsync(JsonSerializer.Serialize(new ClientResponse
|
||||
{
|
||||
Code = 401,
|
||||
Status = "Unauthorized",
|
||||
Error = "NotAuthenticated",
|
||||
ErrorCode = 1074,
|
||||
ErrorMessage = Failure
|
||||
}));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Auth.User
|
||||
namespace Prospect.Server.Api.Services.Auth.User;
|
||||
|
||||
public class UserAuthenticationOptions : AuthenticationSchemeOptions
|
||||
{
|
||||
public class UserAuthenticationOptions : AuthenticationSchemeOptions
|
||||
{
|
||||
public const string DefaultScheme = "UserAuth";
|
||||
public string Scheme => DefaultScheme;
|
||||
public string AuthenticationType = DefaultScheme;
|
||||
}
|
||||
public const string DefaultScheme = "UserAuth";
|
||||
public string Scheme => DefaultScheme;
|
||||
public string AuthenticationType = DefaultScheme;
|
||||
}
|
||||
@@ -2,19 +2,18 @@
|
||||
using MongoDB.Driver;
|
||||
using Prospect.Server.Api.Config;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Database
|
||||
{
|
||||
public abstract class BaseDbService<T>
|
||||
{
|
||||
protected BaseDbService(IOptions<DatabaseSettings> options, string collection)
|
||||
{
|
||||
var settings = options.Value;
|
||||
var client = new MongoClient(settings.ConnectionString);
|
||||
var database = client.GetDatabase(settings.DatabaseName);
|
||||
namespace Prospect.Server.Api.Services.Database;
|
||||
|
||||
Collection = database.GetCollection<T>(collection);
|
||||
}
|
||||
|
||||
protected IMongoCollection<T> Collection { get; }
|
||||
public abstract class BaseDbService<T>
|
||||
{
|
||||
protected BaseDbService(IOptions<DatabaseSettings> options, string collection)
|
||||
{
|
||||
var settings = options.Value;
|
||||
var client = new MongoClient(settings.ConnectionString);
|
||||
var database = client.GetDatabase(settings.DatabaseName);
|
||||
|
||||
Collection = database.GetCollection<T>(collection);
|
||||
}
|
||||
|
||||
protected IMongoCollection<T> Collection { get; }
|
||||
}
|
||||
@@ -1,38 +1,36 @@
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Driver;
|
||||
using Prospect.Server.Api.Config;
|
||||
using Prospect.Server.Api.Services.Database.Models;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Database
|
||||
namespace Prospect.Server.Api.Services.Database;
|
||||
|
||||
public class DbEntityService : BaseDbService<PlayFabEntity>
|
||||
{
|
||||
public class DbEntityService : BaseDbService<PlayFabEntity>
|
||||
public DbEntityService(IOptions<DatabaseSettings> settings) : base(settings, nameof(PlayFabEntity))
|
||||
{
|
||||
public DbEntityService(IOptions<DatabaseSettings> settings) : base(settings, nameof(PlayFabEntity))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<PlayFabEntity> FindAsync(string userId)
|
||||
{
|
||||
return await Collection.Find(user => user.UserId == userId).SingleOrDefaultAsync();
|
||||
}
|
||||
public async Task<PlayFabEntity> FindAsync(string userId)
|
||||
{
|
||||
return await Collection.Find(user => user.UserId == userId).SingleOrDefaultAsync();
|
||||
}
|
||||
|
||||
private async Task<PlayFabEntity> CreateAsync(string userId)
|
||||
private async Task<PlayFabEntity> CreateAsync(string userId)
|
||||
{
|
||||
var user = new PlayFabEntity
|
||||
{
|
||||
var user = new PlayFabEntity
|
||||
{
|
||||
UserId = userId
|
||||
};
|
||||
UserId = userId
|
||||
};
|
||||
|
||||
await Collection.InsertOneAsync(user);
|
||||
await Collection.InsertOneAsync(user);
|
||||
|
||||
return user;
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
public async Task<PlayFabEntity> FindOrCreateAsync(string userId)
|
||||
{
|
||||
return await FindAsync(userId) ??
|
||||
await CreateAsync(userId);
|
||||
}
|
||||
public async Task<PlayFabEntity> FindOrCreateAsync(string userId)
|
||||
{
|
||||
return await FindAsync(userId) ??
|
||||
await CreateAsync(userId);
|
||||
}
|
||||
}
|
||||
@@ -1,60 +1,57 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Driver;
|
||||
using Prospect.Server.Api.Config;
|
||||
using Prospect.Server.Api.Services.Database.Models;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Database
|
||||
namespace Prospect.Server.Api.Services.Database;
|
||||
|
||||
public class DbUserDataService : BaseDbService<PlayFabUserData>
|
||||
{
|
||||
public class DbUserDataService : BaseDbService<PlayFabUserData>
|
||||
public DbUserDataService(IOptions<DatabaseSettings> options) : base(options, nameof(PlayFabUserData))
|
||||
{
|
||||
public DbUserDataService(IOptions<DatabaseSettings> options) : base(options, nameof(PlayFabUserData))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> HasAsync(string playFabId, string key)
|
||||
{
|
||||
return await Collection.Find(data => data.PlayFabId == playFabId && data.Key == key).AnyAsync();
|
||||
}
|
||||
public async Task<bool> HasAsync(string playFabId, string key)
|
||||
{
|
||||
return await Collection.Find(data => data.PlayFabId == playFabId && data.Key == key).AnyAsync();
|
||||
}
|
||||
|
||||
public async Task<PlayFabUserData> FindAsync(string playFabId, string key)
|
||||
{
|
||||
return await Collection.Find(data => data.PlayFabId == playFabId && data.Key == key).SingleOrDefaultAsync();
|
||||
}
|
||||
public async Task<PlayFabUserData> FindAsync(string playFabId, string key)
|
||||
{
|
||||
return await Collection.Find(data => data.PlayFabId == playFabId && data.Key == key).SingleOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task<PlayFabUserData> InsertAsync(string playFabId, string key, string value, bool isPublic)
|
||||
public async Task<PlayFabUserData> InsertAsync(string playFabId, string key, string value, bool isPublic)
|
||||
{
|
||||
var data = new PlayFabUserData
|
||||
{
|
||||
var data = new PlayFabUserData
|
||||
{
|
||||
PlayFabId = playFabId,
|
||||
Key = key,
|
||||
Value = value,
|
||||
Public = isPublic,
|
||||
LastUpdated = DateTime.UtcNow
|
||||
};
|
||||
PlayFabId = playFabId,
|
||||
Key = key,
|
||||
Value = value,
|
||||
Public = isPublic,
|
||||
LastUpdated = DateTime.UtcNow
|
||||
};
|
||||
|
||||
await Collection.InsertOneAsync(data);
|
||||
await Collection.InsertOneAsync(data);
|
||||
|
||||
return data;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
public async Task<IAsyncCursor<PlayFabUserData>> AllAsync(string playFabId, bool publicOnly)
|
||||
{
|
||||
var query = publicOnly
|
||||
? Collection.Find(data => data.PlayFabId == playFabId && data.Public)
|
||||
: Collection.Find(data => data.PlayFabId == playFabId);
|
||||
public async Task<IAsyncCursor<PlayFabUserData>> AllAsync(string playFabId, bool publicOnly)
|
||||
{
|
||||
var query = publicOnly
|
||||
? Collection.Find(data => data.PlayFabId == playFabId && data.Public)
|
||||
: Collection.Find(data => data.PlayFabId == playFabId);
|
||||
|
||||
return await query.ToCursorAsync();
|
||||
}
|
||||
return await query.ToCursorAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateValueAsync(string dataId, string value)
|
||||
{
|
||||
var update = Builders<PlayFabUserData>.Update
|
||||
.Set(data => data.Value, value)
|
||||
.Set(data => data.LastUpdated, DateTime.UtcNow);
|
||||
public async Task UpdateValueAsync(string dataId, string value)
|
||||
{
|
||||
var update = Builders<PlayFabUserData>.Update
|
||||
.Set(data => data.Value, value)
|
||||
.Set(data => data.LastUpdated, DateTime.UtcNow);
|
||||
|
||||
await Collection.UpdateOneAsync(data => data.Id == dataId, update);
|
||||
}
|
||||
await Collection.UpdateOneAsync(data => data.Id == dataId, update);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,46 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Options;
|
||||
using MongoDB.Driver;
|
||||
using Prospect.Server.Api.Config;
|
||||
using Prospect.Server.Api.Services.Database.Models;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Database
|
||||
namespace Prospect.Server.Api.Services.Database;
|
||||
|
||||
public class DbUserService : BaseDbService<PlayFabUser>
|
||||
{
|
||||
public class DbUserService : BaseDbService<PlayFabUser>
|
||||
public DbUserService(IOptions<DatabaseSettings> settings) : base(settings, nameof(PlayFabUser))
|
||||
{
|
||||
public DbUserService(IOptions<DatabaseSettings> settings) : base(settings, nameof(PlayFabUser))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<PlayFabUser> FindAsync(PlayFabUserAuthType type, string key)
|
||||
{
|
||||
return await Collection.Find(user => user.Auth.Any(auth =>
|
||||
auth.Type == type &&
|
||||
auth.Key == key)).FirstOrDefaultAsync();
|
||||
}
|
||||
public async Task<PlayFabUser> FindAsync(PlayFabUserAuthType type, string key)
|
||||
{
|
||||
return await Collection.Find(user => user.Auth.Any(auth =>
|
||||
auth.Type == type &&
|
||||
auth.Key == key)).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
private async Task<PlayFabUser> CreateAsync(PlayFabUserAuthType type, string key)
|
||||
private async Task<PlayFabUser> CreateAsync(PlayFabUserAuthType type, string key)
|
||||
{
|
||||
var user = new PlayFabUser
|
||||
{
|
||||
var user = new PlayFabUser
|
||||
DisplayName = "Unknown",
|
||||
Auth = new List<PlayFabUserAuth>
|
||||
{
|
||||
DisplayName = "Unknown",
|
||||
Auth = new List<PlayFabUserAuth>
|
||||
new PlayFabUserAuth
|
||||
{
|
||||
new PlayFabUserAuth
|
||||
{
|
||||
Type = type,
|
||||
Key = key
|
||||
}
|
||||
Type = type,
|
||||
Key = key
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
await Collection.InsertOneAsync(user);
|
||||
await Collection.InsertOneAsync(user);
|
||||
|
||||
return user;
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
public async Task<PlayFabUser> FindOrCreateAsync(PlayFabUserAuthType type, string key)
|
||||
{
|
||||
return await FindAsync(type, key) ??
|
||||
await CreateAsync(type, key);
|
||||
}
|
||||
public async Task<PlayFabUser> FindOrCreateAsync(PlayFabUserAuthType type, string key)
|
||||
{
|
||||
return await FindAsync(type, key) ??
|
||||
await CreateAsync(type, key);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +1,21 @@
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Cryptography;
|
||||
using MongoDB.Bson.Serialization;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Database.Generator
|
||||
{
|
||||
public class PlayFabIdGenerator : IIdGenerator
|
||||
{
|
||||
private static readonly RNGCryptoServiceProvider Random = new RNGCryptoServiceProvider();
|
||||
|
||||
public object GenerateId(object container, object document)
|
||||
{
|
||||
Span<byte> data = stackalloc byte[8];
|
||||
Random.GetBytes(data);
|
||||
return Convert.ToHexString(data);
|
||||
}
|
||||
namespace Prospect.Server.Api.Services.Database.Generator;
|
||||
|
||||
public bool IsEmpty(object id)
|
||||
{
|
||||
return id is not string idStr || string.IsNullOrEmpty(idStr);
|
||||
}
|
||||
public class PlayFabIdGenerator : IIdGenerator
|
||||
{
|
||||
private static readonly RNGCryptoServiceProvider Random = new RNGCryptoServiceProvider();
|
||||
|
||||
public object GenerateId(object container, object document)
|
||||
{
|
||||
Span<byte> data = stackalloc byte[8];
|
||||
Random.GetBytes(data);
|
||||
return Convert.ToHexString(data);
|
||||
}
|
||||
|
||||
public bool IsEmpty(object id)
|
||||
{
|
||||
return id is not string idStr || string.IsNullOrEmpty(idStr);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Prospect.Server.Api.Services.Database.Generator;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Database.Models
|
||||
namespace Prospect.Server.Api.Services.Database.Models;
|
||||
|
||||
/// <summary>
|
||||
/// title_player_account
|
||||
/// </summary>
|
||||
public class PlayFabEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// title_player_account
|
||||
/// </summary>
|
||||
public class PlayFabEntity
|
||||
{
|
||||
[BsonId(IdGenerator = typeof(PlayFabIdGenerator))]
|
||||
public string Id { get; set; }
|
||||
[BsonId(IdGenerator = typeof(PlayFabIdGenerator))]
|
||||
public string Id { get; set; }
|
||||
|
||||
[BsonRequired]
|
||||
[BsonElement("UserId")]
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
[BsonRequired]
|
||||
[BsonElement("UserId")]
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
@@ -1,23 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
using Prospect.Server.Api.Services.Database.Generator;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Database.Models
|
||||
namespace Prospect.Server.Api.Services.Database.Models;
|
||||
|
||||
/// <summary>
|
||||
/// master_player_account
|
||||
/// </summary>
|
||||
public class PlayFabUser
|
||||
{
|
||||
/// <summary>
|
||||
/// master_player_account
|
||||
/// </summary>
|
||||
public class PlayFabUser
|
||||
{
|
||||
[BsonId(IdGenerator = typeof(PlayFabIdGenerator))]
|
||||
public string Id { get; set; }
|
||||
[BsonId(IdGenerator = typeof(PlayFabIdGenerator))]
|
||||
public string Id { get; set; }
|
||||
|
||||
[BsonRequired]
|
||||
[BsonElement("DisplayName")]
|
||||
public string DisplayName { get; set; }
|
||||
[BsonRequired]
|
||||
[BsonElement("DisplayName")]
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
[BsonRequired]
|
||||
[BsonElement("Auth")]
|
||||
public List<PlayFabUserAuth> Auth { get; set; }
|
||||
}
|
||||
[BsonRequired]
|
||||
[BsonElement("Auth")]
|
||||
public List<PlayFabUserAuth> Auth { get; set; }
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Database.Models
|
||||
namespace Prospect.Server.Api.Services.Database.Models;
|
||||
|
||||
public class PlayFabUserAuth
|
||||
{
|
||||
public class PlayFabUserAuth
|
||||
{
|
||||
[BsonElement("Type")]
|
||||
public PlayFabUserAuthType Type { get; set; }
|
||||
[BsonElement("Type")]
|
||||
public PlayFabUserAuthType Type { get; set; }
|
||||
|
||||
[BsonElement("Key")]
|
||||
public string Key { get; set; }
|
||||
}
|
||||
[BsonElement("Key")]
|
||||
public string Key { get; set; }
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
namespace Prospect.Server.Api.Services.Database.Models
|
||||
namespace Prospect.Server.Api.Services.Database.Models;
|
||||
|
||||
public enum PlayFabUserAuthType
|
||||
{
|
||||
public enum PlayFabUserAuthType
|
||||
{
|
||||
Epic,
|
||||
Steam
|
||||
}
|
||||
Epic,
|
||||
Steam
|
||||
}
|
||||
@@ -1,36 +1,34 @@
|
||||
using System;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson;
|
||||
using MongoDB.Bson.Serialization.Attributes;
|
||||
|
||||
namespace Prospect.Server.Api.Services.Database.Models
|
||||
{
|
||||
public class PlayFabUserData
|
||||
{
|
||||
[BsonId]
|
||||
[BsonRepresentation(BsonType.ObjectId)]
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// PlayFabUser.Id
|
||||
/// </summary>
|
||||
[BsonRequired]
|
||||
[BsonElement("PlayFabId")]
|
||||
public string PlayFabId { get; set; }
|
||||
namespace Prospect.Server.Api.Services.Database.Models;
|
||||
|
||||
[BsonRequired]
|
||||
[BsonElement("Key")]
|
||||
public string Key { get; set; }
|
||||
public class PlayFabUserData
|
||||
{
|
||||
[BsonId]
|
||||
[BsonRepresentation(BsonType.ObjectId)]
|
||||
public string Id { get; set; }
|
||||
|
||||
[BsonRequired]
|
||||
[BsonElement("Value")]
|
||||
public string Value { get; set; }
|
||||
/// <summary>
|
||||
/// PlayFabUser.Id
|
||||
/// </summary>
|
||||
[BsonRequired]
|
||||
[BsonElement("PlayFabId")]
|
||||
public string PlayFabId { get; set; }
|
||||
|
||||
[BsonRequired]
|
||||
[BsonElement("Key")]
|
||||
public string Key { get; set; }
|
||||
|
||||
[BsonRequired]
|
||||
[BsonElement("Public")]
|
||||
public bool Public { get; set; }
|
||||
[BsonRequired]
|
||||
[BsonElement("Value")]
|
||||
public string Value { get; set; }
|
||||
|
||||
[BsonRequired]
|
||||
[BsonElement("LastUpdated")]
|
||||
public DateTime LastUpdated { get; set; }
|
||||
}
|
||||
[BsonRequired]
|
||||
[BsonElement("Public")]
|
||||
public bool Public { get; set; }
|
||||
|
||||
[BsonRequired]
|
||||
[BsonElement("LastUpdated")]
|
||||
public DateTime LastUpdated { get; set; }
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,33 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Logging;
|
||||
namespace Prospect.Server.Api.Services.UserData;
|
||||
|
||||
namespace Prospect.Server.Api.Services.UserData
|
||||
public class TitleDataService
|
||||
{
|
||||
public class TitleDataService
|
||||
{
|
||||
public TitleDataService(ILogger<TitleDataService> logger)
|
||||
{
|
||||
public TitleDataService(ILogger<TitleDataService> logger)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, string> Find(List<string> keys)
|
||||
{
|
||||
if (keys != null && keys.Count > 0)
|
||||
{
|
||||
var result = new Dictionary<string, string>();
|
||||
public Dictionary<string, string> Find(List<string> keys)
|
||||
{
|
||||
if (keys != null && keys.Count > 0)
|
||||
{
|
||||
var result = new Dictionary<string, string>();
|
||||
|
||||
foreach (var key in keys)
|
||||
{
|
||||
if (TitleDataDefault.Data.TryGetValue(key, out var value))
|
||||
{
|
||||
result.Add(key, value);
|
||||
}
|
||||
}
|
||||
foreach (var key in keys)
|
||||
{
|
||||
if (TitleDataDefault.Data.TryGetValue(key, out var value))
|
||||
{
|
||||
result.Add(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return TitleDataDefault.Data;
|
||||
}
|
||||
}
|
||||
return TitleDataDefault.Data;
|
||||
}
|
||||
}
|
||||
@@ -1,182 +1,177 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Prospect.Server.Api.Models.Client.Data;
|
||||
using Prospect.Server.Api.Models.Client.Data;
|
||||
using Prospect.Server.Api.Services.Database;
|
||||
|
||||
namespace Prospect.Server.Api.Services.UserData
|
||||
namespace Prospect.Server.Api.Services.UserData;
|
||||
|
||||
public class UserDataService
|
||||
{
|
||||
public class UserDataService
|
||||
private readonly ILogger<UserDataService> _logger;
|
||||
private readonly DbUserDataService _dbUserDataService;
|
||||
|
||||
public UserDataService(ILogger<UserDataService> logger, DbUserDataService dbUserDataService)
|
||||
{
|
||||
private readonly ILogger<UserDataService> _logger;
|
||||
private readonly DbUserDataService _dbUserDataService;
|
||||
_logger = logger;
|
||||
_dbUserDataService = dbUserDataService;
|
||||
}
|
||||
|
||||
public UserDataService(ILogger<UserDataService> logger, DbUserDataService dbUserDataService)
|
||||
/// <summary>
|
||||
/// Initialize data for the given PlayFabId.
|
||||
/// </summary>
|
||||
public async Task InitAsync(string playFabId)
|
||||
{
|
||||
// TODO: Proper objects.
|
||||
var defaultData = new Dictionary<string, (bool isPublic, string value)>
|
||||
{
|
||||
_logger = logger;
|
||||
_dbUserDataService = dbUserDataService;
|
||||
["Generators__2021_09_09"] = (true, "[{\"generatorId\":\"playerquarters_gen_aurum\",\"lastClaimTime\":{\"seconds\":0}},{\"generatorId\":\"playerquarters_gen_kmarks\",\"lastClaimTime\":{\"seconds\":0}},{\"generatorId\":\"playerquarters_gen_crate\",\"lastClaimTime\":{\"seconds\":0}}]"),
|
||||
["InventoryInfo"] = (true, "{\"inventoryStashLimit\":75,\"inventoryBagLimit\":300,\"inventorySafeLimit\":5}"),
|
||||
["LOADOUT"] = (true, $"{{\"id\":\"\",\"userId\":\"{playFabId}\",\"kit\":\"\",\"shield\":\"\",\"helmet\":\"\",\"weaponOne\":\"\",\"weaponTwo\":\"\",\"bag\":null,\"bagItemsAsJsonStr\":\"\",\"safeItemsAsJsonStr\":\"\"}}"),
|
||||
["OnboardingProgression"] = (true, "{\"currentMissionID\":\"TalkToBadum\",\"progress\":0,\"showPopup\":true}"),
|
||||
["PickaxeUpgradeLevel"] = (true, "0"),
|
||||
["PlayerQuartersLevel"] = (true, "{\"level\":1,\"upgradeStartedTime\":{\"seconds\":0}}"),
|
||||
};
|
||||
|
||||
foreach (var (key, (isPublic, value)) in defaultData)
|
||||
{
|
||||
if (!await _dbUserDataService.HasAsync(playFabId, key))
|
||||
{
|
||||
await _dbUserDataService.InsertAsync(playFabId, key, value, isPublic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="currentUserId">
|
||||
/// The authenticated user id.
|
||||
/// </param>
|
||||
/// <param name="requestUserId">
|
||||
/// The requested user id.
|
||||
/// </param>
|
||||
/// <param name="keys"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Dictionary<string, FUserDataRecord>> FindAsync(
|
||||
string currentUserId,
|
||||
string requestUserId,
|
||||
List<string> keys)
|
||||
{
|
||||
if (string.IsNullOrEmpty(currentUserId))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(currentUserId));
|
||||
}
|
||||
|
||||
if (requestUserId == null)
|
||||
{
|
||||
requestUserId = currentUserId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize data for the given PlayFabId.
|
||||
/// </summary>
|
||||
public async Task InitAsync(string playFabId)
|
||||
var other = currentUserId != requestUserId;
|
||||
var result = new Dictionary<string, FUserDataRecord>();
|
||||
|
||||
if (keys != null && keys.Count > 0)
|
||||
{
|
||||
// TODO: Proper objects.
|
||||
var defaultData = new Dictionary<string, (bool isPublic, string value)>
|
||||
foreach (var key in keys)
|
||||
{
|
||||
["Generators__2021_09_09"] = (true, "[{\"generatorId\":\"playerquarters_gen_aurum\",\"lastClaimTime\":{\"seconds\":0}},{\"generatorId\":\"playerquarters_gen_kmarks\",\"lastClaimTime\":{\"seconds\":0}},{\"generatorId\":\"playerquarters_gen_crate\",\"lastClaimTime\":{\"seconds\":0}}]"),
|
||||
["InventoryInfo"] = (true, "{\"inventoryStashLimit\":75,\"inventoryBagLimit\":300,\"inventorySafeLimit\":5}"),
|
||||
["LOADOUT"] = (true, $"{{\"id\":\"\",\"userId\":\"{playFabId}\",\"kit\":\"\",\"shield\":\"\",\"helmet\":\"\",\"weaponOne\":\"\",\"weaponTwo\":\"\",\"bag\":null,\"bagItemsAsJsonStr\":\"\",\"safeItemsAsJsonStr\":\"\"}}"),
|
||||
["OnboardingProgression"] = (true, "{\"currentMissionID\":\"TalkToBadum\",\"progress\":0,\"showPopup\":true}"),
|
||||
["PickaxeUpgradeLevel"] = (true, "0"),
|
||||
["PlayerQuartersLevel"] = (true, "{\"level\":1,\"upgradeStartedTime\":{\"seconds\":0}}"),
|
||||
};
|
||||
|
||||
foreach (var (key, (isPublic, value)) in defaultData)
|
||||
{
|
||||
if (!await _dbUserDataService.HasAsync(playFabId, key))
|
||||
var data = await _dbUserDataService.FindAsync(requestUserId, key);
|
||||
if (data == null)
|
||||
{
|
||||
await _dbUserDataService.InsertAsync(playFabId, key, value, isPublic);
|
||||
// TODO: Error?
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="currentUserId">
|
||||
/// The authenticated user id.
|
||||
/// </param>
|
||||
/// <param name="requestUserId">
|
||||
/// The requested user id.
|
||||
/// </param>
|
||||
/// <param name="keys"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Dictionary<string, FUserDataRecord>> FindAsync(
|
||||
string currentUserId,
|
||||
string requestUserId,
|
||||
List<string> keys)
|
||||
{
|
||||
if (string.IsNullOrEmpty(currentUserId))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(currentUserId));
|
||||
}
|
||||
|
||||
if (requestUserId == null)
|
||||
{
|
||||
requestUserId = currentUserId;
|
||||
}
|
||||
|
||||
var other = currentUserId != requestUserId;
|
||||
var result = new Dictionary<string, FUserDataRecord>();
|
||||
|
||||
if (keys != null && keys.Count > 0)
|
||||
{
|
||||
foreach (var key in keys)
|
||||
if (!data.Public && other)
|
||||
{
|
||||
var data = await _dbUserDataService.FindAsync(requestUserId, key);
|
||||
if (data == null)
|
||||
{
|
||||
// TODO: Error?
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!data.Public && other)
|
||||
{
|
||||
// TODO: Error?
|
||||
continue;
|
||||
}
|
||||
// TODO: Error?
|
||||
continue;
|
||||
}
|
||||
|
||||
result.Add(data.Key, new FUserDataRecord
|
||||
{
|
||||
LastUpdated = data.LastUpdated,
|
||||
Permission = data.Public ? UserDataPermission.Public : UserDataPermission.Private,
|
||||
Value = data.Value
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var cursor = await _dbUserDataService.AllAsync(requestUserId, other);
|
||||
|
||||
while (await cursor.MoveNextAsync())
|
||||
{
|
||||
foreach (var data in cursor.Current)
|
||||
{
|
||||
result.Add(data.Key, new FUserDataRecord
|
||||
{
|
||||
LastUpdated = data.LastUpdated,
|
||||
Permission = data.Public ? UserDataPermission.Public : UserDataPermission.Private,
|
||||
Value = data.Value
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var cursor = await _dbUserDataService.AllAsync(requestUserId, other);
|
||||
|
||||
while (await cursor.MoveNextAsync())
|
||||
{
|
||||
foreach (var data in cursor.Current)
|
||||
{
|
||||
result.Add(data.Key, new FUserDataRecord
|
||||
{
|
||||
LastUpdated = data.LastUpdated,
|
||||
Permission = data.Public ? UserDataPermission.Public : UserDataPermission.Private,
|
||||
Value = data.Value
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="currentUserId">
|
||||
/// The authenticated user id.
|
||||
/// </param>
|
||||
/// <param name="requestUserId">
|
||||
/// The requested user id.
|
||||
/// </param>
|
||||
/// <param name="changes"></param>
|
||||
/// <returns></returns>
|
||||
public async Task UpdateAsync(
|
||||
string currentUserId,
|
||||
string requestUserId,
|
||||
Dictionary<string, string> changes)
|
||||
{
|
||||
if (changes.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(currentUserId))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(currentUserId));
|
||||
}
|
||||
|
||||
if (requestUserId == null)
|
||||
{
|
||||
requestUserId = currentUserId;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Whether we are updating someone else.
|
||||
var other = currentUserId != requestUserId;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="currentUserId">
|
||||
/// The authenticated user id.
|
||||
/// </param>
|
||||
/// <param name="requestUserId">
|
||||
/// The requested user id.
|
||||
/// </param>
|
||||
/// <param name="changes"></param>
|
||||
/// <returns></returns>
|
||||
public async Task UpdateAsync(
|
||||
string currentUserId,
|
||||
string requestUserId,
|
||||
Dictionary<string, string> changes)
|
||||
{
|
||||
if (changes.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (key, value) in changes)
|
||||
if (string.IsNullOrEmpty(currentUserId))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(currentUserId));
|
||||
}
|
||||
|
||||
if (requestUserId == null)
|
||||
{
|
||||
requestUserId = currentUserId;
|
||||
}
|
||||
|
||||
// Whether we are updating someone else.
|
||||
var other = currentUserId != requestUserId;
|
||||
|
||||
foreach (var (key, value) in changes)
|
||||
{
|
||||
var data = await _dbUserDataService.FindAsync(currentUserId, key);
|
||||
if (data == null)
|
||||
{
|
||||
var data = await _dbUserDataService.FindAsync(currentUserId, key);
|
||||
if (data == null)
|
||||
if (other)
|
||||
{
|
||||
if (other)
|
||||
{
|
||||
_logger.LogWarning("User {PlayFabId} attempted to update non-existing key {Key} of another user {PlayFabIdOther}", currentUserId, key, requestUserId);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _dbUserDataService.InsertAsync(currentUserId, key, value, false);
|
||||
}
|
||||
_logger.LogWarning("User {PlayFabId} attempted to update non-existing key {Key} of another user {PlayFabIdOther}", currentUserId, key, requestUserId);
|
||||
}
|
||||
else
|
||||
{
|
||||
await _dbUserDataService.InsertAsync(currentUserId, key, value, false);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!data.Public && other)
|
||||
{
|
||||
_logger.LogWarning("User {PlayFabId} attempted to update non-public key {Key} of another user {PlayFabIdOther}", currentUserId, key, data.PlayFabId);
|
||||
continue;
|
||||
}
|
||||
|
||||
await _dbUserDataService.UpdateValueAsync(data.Id, value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!data.Public && other)
|
||||
{
|
||||
_logger.LogWarning("User {PlayFabId} attempted to update non-public key {Key} of another user {PlayFabIdOther}", currentUserId, key, data.PlayFabId);
|
||||
continue;
|
||||
}
|
||||
|
||||
await _dbUserDataService.UpdateValueAsync(data.Id, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +1,65 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Prospect.Server.Api.Config;
|
||||
using Prospect.Server.Api.Converters;
|
||||
using Prospect.Server.Api.Middleware;
|
||||
using Prospect.Server.Api.Services.Auth;
|
||||
using Prospect.Server.Api.Services.Auth.User;
|
||||
using Prospect.Server.Api.Services.Database;
|
||||
using Prospect.Server.Api.Services.UserData;
|
||||
using Serilog;
|
||||
|
||||
namespace Prospect.Server.Api
|
||||
namespace Prospect.Server.Api;
|
||||
|
||||
public class Startup
|
||||
{
|
||||
public class Startup
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
private IConfiguration Configuration { get; }
|
||||
private IConfiguration Configuration { get; }
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.Configure<AuthTokenSettings>(Configuration.GetSection(nameof(AuthTokenSettings)));
|
||||
services.Configure<DatabaseSettings>(Configuration.GetSection(nameof(DatabaseSettings)));
|
||||
services.Configure<PlayFabSettings>(Configuration.GetSection(nameof(PlayFabSettings)));
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.Configure<AuthTokenSettings>(Configuration.GetSection(nameof(AuthTokenSettings)));
|
||||
services.Configure<DatabaseSettings>(Configuration.GetSection(nameof(DatabaseSettings)));
|
||||
services.Configure<PlayFabSettings>(Configuration.GetSection(nameof(PlayFabSettings)));
|
||||
|
||||
services.AddSingleton<AuthTokenService>();
|
||||
services.AddSingleton<UserDataService>();
|
||||
services.AddSingleton<TitleDataService>();
|
||||
services.AddSingleton<AuthTokenService>();
|
||||
services.AddSingleton<UserDataService>();
|
||||
services.AddSingleton<TitleDataService>();
|
||||
|
||||
services.AddSingleton<DbUserService>();
|
||||
services.AddSingleton<DbEntityService>();
|
||||
services.AddSingleton<DbUserService>();
|
||||
services.AddSingleton<DbEntityService>();
|
||||
|
||||
services.AddSingleton<DbUserDataService>();
|
||||
services.AddSingleton<DbUserDataService>();
|
||||
|
||||
services.AddAuthentication(_ =>
|
||||
{
|
||||
services.AddAuthentication(_ =>
|
||||
{
|
||||
|
||||
})
|
||||
.AddUserAuthentication(_ => {})
|
||||
.AddEntityAuthentication(_ => {});
|
||||
})
|
||||
.AddUserAuthentication(_ => {})
|
||||
.AddEntityAuthentication(_ => {});
|
||||
|
||||
services.AddControllers().AddJsonOptions(options =>
|
||||
{
|
||||
options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
|
||||
});
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
services.AddControllers().AddJsonOptions(options =>
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseSerilogRequestLogging();
|
||||
app.UseMiddleware<RequestLoggerMiddleware>();
|
||||
app.UseRouting();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
});
|
||||
options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
|
||||
});
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
app.UseSerilogRequestLogging();
|
||||
app.UseMiddleware<RequestLoggerMiddleware>();
|
||||
app.UseRouting();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllers();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
namespace Prospect.Server.Steam;
|
||||
|
||||
namespace Prospect.Server.Steam
|
||||
public class AppDlc
|
||||
{
|
||||
public class AppDlc
|
||||
{
|
||||
public uint AppId { get; set; }
|
||||
public uint AppId { get; set; }
|
||||
|
||||
public List<uint> Licenses { get; set; }
|
||||
}
|
||||
public List<uint> Licenses { get; set; }
|
||||
}
|
||||
@@ -1,167 +1,163 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net;
|
||||
|
||||
namespace Prospect.Server.Steam
|
||||
namespace Prospect.Server.Steam;
|
||||
|
||||
public class AppTicket
|
||||
{
|
||||
public class AppTicket
|
||||
private AppTicket()
|
||||
{
|
||||
private AppTicket()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Full appticket, with a GC token and session header.
|
||||
/// </summary>
|
||||
public byte[] AuthTicket { get; set; }
|
||||
/// <summary>
|
||||
/// Full appticket, with a GC token and session header.
|
||||
/// </summary>
|
||||
public byte[] AuthTicket { get; set; }
|
||||
|
||||
public ulong GcToken { get; set; }
|
||||
public ulong GcToken { get; set; }
|
||||
|
||||
public DateTimeOffset TokenGenerated { get; set; }
|
||||
public DateTimeOffset TokenGenerated { get; set; }
|
||||
|
||||
private IPAddress SessionExternalIp { get; set; }
|
||||
private IPAddress SessionExternalIp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Time the client has been connected to Steam in ms.
|
||||
/// </summary>
|
||||
public uint ClientConnectionTime { get; set; }
|
||||
/// <summary>
|
||||
/// Time the client has been connected to Steam in ms.
|
||||
/// </summary>
|
||||
public uint ClientConnectionTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How many servers the client has connected to.
|
||||
/// </summary>
|
||||
public uint ClientConnectionCount { get; set; }
|
||||
/// <summary>
|
||||
/// How many servers the client has connected to.
|
||||
/// </summary>
|
||||
public uint ClientConnectionCount { get; set; }
|
||||
|
||||
public uint Version { get; set; }
|
||||
public uint Version { get; set; }
|
||||
|
||||
public ulong SteamId { get; set; }
|
||||
public ulong SteamId { get; set; }
|
||||
|
||||
public uint AppId { get; set; }
|
||||
public uint AppId { get; set; }
|
||||
|
||||
public IPAddress OwnershipTicketExternalIp { get; set; }
|
||||
public IPAddress OwnershipTicketExternalIp { get; set; }
|
||||
|
||||
public IPAddress OwnershipTicketInternalIp { get; set; }
|
||||
public IPAddress OwnershipTicketInternalIp { get; set; }
|
||||
|
||||
public uint OwnershipFlags { get; set; }
|
||||
public uint OwnershipFlags { get; set; }
|
||||
|
||||
public DateTimeOffset OwnershipTicketGenerated { get; set; }
|
||||
public DateTimeOffset OwnershipTicketGenerated { get; set; }
|
||||
|
||||
public DateTimeOffset OwnershipTicketExpires { get; set; }
|
||||
public DateTimeOffset OwnershipTicketExpires { get; set; }
|
||||
|
||||
public List<uint> Licenses { get; set; }
|
||||
public List<uint> Licenses { get; set; }
|
||||
|
||||
public List<AppDlc> Dlc { get; set; }
|
||||
public List<AppDlc> Dlc { get; set; }
|
||||
|
||||
public byte[] Signature { get; set; }
|
||||
public byte[] Signature { get; set; }
|
||||
|
||||
public bool IsExpired { get; set; }
|
||||
public bool IsExpired { get; set; }
|
||||
|
||||
public bool HasValidSignature { get; set; }
|
||||
public bool HasValidSignature { get; set; }
|
||||
|
||||
public bool IsValid { get; set; }
|
||||
public bool IsValid { get; set; }
|
||||
|
||||
public static AppTicket Parse(string ticketHex)
|
||||
public static AppTicket Parse(string ticketHex)
|
||||
{
|
||||
var result = new AppTicket();
|
||||
var ticketBytes = Convert.FromHexString(ticketHex);
|
||||
|
||||
using (var stream = new MemoryStream(ticketBytes))
|
||||
using (var ticketReader = new BinaryReader(stream))
|
||||
{
|
||||
var result = new AppTicket();
|
||||
var ticketBytes = Convert.FromHexString(ticketHex);
|
||||
|
||||
using (var stream = new MemoryStream(ticketBytes))
|
||||
using (var ticketReader = new BinaryReader(stream))
|
||||
// AuthTicket
|
||||
var initialLength = ticketReader.ReadUInt32();
|
||||
if (initialLength == 20)
|
||||
{
|
||||
// AuthTicket
|
||||
var initialLength = ticketReader.ReadUInt32();
|
||||
if (initialLength == 20)
|
||||
{
|
||||
result.AuthTicket = ticketBytes.AsSpan(0, 52).ToArray();
|
||||
result.GcToken = ticketReader.ReadUInt64();
|
||||
result.AuthTicket = ticketBytes.AsSpan(0, 52).ToArray();
|
||||
result.GcToken = ticketReader.ReadUInt64();
|
||||
|
||||
ticketReader.BaseStream.Position += 8;
|
||||
ticketReader.BaseStream.Position += 8;
|
||||
|
||||
result.TokenGenerated = DateTimeOffset.FromUnixTimeSeconds(ticketReader.ReadUInt32());
|
||||
result.TokenGenerated = DateTimeOffset.FromUnixTimeSeconds(ticketReader.ReadUInt32());
|
||||
|
||||
if (ticketReader.ReadUInt32() != 24)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ticketReader.BaseStream.Position += 8;
|
||||
|
||||
result.SessionExternalIp = new IPAddress(BitConverter.GetBytes(ticketReader.ReadUInt32()));
|
||||
|
||||
ticketReader.BaseStream.Position += 4;
|
||||
|
||||
result.ClientConnectionTime = ticketReader.ReadUInt32();
|
||||
result.ClientConnectionCount = ticketReader.ReadUInt32();
|
||||
|
||||
if (ticketReader.ReadUInt32() + ticketReader.BaseStream.Position != ticketReader.BaseStream.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ticketReader.BaseStream.Position -= 4;
|
||||
}
|
||||
|
||||
// Ownership ticket
|
||||
var ownershipTicketOffset = ticketReader.BaseStream.Position;
|
||||
var ownershipTicketLength = ticketReader.ReadUInt32();
|
||||
if (ownershipTicketOffset + ownershipTicketLength != ticketReader.BaseStream.Length &&
|
||||
ownershipTicketOffset + ownershipTicketLength + 128 != ticketReader.BaseStream.Length)
|
||||
if (ticketReader.ReadUInt32() != 24)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
result.Version = ticketReader.ReadUInt32();
|
||||
result.SteamId = ticketReader.ReadUInt64();
|
||||
result.AppId = ticketReader.ReadUInt32();
|
||||
result.OwnershipTicketExternalIp = new IPAddress(BitConverter.GetBytes(ticketReader.ReadUInt32()));
|
||||
result.OwnershipTicketInternalIp = new IPAddress(BitConverter.GetBytes(ticketReader.ReadUInt32()));
|
||||
result.OwnershipFlags = ticketReader.ReadUInt32();
|
||||
result.OwnershipTicketGenerated = DateTimeOffset.FromUnixTimeSeconds(ticketReader.ReadUInt32());
|
||||
result.OwnershipTicketExpires = DateTimeOffset.FromUnixTimeSeconds(ticketReader.ReadUInt32());
|
||||
result.Licenses = new List<uint>();
|
||||
|
||||
var licenseCount = ticketReader.ReadUInt16();
|
||||
for (var i = 0; i < licenseCount; i++)
|
||||
{
|
||||
result.Licenses.Add(ticketReader.ReadUInt32());
|
||||
}
|
||||
|
||||
result.Dlc = new List<AppDlc>();
|
||||
|
||||
var dlcCount = ticketReader.ReadUInt16();
|
||||
for (var i = 0; i < dlcCount; i++)
|
||||
{
|
||||
var dlc = new AppDlc();
|
||||
|
||||
dlc.AppId = ticketReader.ReadUInt32();
|
||||
dlc.Licenses = new List<uint>();
|
||||
|
||||
var dlcLicenseCount = ticketReader.ReadUInt16();
|
||||
for (var j = 0; j < dlcLicenseCount; j++)
|
||||
{
|
||||
dlc.Licenses.Add(ticketReader.ReadUInt32());
|
||||
}
|
||||
ticketReader.BaseStream.Position += 8;
|
||||
|
||||
result.Dlc.Add(dlc);
|
||||
}
|
||||
result.SessionExternalIp = new IPAddress(BitConverter.GetBytes(ticketReader.ReadUInt32()));
|
||||
|
||||
ticketReader.BaseStream.Position += 4;
|
||||
|
||||
ticketReader.ReadUInt16();
|
||||
result.ClientConnectionTime = ticketReader.ReadUInt32();
|
||||
result.ClientConnectionCount = ticketReader.ReadUInt32();
|
||||
|
||||
if (ticketReader.BaseStream.Position + 128 == ticketReader.BaseStream.Length)
|
||||
if (ticketReader.ReadUInt32() + ticketReader.BaseStream.Position != ticketReader.BaseStream.Length)
|
||||
{
|
||||
result.Signature = ticketBytes.AsSpan((int)ticketReader.BaseStream.Position, 128).ToArray();
|
||||
return null;
|
||||
}
|
||||
|
||||
var date = DateTimeOffset.UtcNow;
|
||||
result.IsExpired = result.OwnershipTicketExpires < date;
|
||||
result.HasValidSignature = result.Signature != null && SteamCrypto.VerifySignature(ticketBytes.AsSpan((int)ownershipTicketOffset, (int)ownershipTicketLength).ToArray(), result.Signature);
|
||||
result.IsValid = !result.IsExpired && (result.Signature == null || result.HasValidSignature);
|
||||
}
|
||||
|
||||
return result;
|
||||
else
|
||||
{
|
||||
ticketReader.BaseStream.Position -= 4;
|
||||
}
|
||||
|
||||
// Ownership ticket
|
||||
var ownershipTicketOffset = ticketReader.BaseStream.Position;
|
||||
var ownershipTicketLength = ticketReader.ReadUInt32();
|
||||
if (ownershipTicketOffset + ownershipTicketLength != ticketReader.BaseStream.Length &&
|
||||
ownershipTicketOffset + ownershipTicketLength + 128 != ticketReader.BaseStream.Length)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
result.Version = ticketReader.ReadUInt32();
|
||||
result.SteamId = ticketReader.ReadUInt64();
|
||||
result.AppId = ticketReader.ReadUInt32();
|
||||
result.OwnershipTicketExternalIp = new IPAddress(BitConverter.GetBytes(ticketReader.ReadUInt32()));
|
||||
result.OwnershipTicketInternalIp = new IPAddress(BitConverter.GetBytes(ticketReader.ReadUInt32()));
|
||||
result.OwnershipFlags = ticketReader.ReadUInt32();
|
||||
result.OwnershipTicketGenerated = DateTimeOffset.FromUnixTimeSeconds(ticketReader.ReadUInt32());
|
||||
result.OwnershipTicketExpires = DateTimeOffset.FromUnixTimeSeconds(ticketReader.ReadUInt32());
|
||||
result.Licenses = new List<uint>();
|
||||
|
||||
var licenseCount = ticketReader.ReadUInt16();
|
||||
for (var i = 0; i < licenseCount; i++)
|
||||
{
|
||||
result.Licenses.Add(ticketReader.ReadUInt32());
|
||||
}
|
||||
|
||||
result.Dlc = new List<AppDlc>();
|
||||
|
||||
var dlcCount = ticketReader.ReadUInt16();
|
||||
for (var i = 0; i < dlcCount; i++)
|
||||
{
|
||||
var dlc = new AppDlc();
|
||||
|
||||
dlc.AppId = ticketReader.ReadUInt32();
|
||||
dlc.Licenses = new List<uint>();
|
||||
|
||||
var dlcLicenseCount = ticketReader.ReadUInt16();
|
||||
for (var j = 0; j < dlcLicenseCount; j++)
|
||||
{
|
||||
dlc.Licenses.Add(ticketReader.ReadUInt32());
|
||||
}
|
||||
|
||||
result.Dlc.Add(dlc);
|
||||
}
|
||||
|
||||
ticketReader.ReadUInt16();
|
||||
|
||||
if (ticketReader.BaseStream.Position + 128 == ticketReader.BaseStream.Length)
|
||||
{
|
||||
result.Signature = ticketBytes.AsSpan((int)ticketReader.BaseStream.Position, 128).ToArray();
|
||||
}
|
||||
|
||||
var date = DateTimeOffset.UtcNow;
|
||||
result.IsExpired = result.OwnershipTicketExpires < date;
|
||||
result.HasValidSignature = result.Signature != null && SteamCrypto.VerifySignature(ticketBytes.AsSpan((int)ownershipTicketOffset, (int)ownershipTicketLength).ToArray(), result.Signature);
|
||||
result.IsValid = !result.IsExpired && (result.Signature == null || result.HasValidSignature);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>true</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace Prospect.Server.Steam
|
||||
{
|
||||
internal static class SteamCrypto
|
||||
{
|
||||
private const string SystemCertificate = "-----BEGIN PUBLIC KEY-----\n" +
|
||||
"MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDf7BrWLBBmLBc1OhSwfFkRf53T\n" +
|
||||
"2Ct64+AVzRkeRuh7h3SiGEYxqQMUeYKO6UWiSRKpI2hzic9pobFhRr3Bvr/WARvY\n" +
|
||||
"gdTckPv+T1JzZsuVcNfFjrocejN1oWI0Rrtgt4Bo+hOneoo3S57G9F1fOpn5nsQ6\n" +
|
||||
"6WOiu4gZKODnFMBCiQIBEQ==\n" +
|
||||
"-----END PUBLIC KEY-----" ;
|
||||
|
||||
public static bool VerifySignature(byte[] data, byte[] signature)
|
||||
{
|
||||
var rsa = new RSACryptoServiceProvider();
|
||||
|
||||
rsa.ImportFromPem(SystemCertificate);
|
||||
|
||||
var dataOk = rsa.VerifyData(data, CryptoConfig.MapNameToOID("SHA1")!, signature);
|
||||
if (!dataOk)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var dataHashed = SHA1.HashData(data);
|
||||
var dataVerified = rsa.VerifyHash(dataHashed, CryptoConfig.MapNameToOID("SHA1")!, signature);
|
||||
namespace Prospect.Server.Steam;
|
||||
|
||||
return dataVerified;
|
||||
internal static class SteamCrypto
|
||||
{
|
||||
private const string SystemCertificate = "-----BEGIN PUBLIC KEY-----\n" +
|
||||
"MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQDf7BrWLBBmLBc1OhSwfFkRf53T\n" +
|
||||
"2Ct64+AVzRkeRuh7h3SiGEYxqQMUeYKO6UWiSRKpI2hzic9pobFhRr3Bvr/WARvY\n" +
|
||||
"gdTckPv+T1JzZsuVcNfFjrocejN1oWI0Rrtgt4Bo+hOneoo3S57G9F1fOpn5nsQ6\n" +
|
||||
"6WOiu4gZKODnFMBCiQIBEQ==\n" +
|
||||
"-----END PUBLIC KEY-----" ;
|
||||
|
||||
public static bool VerifySignature(byte[] data, byte[] signature)
|
||||
{
|
||||
var rsa = new RSACryptoServiceProvider();
|
||||
|
||||
rsa.ImportFromPem(SystemCertificate);
|
||||
|
||||
var dataOk = rsa.VerifyData(data, CryptoConfig.MapNameToOID("SHA1")!, signature);
|
||||
if (!dataOk)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var dataHashed = SHA1.HashData(data);
|
||||
var dataVerified = rsa.VerifyHash(dataHashed, CryptoConfig.MapNameToOID("SHA1")!, signature);
|
||||
|
||||
return dataVerified;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user