mirror of
https://github.com/CannedNet/CannedNet.git
synced 2026-10-25 23:18:54 -07:00
some api work
This commit is contained in:
@@ -6,3 +6,4 @@ riderModule.iml
|
|||||||
/.idea
|
/.idea
|
||||||
/CannedNet.API/Migrations
|
/CannedNet.API/Migrations
|
||||||
CannedNet.sln.DotSettings.user
|
CannedNet.sln.DotSettings.user
|
||||||
|
CannedNet/Data/PrivateKey.pem
|
||||||
|
|||||||
@@ -22,6 +22,5 @@
|
|||||||
"Discovery": "https://api.lapis.codes",
|
"Discovery": "https://api.lapis.codes",
|
||||||
"PlayerSettings": "https://api.lapis.codes",
|
"PlayerSettings": "https://api.lapis.codes",
|
||||||
"Rendering": "https://api.lapis.codes",
|
"Rendering": "https://api.lapis.codes",
|
||||||
"Launcher": "https://launcher.lapis.codes",
|
"Launcher": "https://launcher.lapis.codes"
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,13 @@ public class APIController
|
|||||||
UseRudderStack = false
|
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) =>
|
app.MapPost("/api/gamesight/event", async (HttpRequest request) =>
|
||||||
{
|
{
|
||||||
string? eventType = null;
|
string? eventType = null;
|
||||||
@@ -418,31 +425,6 @@ public class APIController
|
|||||||
return Results.Ok(avatar);
|
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", () =>
|
app.MapGet("/api/PlayerReporting/v1/moderationBlockDetails", () =>
|
||||||
Results.Content("{\"ReportCategory\":0,\"Duration\":0,\"GameSessionId\":0,\"IsHostKick\":false,\"Message\":\"\",\"PlayerIdReporter\":null,\"IsBan\":false}", "application/json"));
|
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");
|
var json = File.ReadAllText("JSON/tempmyprogress.json");
|
||||||
return Results.Content(json, "application/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) =>
|
app.MapGet("/api/communityboard/v2/current", async (HttpRequest request, AppDbContext db) =>
|
||||||
{
|
{
|
||||||
var json = File.ReadAllText("JSON/communityboard.json");
|
var json = File.ReadAllText("JSON/communityboard.json");
|
||||||
@@ -618,10 +569,6 @@ public class APIController
|
|||||||
// TODO ADD FUNCTIONALITY
|
// TODO ADD FUNCTIONALITY
|
||||||
return Results.Content("{\"Created\":[],\"Responses\":[]}", "application/json");
|
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) =>
|
app.MapGet("/api/storefronts/v1/p2p/betaEnabled", async (HttpRequest request, AppDbContext db) =>
|
||||||
{
|
{
|
||||||
return "false";
|
return "false";
|
||||||
@@ -631,11 +578,6 @@ public class APIController
|
|||||||
var json = File.ReadAllText("JSON/announcements.json");
|
var json = File.ReadAllText("JSON/announcements.json");
|
||||||
return Results.Content(json, "application/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) =>
|
app.MapGet("/api/quickPlay/v1/getandclear", async (HttpRequest request, AppDbContext db) =>
|
||||||
{
|
{
|
||||||
// TODO ADD FUNCTIONALITY
|
// TODO ADD FUNCTIONALITY
|
||||||
@@ -666,98 +608,6 @@ public class APIController
|
|||||||
|
|
||||||
return Results.Json(bio);
|
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<string>();
|
|
||||||
|
|
||||||
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<object>();
|
|
||||||
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) =>
|
app.MapGet("/roomserver/rooms/bulk", async (HttpRequest request, AppDbContext db) =>
|
||||||
{
|
{
|
||||||
var idParam = request.Query["id"].FirstOrDefault();
|
var idParam = request.Query["id"].FirstOrDefault();
|
||||||
@@ -1068,13 +918,6 @@ public class APIController
|
|||||||
|
|
||||||
return Results.Json(response);
|
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) =>
|
app.MapGet("/roomserver/rooms/{id}", async (HttpRequest request, AppDbContext db, string id) =>
|
||||||
{
|
{
|
||||||
// this sucked to do
|
// this sucked to do
|
||||||
|
|||||||
@@ -94,5 +94,41 @@ public class AuthController
|
|||||||
// TODO: implement
|
// TODO: implement
|
||||||
return Results.Ok(RecNetResult.Ok());
|
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<string>();
|
||||||
|
|
||||||
|
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<object>();
|
||||||
|
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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ public class EconController
|
|||||||
{
|
{
|
||||||
var jwtService = app.Services.GetRequiredService<JwtTokenService>();
|
var jwtService = app.Services.GetRequiredService<JwtTokenService>();
|
||||||
var notificationService = app.Services.GetRequiredService<NotificationService>();
|
var notificationService = app.Services.GetRequiredService<NotificationService>();
|
||||||
|
var storefrontService = app.Services.GetRequiredService<StorefrontFillService>();
|
||||||
|
|
||||||
app.MapGet("/api/avatar/v1/defaultunlocked", () =>
|
app.MapGet("/api/avatar/v1/defaultunlocked", () =>
|
||||||
{
|
{
|
||||||
@@ -362,5 +363,133 @@ public class EconController
|
|||||||
|
|
||||||
return Results.Json(balance);
|
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 });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,26 @@
|
|||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using CannedNet.Services.Infrastructure;
|
using CannedNet.Services.Infrastructure;
|
||||||
using SixLabors.ImageSharp;
|
using SixLabors.ImageSharp;
|
||||||
using SixLabors.ImageSharp.Formats.Png;
|
using SixLabors.ImageSharp.Formats.Jpeg;
|
||||||
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
using SixLabors.ImageSharp.Processing;
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
|
||||||
namespace CannedNet.Services.Controllers;
|
namespace CannedNet.Services.Controllers;
|
||||||
|
|
||||||
public class ImageController
|
public class ImageController
|
||||||
{
|
{
|
||||||
private static readonly HttpClient HttpClient = new();
|
private static readonly byte[] PlaceholderJpeg;
|
||||||
|
|
||||||
|
static ImageController()
|
||||||
|
{
|
||||||
|
Signatures.Init();
|
||||||
|
|
||||||
|
using var image = new Image<Rgba32>(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)
|
public WebApplicationBuilder Initialize(string[]? args = null)
|
||||||
=> ServiceExtensions.CreateRecNetBuilder(args);
|
=> ServiceExtensions.CreateRecNetBuilder(args);
|
||||||
@@ -16,67 +28,84 @@ public class ImageController
|
|||||||
public void MapEndpoints(WebApplication app)
|
public void MapEndpoints(WebApplication app)
|
||||||
{
|
{
|
||||||
var imagesDir = Path.Combine("Images");
|
var imagesDir = Path.Combine("Images");
|
||||||
|
|
||||||
Directory.CreateDirectory(imagesDir);
|
Directory.CreateDirectory(imagesDir);
|
||||||
|
|
||||||
app.MapGet("/{imageName}", async (
|
app.MapGet("/{imageName}", async (HttpContext context, string imageName) =>
|
||||||
HttpContext context,
|
|
||||||
string imageName
|
|
||||||
) =>
|
|
||||||
{
|
{
|
||||||
byte[] imageBytes;
|
|
||||||
|
|
||||||
var filePath = Path.Combine(imagesDir, imageName);
|
var filePath = Path.Combine(imagesDir, imageName);
|
||||||
|
|
||||||
|
byte[] imageBytes;
|
||||||
|
string contentType;
|
||||||
|
|
||||||
if (File.Exists(filePath))
|
if (File.Exists(filePath))
|
||||||
{
|
{
|
||||||
imageBytes = await File.ReadAllBytesAsync(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
|
else
|
||||||
{
|
{
|
||||||
var response = await HttpClient.GetAsync(
|
imageBytes = PlaceholderJpeg;
|
||||||
$"https://cdn.rec.net/img/{imageName}"
|
contentType = "image/jpeg";
|
||||||
);
|
|
||||||
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
return Results.NotFound();
|
|
||||||
|
|
||||||
imageBytes = await response.Content.ReadAsByteArrayAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int? width = null;
|
var cropSquare = context.Request.Query["cropSquare"].FirstOrDefault();
|
||||||
int? height = null;
|
var widthStr = context.Request.Query["width"].FirstOrDefault();
|
||||||
|
var heightStr = context.Request.Query["height"].FirstOrDefault();
|
||||||
|
|
||||||
if (int.TryParse(context.Request.Query["width"], out var w))
|
if (string.IsNullOrEmpty(widthStr) && string.IsNullOrEmpty(heightStr) && string.IsNullOrEmpty(cropSquare))
|
||||||
width = w;
|
|
||||||
|
|
||||||
if (int.TryParse(context.Request.Query["height"], out var h))
|
|
||||||
height = h;
|
|
||||||
|
|
||||||
if (width == null && height == null)
|
|
||||||
{
|
{
|
||||||
return Results.File(imageBytes, MediaTypeNames.Image.Png);
|
SignImageResponse(context, ref imageBytes);
|
||||||
|
return Results.File(imageBytes, contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
using var image = Image.Load(imageBytes);
|
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(
|
var size = Math.Min(image.Width, image.Height);
|
||||||
width ?? 0,
|
var x = (image.Width - size) / 2;
|
||||||
height ?? 0
|
var y = (image.Height - size) / 2;
|
||||||
),
|
image.Mutate(img => img.Crop(new Rectangle(x, y, size, size)));
|
||||||
Mode = ResizeMode.Max
|
}
|
||||||
}));
|
|
||||||
|
|
||||||
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(
|
if (resizeWidth > 0 || resizeHeight > 0)
|
||||||
output.ToArray(),
|
{
|
||||||
MediaTypeNames.Image.Png
|
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}";
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -231,7 +231,157 @@ public class MatchmakingController
|
|||||||
return Results.Json(response);
|
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
|
// dormroom location id : 76d98498-60a1-430c-ab76-b54a29b7a163
|
||||||
// offline dorm
|
// 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) =>
|
app.MapPost("/player/heartbeat", async (HttpRequest request, AppDbContext db) =>
|
||||||
{
|
{
|
||||||
var authHeader = request.Headers.Authorization.ToString();
|
var authHeader = request.Headers.Authorization.ToString();
|
||||||
|
|||||||
@@ -45,6 +45,13 @@ public class RoomsController
|
|||||||
|
|
||||||
return Results.Json(await BuildRoomResponse(result, db));
|
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<object> BuildRoomResponse(Room result, AppDbContext db)
|
private static async Task<object> BuildRoomResponse(Room result, AppDbContext db)
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user