From 3b82968c8e0b0e770833826de67c4119cc838c71 Mon Sep 17 00:00:00 2001 From: Lapis Date: Fri, 5 Jun 2026 09:21:20 -0400 Subject: [PATCH] some api work --- .gitignore | 1 + CannedNet/JSON/endpoints_old.json | 3 +- .../Services/Controllers/APIController.cs | 171 +----------------- .../Services/Controllers/AuthController.cs | 42 ++++- .../Services/Controllers/EconController.cs | 129 +++++++++++++ .../Services/Controllers/ImageController.cs | 109 +++++++---- .../Controllers/MatchmakingController.cs | 157 +++++++++++++++- .../Services/Controllers/RoomsController.cs | 7 + CannedNet/Services/Signatures.cs | 46 +++++ 9 files changed, 450 insertions(+), 215 deletions(-) create mode 100644 CannedNet/Services/Signatures.cs diff --git a/.gitignore b/.gitignore index 5ef5b7c..f3aee93 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ riderModule.iml /.idea /CannedNet.API/Migrations CannedNet.sln.DotSettings.user +CannedNet/Data/PrivateKey.pem diff --git a/CannedNet/JSON/endpoints_old.json b/CannedNet/JSON/endpoints_old.json index 5535149..a7572e2 100644 --- a/CannedNet/JSON/endpoints_old.json +++ b/CannedNet/JSON/endpoints_old.json @@ -22,6 +22,5 @@ "Discovery": "https://api.lapis.codes", "PlayerSettings": "https://api.lapis.codes", "Rendering": "https://api.lapis.codes", - "Launcher": "https://launcher.lapis.codes", - + "Launcher": "https://launcher.lapis.codes" } \ No newline at end of file diff --git a/CannedNet/Services/Controllers/APIController.cs b/CannedNet/Services/Controllers/APIController.cs index 33ae74d..c722c00 100644 --- a/CannedNet/Services/Controllers/APIController.cs +++ b/CannedNet/Services/Controllers/APIController.cs @@ -29,6 +29,13 @@ public class APIController UseRudderStack = false })); + app.MapGet("/api/config/v1/azurespeech", () => Results.Ok(new + { + Key = "dce8de5b297747d9b5bddcc7f19e8c5b", + Region = "eastus", + Enabled = false + })); + app.MapPost("/api/gamesight/event", async (HttpRequest request) => { string? eventType = null; @@ -417,31 +424,6 @@ public class APIController await db.SaveChangesAsync(); return Results.Ok(avatar); }); - - app.MapGet("/api/avatar/v3/saved", async (HttpRequest request, AppDbContext db) => - { - var authHeader = request.Headers.Authorization.ToString(); - - if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) - return Results.Unauthorized(); - - var token = authHeader.Substring("Bearer ".Length); - var accountId = jwtService.ValidateAndGetAccountId(token); - - if (string.IsNullOrEmpty(accountId)) - return Results.Unauthorized(); - - if (!int.TryParse(accountId.AsSpan(), out var id)) - return Results.Unauthorized(); - - request.EnableBuffering(); - - var items = await db.SavedOutfits - .Where(i => i.OwnerAccountId == id) - .ToListAsync(); - - return Results.Json(items); - }); app.MapGet("/api/PlayerReporting/v1/moderationBlockDetails", () => Results.Content("{\"ReportCategory\":0,\"Duration\":0,\"GameSessionId\":0,\"IsHostKick\":false,\"Message\":\"\",\"PlayerIdReporter\":null,\"IsBan\":false}", "application/json")); @@ -577,37 +559,6 @@ public class APIController var json = File.ReadAllText("JSON/tempmyprogress.json"); return Results.Content(json, "application/json"); }); - app.MapGet("/api/avatar/v2/gifts", async (HttpRequest request, AppDbContext db, JwtTokenService jwtService) => - { - try - { - var authHeader = request.Headers.Authorization.ToString(); - if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) - return Results.Unauthorized(); - - var token = authHeader.Substring("Bearer ".Length); - var accountId = jwtService.ValidateAndGetAccountId(token); - - if (string.IsNullOrEmpty(accountId) || !int.TryParse(accountId.AsSpan(), out var id)) - return Results.Unauthorized(); - - // Get all pending (unconsumed) gifts for this player - var pendingGifts = await db.ReceivedGifts - .Where(rg => rg.ReceiverAccountId == id && !rg.IsConsumed) - .ToListAsync(); - - return Results.Json(pendingGifts); - } - catch (Exception ex) - { - return Results.Problem($"Error retrieving gifts: {ex.Message}"); - } - }); - app.MapGet("/api/gamerewards/v1/pending", async (HttpRequest request, AppDbContext db) => - { - // TODO ADD FUNCTIONALITY - return "[]"; - }); app.MapGet("/api/communityboard/v2/current", async (HttpRequest request, AppDbContext db) => { var json = File.ReadAllText("JSON/communityboard.json"); @@ -618,10 +569,6 @@ public class APIController // TODO ADD FUNCTIONALITY return Results.Content("{\"Created\":[],\"Responses\":[]}", "application/json"); }); - app.MapPost("/api/CampusCard/v1/UpdateAndGetSubscription", async (HttpRequest request, AppDbContext db) => - { - return Results.Json(new { subscription = (object?)null, platformAccountSubscribedPlayerId = (object?)null }); - }); app.MapGet("/api/storefronts/v1/p2p/betaEnabled", async (HttpRequest request, AppDbContext db) => { return "false"; @@ -631,11 +578,6 @@ public class APIController var json = File.ReadAllText("JSON/announcements.json"); return Results.Content(json, "application/json"); }); - app.MapGet("/api/roomkeys/v1/mine", async (HttpRequest request, AppDbContext db) => - { - // TODO ADD FUNCTIONALITY - return "[]"; - }); app.MapGet("/api/quickPlay/v1/getandclear", async (HttpRequest request, AppDbContext db) => { // TODO ADD FUNCTIONALITY @@ -666,98 +608,6 @@ public class APIController return Results.Json(bio); }); - app.MapPost("/api/accounts/v1/forplatformids", async (HttpRequest request, AppDbContext db) => - { - request.EnableBuffering(); - request.Body.Position = 0; - using var reader = new StreamReader(request.Body); - var body = await reader.ReadToEndAsync(); - - var ids = new List(); - - if (!string.IsNullOrWhiteSpace(body)) - { - foreach (var pair in body.Split('&')) - { - var keyValue = pair.Split('='); - if (keyValue.Length == 2 && keyValue[0] == "Ids") - { - var idString = Uri.UnescapeDataString(keyValue[1]); - ids = idString.Split(',').ToList(); - break; - } - } - } - - var results = new List(); - foreach (var platformId in ids) - { - var cachedLogin = await db.CachedLogins.FirstOrDefaultAsync(c => c.PlatformID == platformId); - if (cachedLogin != null) - { - results.Add(new { accountId = cachedLogin.AccountId, platformId = platformId }); - } - } - - return Results.Json(results); - }); - app.MapGet("/api/storefronts/v3/giftdropstore/3", async (HttpRequest request, AppDbContext db) => - { - var storefronts = await storefrontService.GetStorefrontsAsync(); - var storefront = storefronts.FirstOrDefault(s => s.StorefrontType == 2 && s.Name == "watch_store"); - if (storefront == null) - { - var json = File.ReadAllText("JSON/storefront3.json"); - return Results.Content(json, "application/json"); - } - var storeItems = storefront.Items.Select(item => new - { - item.Id, - item.StorefrontId, - item.PurchasableItemId, - item.Type, - item.IsFeatured, - item.NewUntil, - GiftDrops = item.GiftDrops.Select(gd => new - { - gd.Id, - gd.StorefrontItemId, - gd.GiftDropId, - gd.FriendlyName, - gd.Tooltip, - gd.ConsumableItemDesc, - gd.AvatarItemDesc, - gd.AvatarItemType, - gd.EquipmentPrefabName, - gd.EquipmentModificationGuid, - gd.IsQuery, - gd.Unique, - gd.SubscribersOnly, - gd.Level, - gd.Rarity, - gd.CurrencyType, - gd.Currency, - gd.Context, - gd.ItemSetId, - gd.ItemSetFriendlyName - }).ToList(), - Prices = item.Prices.Select(p => new - { - p.Id, - p.StorefrontItemId, - p.CurrencyType, - p.Price - }).ToList() - }).ToList(); - var response = new { storefront.Id, storefront.Name, storefront.StorefrontType, storefront.NextUpdate, StoreItems = storeItems }; - return Results.Ok(response); - }); - app.MapGet("/api/challenge/v2/getCurrent", async (HttpRequest request, AppDbContext db) => - { - var json = File.ReadAllText("JSON/weeklychallenge.json"); - return Results.Content(json, "application/json"); - //return "{}"; - }); app.MapGet("/roomserver/rooms/bulk", async (HttpRequest request, AppDbContext db) => { var idParam = request.Query["id"].FirstOrDefault(); @@ -1068,13 +918,6 @@ public class APIController return Results.Json(response); }); - - app.MapGet("/roomserver/rooms/createdby/me", async (HttpRequest request, AppDbContext db) => - { - // TODO ADD FUNCTIONALITY - var json = File.ReadAllText("JSON/ownedrooms.json"); - return Results.Content(json, "application/json"); - }); app.MapGet("/roomserver/rooms/{id}", async (HttpRequest request, AppDbContext db, string id) => { // this sucked to do diff --git a/CannedNet/Services/Controllers/AuthController.cs b/CannedNet/Services/Controllers/AuthController.cs index 24ead4a..6a33b4f 100644 --- a/CannedNet/Services/Controllers/AuthController.cs +++ b/CannedNet/Services/Controllers/AuthController.cs @@ -90,9 +90,45 @@ public class AuthController }); app.MapGet("/role/developer/{id}", async (HttpRequest request, AppDbContext db, string id) => + { + // TODO: implement + return Results.Ok(RecNetResult.Ok()); + }); + + app.MapPost("/api/accounts/v1/forplatformids", async (HttpRequest request, AppDbContext db) => + { + request.EnableBuffering(); + request.Body.Position = 0; + using var reader = new StreamReader(request.Body); + var body = await reader.ReadToEndAsync(); + + var ids = new List(); + + if (!string.IsNullOrWhiteSpace(body)) + { + foreach (var pair in body.Split('&')) { - // TODO: implement - return Results.Ok(RecNetResult.Ok()); - }); + var keyValue = pair.Split('='); + if (keyValue.Length == 2 && keyValue[0] == "Ids") + { + var idString = Uri.UnescapeDataString(keyValue[1]); + ids = idString.Split(',').ToList(); + break; + } + } + } + + var results = new List(); + foreach (var platformId in ids) + { + var cachedLogin = await db.CachedLogins.FirstOrDefaultAsync(c => c.PlatformID == platformId); + if (cachedLogin != null) + { + results.Add(new { accountId = cachedLogin.AccountId, platformId = platformId }); + } + } + + return Results.Json(results); + }); } } diff --git a/CannedNet/Services/Controllers/EconController.cs b/CannedNet/Services/Controllers/EconController.cs index 6bbabab..ecc8d8d 100644 --- a/CannedNet/Services/Controllers/EconController.cs +++ b/CannedNet/Services/Controllers/EconController.cs @@ -12,6 +12,7 @@ public class EconController { var jwtService = app.Services.GetRequiredService(); var notificationService = app.Services.GetRequiredService(); + var storefrontService = app.Services.GetRequiredService(); app.MapGet("/api/avatar/v1/defaultunlocked", () => { @@ -362,5 +363,133 @@ public class EconController return Results.Json(balance); }); + + app.MapGet("/api/storefronts/v3/giftdropstore/3", async (HttpRequest request, AppDbContext db) => + { + var storefronts = await storefrontService.GetStorefrontsAsync(); + var storefront = storefronts.FirstOrDefault(s => s.StorefrontType == 2 && s.Name == "watch_store"); + if (storefront == null) + { + var json = File.ReadAllText("JSON/storefront3.json"); + return Results.Content(json, "application/json"); + } + var storeItems = storefront.Items.Select(item => new + { + item.Id, + item.StorefrontId, + item.PurchasableItemId, + item.Type, + item.IsFeatured, + item.NewUntil, + GiftDrops = item.GiftDrops.Select(gd => new + { + gd.Id, + gd.StorefrontItemId, + gd.GiftDropId, + gd.FriendlyName, + gd.Tooltip, + gd.ConsumableItemDesc, + gd.AvatarItemDesc, + gd.AvatarItemType, + gd.EquipmentPrefabName, + gd.EquipmentModificationGuid, + gd.IsQuery, + gd.Unique, + gd.SubscribersOnly, + gd.Level, + gd.Rarity, + gd.CurrencyType, + gd.Currency, + gd.Context, + gd.ItemSetId, + gd.ItemSetFriendlyName + }).ToList(), + Prices = item.Prices.Select(p => new + { + p.Id, + p.StorefrontItemId, + p.CurrencyType, + p.Price + }).ToList() + }).ToList(); + var response = new { storefront.Id, storefront.Name, storefront.StorefrontType, storefront.NextUpdate, StoreItems = storeItems }; + return Results.Ok(response); + }); + + app.MapGet("/api/challenge/v2/getCurrent", async (HttpRequest request, AppDbContext db) => + { + var json = File.ReadAllText("JSON/weeklychallenge.json"); + return Results.Content(json, "application/json"); + //return "{}"; + }); + + app.MapGet("/api/avatar/v3/saved", async (HttpRequest request, AppDbContext db) => + { + var authHeader = request.Headers.Authorization.ToString(); + + if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) + return Results.Unauthorized(); + + var token = authHeader.Substring("Bearer ".Length); + var accountId = jwtService.ValidateAndGetAccountId(token); + + if (string.IsNullOrEmpty(accountId)) + return Results.Unauthorized(); + + if (!int.TryParse(accountId.AsSpan(), out var id)) + return Results.Unauthorized(); + + request.EnableBuffering(); + + var items = await db.SavedOutfits + .Where(i => i.OwnerAccountId == id) + .ToListAsync(); + + return Results.Json(items); + }); + + app.MapGet("/api/avatar/v2/gifts", async (HttpRequest request, AppDbContext db, JwtTokenService jwtService) => + { + try + { + var authHeader = request.Headers.Authorization.ToString(); + if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) + return Results.Unauthorized(); + + var token = authHeader.Substring("Bearer ".Length); + var accountId = jwtService.ValidateAndGetAccountId(token); + + if (string.IsNullOrEmpty(accountId) || !int.TryParse(accountId.AsSpan(), out var id)) + return Results.Unauthorized(); + + // Get all pending (unconsumed) gifts for this player + var pendingGifts = await db.ReceivedGifts + .Where(rg => rg.ReceiverAccountId == id && !rg.IsConsumed) + .ToListAsync(); + + return Results.Json(pendingGifts); + } + catch (Exception ex) + { + return Results.Problem($"Error retrieving gifts: {ex.Message}"); + } + }); + + app.MapGet("/api/gamerewards/v1/pending", async (HttpRequest request, AppDbContext db) => + { + // TODO ADD FUNCTIONALITY + return "[]"; + }); + + app.MapGet("/api/roomkeys/v1/mine", async (HttpRequest request, AppDbContext db) => + { + // TODO ADD FUNCTIONALITY + return "[]"; + }); + + app.MapPost("/api/CampusCard/v1/UpdateAndGetSubscription", async (HttpRequest request, AppDbContext db) => + { + return Results.Json(new { subscription = (object?)null, platformAccountSubscribedPlayerId = (object?)null }); + }); } } diff --git a/CannedNet/Services/Controllers/ImageController.cs b/CannedNet/Services/Controllers/ImageController.cs index d639236..7bed144 100644 --- a/CannedNet/Services/Controllers/ImageController.cs +++ b/CannedNet/Services/Controllers/ImageController.cs @@ -1,14 +1,26 @@ using System.Net.Mime; using CannedNet.Services.Infrastructure; using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; namespace CannedNet.Services.Controllers; public class ImageController { - private static readonly HttpClient HttpClient = new(); + private static readonly byte[] PlaceholderJpeg; + + static ImageController() + { + Signatures.Init(); + + using var image = new Image(64, 64); + image.Mutate(x => x.BackgroundColor(Color.FromRgb(32, 32, 32))); + using var ms = new MemoryStream(); + image.SaveAsJpeg(ms, new JpegEncoder { Quality = 50 }); + PlaceholderJpeg = ms.ToArray(); + } public WebApplicationBuilder Initialize(string[]? args = null) => ServiceExtensions.CreateRecNetBuilder(args); @@ -16,67 +28,84 @@ public class ImageController public void MapEndpoints(WebApplication app) { var imagesDir = Path.Combine("Images"); - Directory.CreateDirectory(imagesDir); - app.MapGet("/{imageName}", async ( - HttpContext context, - string imageName - ) => + app.MapGet("/{imageName}", async (HttpContext context, string imageName) => { - byte[] imageBytes; - var filePath = Path.Combine(imagesDir, imageName); + byte[] imageBytes; + string contentType; + if (File.Exists(filePath)) { imageBytes = await File.ReadAllBytesAsync(filePath); + var ext = Path.GetExtension(imageName).ToLowerInvariant(); + contentType = ext switch + { + ".jpg" or ".jpeg" => "image/jpeg", + ".gif" => "image/gif", + ".webp" => "image/webp", + ".bmp" => "image/bmp", + _ => "image/png" + }; } else { - var response = await HttpClient.GetAsync( - $"https://cdn.rec.net/img/{imageName}" - ); - - if (!response.IsSuccessStatusCode) - return Results.NotFound(); - - imageBytes = await response.Content.ReadAsByteArrayAsync(); + imageBytes = PlaceholderJpeg; + contentType = "image/jpeg"; } - int? width = null; - int? height = null; + var cropSquare = context.Request.Query["cropSquare"].FirstOrDefault(); + var widthStr = context.Request.Query["width"].FirstOrDefault(); + var heightStr = context.Request.Query["height"].FirstOrDefault(); - if (int.TryParse(context.Request.Query["width"], out var w)) - width = w; - - if (int.TryParse(context.Request.Query["height"], out var h)) - height = h; - - if (width == null && height == null) + if (string.IsNullOrEmpty(widthStr) && string.IsNullOrEmpty(heightStr) && string.IsNullOrEmpty(cropSquare)) { - return Results.File(imageBytes, MediaTypeNames.Image.Png); + SignImageResponse(context, ref imageBytes); + return Results.File(imageBytes, contentType); } using var image = Image.Load(imageBytes); - image.Mutate(x => x.Resize(new ResizeOptions + var resizeWidth = 0; + var resizeHeight = 0; + + if (!string.IsNullOrEmpty(cropSquare) && cropSquare != "0" && cropSquare != "false") { - Size = new Size( - width ?? 0, - height ?? 0 - ), - Mode = ResizeMode.Max - })); + var size = Math.Min(image.Width, image.Height); + var x = (image.Width - size) / 2; + var y = (image.Height - size) / 2; + image.Mutate(img => img.Crop(new Rectangle(x, y, size, size))); + } - await using var output = new MemoryStream(); + if (int.TryParse(widthStr, out var w)) + resizeWidth = w; - await image.SaveAsync(output, new PngEncoder()); + if (int.TryParse(heightStr, out var h)) + resizeHeight = h; - return Results.File( - output.ToArray(), - MediaTypeNames.Image.Png - ); + if (resizeWidth > 0 || resizeHeight > 0) + { + image.Mutate(x => x.Resize(resizeWidth, resizeHeight)); + } + + using var output = new MemoryStream(); + await image.SaveAsJpegAsync(output, new JpegEncoder { Quality = 85 }); + imageBytes = output.ToArray(); + SignImageResponse(context, ref imageBytes); + return Results.File(imageBytes, "image/jpeg"); }); } + + private static void SignImageResponse(HttpContext context, ref byte[] imageBytes) + { + if (context.Request.Query["sig"] != "p1") return; + + var signature = Signatures.Sign(imageBytes); + if (signature != null) + { + context.Response.Headers["Content-Signature"] = $"key-id=KEY:RSA:p1.rec.net; data={signature}"; + } + } } \ No newline at end of file diff --git a/CannedNet/Services/Controllers/MatchmakingController.cs b/CannedNet/Services/Controllers/MatchmakingController.cs index f8d2abe..811c560 100644 --- a/CannedNet/Services/Controllers/MatchmakingController.cs +++ b/CannedNet/Services/Controllers/MatchmakingController.cs @@ -231,7 +231,157 @@ public class MatchmakingController return Results.Json(response); }); - app.MapPost("/goto/none", (HttpRequest request) => + app.MapPost("/matchmake/{room}", async (HttpRequest request, string room, AppDbContext db) => + { + var authHeader = request.Headers.Authorization.ToString(); + + if (string.IsNullOrEmpty(authHeader) || !authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) + return Results.Unauthorized(); + + var token = authHeader.Substring("Bearer ".Length); + var accountId = jwtService.ValidateAndGetAccountId(token); + + if (string.IsNullOrEmpty(accountId)) + return Results.Unauthorized(); + + if (!int.TryParse(accountId.AsSpan(), out var id)) + return Results.Unauthorized(); + + request.EnableBuffering(); + request.Body.Position = 0; + var form = await request.ReadFormAsync(); + int joinMode = 0; + if (int.TryParse(form["JoinMode"].ToString(), out var mode)) + { + joinMode = mode; + } + request.Body.Position = 0; + + Room? roomData = null; + var roomLower = room.ToLower(); + + if (roomLower == "dorm") + { + roomData = await db.Rooms.FirstOrDefaultAsync(r => r.IsDorm && r.CreatorAccountId == id); + } + else if (int.TryParse(room, out var roomId)) + { + roomData = await db.Rooms.FirstOrDefaultAsync(r => r.RoomId == roomId); + } + + if (roomData == null) + { + roomData = await db.Rooms.FirstOrDefaultAsync(r => r.Name.ToLower() == roomLower); + } + + if (roomData == null) + { + return Results.NotFound("Room not found"); + } + + var subRoom = await db.SubRooms.FirstOrDefaultAsync(s => s.RoomId == roomData.RoomId); + + string location = subRoom?.UnitySceneId ?? ""; + int subRoomId = subRoom?.SubRoomId ?? 0; + int maxCapacity = subRoom?.MaxPlayers ?? 4; + + + RoomInstance? instanceToUse; + string photonRoomId; + + bool isPrivateInstance = joinMode == 2 || roomData.IsDorm; + + var existingInstance = await db.RoomInstances.FirstOrDefaultAsync(r => r.OwnerAccountId == id && r.roomId == roomData.RoomId); + + if (existingInstance != null) + { + photonRoomId = existingInstance.photonRoomId ?? Guid.NewGuid().ToString(); + existingInstance.roomInstanceId = existingInstance.Id; + existingInstance.roomId = roomData.RoomId; + existingInstance.subRoomId = subRoomId; + existingInstance.location = location; + existingInstance.dataBlob = ""; + existingInstance.photonRegionId = "us"; + existingInstance.photonRoomId = photonRoomId; + existingInstance.name = roomData.Name; + existingInstance.maxCapacity = maxCapacity; + existingInstance.isFull = false; + existingInstance.isPrivate = isPrivateInstance; + instanceToUse = existingInstance; + } + else + { + photonRoomId = Guid.NewGuid().ToString(); + + var oldInstances = await db.RoomInstances + .Where(r => r.OwnerAccountId == id && r.roomId != roomData.RoomId) + .ToListAsync(); + db.RoomInstances.RemoveRange(oldInstances); + + var publicInstance = await db.RoomInstances + .FirstOrDefaultAsync(r => r.roomId == roomData.RoomId && !r.isPrivate && !r.isFull); + + if (publicInstance != null) + { + photonRoomId = publicInstance.photonRoomId ?? Guid.NewGuid().ToString(); + } + + instanceToUse = new RoomInstance + { + OwnerAccountId = id, + roomInstanceId = 1, + roomId = roomData.RoomId, + subRoomId = subRoomId, + roomInstanceType = 2, + location = location, + dataBlob = "", + photonRegionId = "us", + photonRoomId = photonRoomId, + name = roomData.Name, + maxCapacity = maxCapacity, + isFull = false, + isPrivate = isPrivateInstance, + isInProgress = false, + EncryptVoiceChat = roomData.EncryptVoiceChat + }; + db.RoomInstances.Add(instanceToUse); + } + + await db.SaveChangesAsync(); + + if (instanceToUse.Id == 0) + { + instanceToUse = await db.RoomInstances.FirstOrDefaultAsync(r => r.OwnerAccountId == id && r.roomId == roomData.RoomId); + } + + var response = new + { + errorCode = 0, + roomInstance = new + { + roomInstanceId = instanceToUse?.Id ?? 1, + roomId = instanceToUse?.roomId ?? roomData.RoomId, + subRoomId = instanceToUse?.subRoomId ?? subRoomId, + roomInstanceType = instanceToUse?.roomInstanceType ?? 2, + location = instanceToUse?.location ?? location, + dataBlob = instanceToUse?.dataBlob ?? "", + eventId = instanceToUse?.eventId ?? 0, + clubId = instanceToUse?.clubId ?? 0, + roomCode = instanceToUse?.roomCode ?? "", + photonRegionId = instanceToUse?.photonRegionId ?? "us", + photonRoomId = instanceToUse?.photonRoomId ?? photonRoomId, + name = instanceToUse?.name ?? roomData.Name, + maxCapacity = instanceToUse?.maxCapacity ?? maxCapacity, + isFull = instanceToUse?.isFull ?? false, + isPrivate = isPrivateInstance, + isInProgress = instanceToUse?.isInProgress ?? false, + EncryptVoiceChat = instanceToUse?.EncryptVoiceChat ?? roomData.EncryptVoiceChat + } + }; + return Results.Json(response); + }); + + app.MapPost("/matchmake/none", (HttpRequest request) => { // dormroom location id : 76d98498-60a1-430c-ab76-b54a29b7a163 // offline dorm @@ -261,11 +411,6 @@ public class MatchmakingController }); }); - app.MapPost("/matchmake/none", () => - { - return Results.Json(new { errorCode = 0 }); - }); - app.MapPost("/player/heartbeat", async (HttpRequest request, AppDbContext db) => { var authHeader = request.Headers.Authorization.ToString(); diff --git a/CannedNet/Services/Controllers/RoomsController.cs b/CannedNet/Services/Controllers/RoomsController.cs index b6a14d9..5c9f07a 100644 --- a/CannedNet/Services/Controllers/RoomsController.cs +++ b/CannedNet/Services/Controllers/RoomsController.cs @@ -45,6 +45,13 @@ public class RoomsController return Results.Json(await BuildRoomResponse(result, db)); }); + + app.MapGet("/roomserver/rooms/createdby/me", async (HttpRequest request, AppDbContext db) => + { + // TODO ADD FUNCTIONALITY + var json = File.ReadAllText("JSON/ownedrooms.json"); + return Results.Content(json, "application/json"); + }); } private static async Task BuildRoomResponse(Room result, AppDbContext db) diff --git a/CannedNet/Services/Signatures.cs b/CannedNet/Services/Signatures.cs new file mode 100644 index 0000000..619ab00 --- /dev/null +++ b/CannedNet/Services/Signatures.cs @@ -0,0 +1,46 @@ +using System.Security.Cryptography; +using System.Text; + +namespace CannedNet.Services; + +public static class Signatures +{ + private static RSA? _rsa; + private static bool _initialized; + + public static void Init() + { + if (_initialized) return; + _initialized = true; + + try + { + var pemPath = Path.Combine("Data", "PrivateKey.pem"); + if (!File.Exists(pemPath)) + { + Console.WriteLine("sigs - creating new sig key"); + Directory.CreateDirectory("Data"); + using var newKey = RSA.Create(2048); + var pem = newKey.ExportPkcs8PrivateKeyPem(); + File.WriteAllText(pemPath, pem); + Console.WriteLine("sigs - key saved to " + pemPath); + } + + var pemContent = File.ReadAllText(pemPath); + _rsa = RSA.Create(); + _rsa.ImportFromPem(pemContent.ToCharArray()); + Console.WriteLine("sigs - key loaded"); + } + catch (Exception ex) + { + Console.WriteLine($"sigs - failed to load key: {ex.Message}"); + } + } + + public static string? Sign(byte[] data) + { + if (_rsa == null) return null; + var signatureBytes = _rsa.SignData(data, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1); + return Convert.ToBase64String(signatureBytes); + } +} \ No newline at end of file