mirror of
https://github.com/JogmansonReal/Radicade.git
synced 2026-10-25 15:09:26 -07:00
229 lines
6.6 KiB
C#
229 lines
6.6 KiB
C#
using System.Security.Cryptography;
|
|
using System.Text.Json;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using RadicadeServer.DB;
|
|
using RadicadeServer.Extensions;
|
|
|
|
namespace RadicadeServer.API.Rooms
|
|
{
|
|
internal static class RoomEconomyPayload
|
|
{
|
|
private const string RawKey = "RoomEconomyPayload.Raw";
|
|
|
|
public static async Task<JsonElement?> ReadBodyAsync(HttpRequest request)
|
|
{
|
|
if (request.HasFormContentType)
|
|
{
|
|
try
|
|
{
|
|
var form = await request.ReadFormAsync();
|
|
if (form.Count > 0)
|
|
{
|
|
var fields = new Dictionary<string, object?>();
|
|
foreach (var field in form)
|
|
fields[field.Key] = field.Value.ToString();
|
|
foreach (var file in form.Files)
|
|
fields[file.Name] = file.FileName;
|
|
return JsonSerializer.SerializeToElement(fields);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
request.HttpContext.Items[RawKey] = $"<form body could not be read: {ex.Message}>";
|
|
}
|
|
}
|
|
|
|
string raw;
|
|
using (var reader = new StreamReader(request.Body))
|
|
raw = await reader.ReadToEndAsync();
|
|
|
|
var text = raw.TrimStart('\uFEFF', ' ', '\t', '\r', '\n');
|
|
if (text.Length == 0) return null;
|
|
|
|
if (text[0] is '{' or '[')
|
|
{
|
|
try
|
|
{
|
|
using var doc = JsonDocument.Parse(text);
|
|
return doc.RootElement.Clone();
|
|
}
|
|
catch (JsonException)
|
|
{
|
|
}
|
|
}
|
|
|
|
var pairs = ParsePairs(raw);
|
|
if (pairs.Count > 0)
|
|
{
|
|
request.HttpContext.Items[RawKey] = raw;
|
|
return JsonSerializer.SerializeToElement(pairs);
|
|
}
|
|
|
|
request.HttpContext.Items[RawKey] = raw;
|
|
return null;
|
|
}
|
|
|
|
public static string RawBody(HttpRequest request) =>
|
|
request.HttpContext.Items.TryGetValue(RawKey, out var raw) ? raw as string ?? "" : "";
|
|
|
|
public static JsonElement? Value(JsonElement? body, params string[] names)
|
|
{
|
|
if (body == null) return null;
|
|
|
|
var stack = new Stack<JsonElement>();
|
|
stack.Push(body.Value);
|
|
var visited = 0;
|
|
|
|
while (stack.Count > 0 && visited++ < 2000)
|
|
{
|
|
var element = stack.Pop();
|
|
if (element.ValueKind == JsonValueKind.Array)
|
|
{
|
|
foreach (var item in element.EnumerateArray()) stack.Push(item);
|
|
continue;
|
|
}
|
|
if (element.ValueKind != JsonValueKind.Object) continue;
|
|
|
|
foreach (var property in element.EnumerateObject())
|
|
{
|
|
if (property.Value.ValueKind is JsonValueKind.Object or JsonValueKind.Array)
|
|
{
|
|
stack.Push(property.Value);
|
|
continue;
|
|
}
|
|
if (Matches(property.Name, names)) return property.Value;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public static string? String(JsonElement? body, params string[] names)
|
|
{
|
|
var value = Value(body, names);
|
|
if (value == null) return null;
|
|
if (value.Value.ValueKind == JsonValueKind.String) return value.Value.GetString();
|
|
if (value.Value.ValueKind is JsonValueKind.Number or JsonValueKind.True or JsonValueKind.False)
|
|
return value.Value.ToString();
|
|
return null;
|
|
}
|
|
|
|
public static long? Long(JsonElement? body, params string[] names)
|
|
{
|
|
var value = Value(body, names);
|
|
if (value == null) return null;
|
|
if (value.Value.ValueKind == JsonValueKind.Number)
|
|
{
|
|
if (value.Value.TryGetInt64(out var number)) return number;
|
|
if (value.Value.TryGetDouble(out var real)) return (long)real;
|
|
}
|
|
if (value.Value.ValueKind == JsonValueKind.String && long.TryParse(value.Value.GetString(), out var parsed))
|
|
return parsed;
|
|
return null;
|
|
}
|
|
|
|
public static bool? Bool(JsonElement? body, params string[] names)
|
|
{
|
|
var value = Value(body, names);
|
|
if (value == null) return null;
|
|
if (value.Value.ValueKind == JsonValueKind.True) return true;
|
|
if (value.Value.ValueKind == JsonValueKind.False) return false;
|
|
return null;
|
|
}
|
|
|
|
public static long? LongFromRequest(HttpRequest request, params string[] names)
|
|
{
|
|
foreach (var pair in request.Query)
|
|
{
|
|
if (!Matches(pair.Key, names)) continue;
|
|
if (long.TryParse(pair.Value.FirstOrDefault(), out var fromQuery)) return fromQuery;
|
|
}
|
|
foreach (var pair in request.RouteValues)
|
|
{
|
|
if (!Matches(pair.Key, names)) continue;
|
|
if (long.TryParse(pair.Value?.ToString(), out var fromRoute)) return fromRoute;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static Dictionary<string, object?> Fields(JsonElement? body)
|
|
{
|
|
var fields = new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase);
|
|
if (body == null || body.Value.ValueKind != JsonValueKind.Object) return fields;
|
|
|
|
foreach (var property in body.Value.EnumerateObject())
|
|
{
|
|
fields[property.Name] = property.Value.ValueKind switch
|
|
{
|
|
JsonValueKind.String => property.Value.GetString(),
|
|
JsonValueKind.Number => property.Value.TryGetInt64(out var number) ? number : property.Value.GetDouble(),
|
|
JsonValueKind.True => true,
|
|
JsonValueKind.False => false,
|
|
JsonValueKind.Null => null,
|
|
_ => property.Value.Clone()
|
|
};
|
|
}
|
|
|
|
return fields;
|
|
}
|
|
|
|
public static async Task<long?> RoomIdAsync(RecDBContext db, HttpRequest request, JsonElement? body, params string[] names)
|
|
{
|
|
var roomId = Long(body, names) ?? LongFromRequest(request, names);
|
|
if (roomId is > 0) return roomId;
|
|
|
|
var accountId = request.HttpContext.User.GetUserId();
|
|
if (accountId is not > 0) return null;
|
|
var presence = await db.Presences.AsNoTracking()
|
|
.FirstOrDefaultAsync(item => item.playerId == accountId.Value);
|
|
if (presence?.roomInstance is not > 0) return null;
|
|
return await db.RoomInstances.AsNoTracking()
|
|
.Where(instance => instance.roomInstanceId == presence.roomInstance.Value)
|
|
.Select(instance => (long?)instance.roomId)
|
|
.FirstOrDefaultAsync();
|
|
}
|
|
|
|
public static string NewId()
|
|
{
|
|
var bytes = RandomNumberGenerator.GetBytes(16);
|
|
return Convert.ToBase64String(bytes).Replace('+', '-').Replace('/', '_').TrimEnd('=');
|
|
}
|
|
|
|
private static Dictionary<string, object?> ParsePairs(string raw)
|
|
{
|
|
var pairs = new Dictionary<string, object?>();
|
|
foreach (var pair in raw.Split('&', StringSplitOptions.RemoveEmptyEntries))
|
|
{
|
|
var at = pair.IndexOf('=');
|
|
var key = at < 0 ? pair : pair[..at];
|
|
var value = at < 0 ? "" : pair[(at + 1)..];
|
|
key = key.Trim();
|
|
if (key.Length == 0) continue;
|
|
|
|
try
|
|
{
|
|
pairs[Uri.UnescapeDataString(key.Replace('+', ' '))] =
|
|
Uri.UnescapeDataString(value.Replace('+', ' '));
|
|
}
|
|
catch (UriFormatException)
|
|
{
|
|
pairs[key] = value;
|
|
}
|
|
}
|
|
return pairs;
|
|
}
|
|
|
|
private static bool Matches(string name, string[] names)
|
|
{
|
|
foreach (var wanted in names)
|
|
{
|
|
if (string.Equals(Normalize(name), Normalize(wanted), StringComparison.Ordinal)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static string Normalize(string name) =>
|
|
string.Concat(name.Where(char.IsLetterOrDigit)).ToLowerInvariant();
|
|
}
|
|
}
|