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