Refactor deserialization and authentication (#550)

* Refactor deserialization and more

* Refactor authentication flow

* Fix unit tests

* Make deserialization better
This commit is contained in:
Josh 2022-11-10 21:14:16 -06:00 committed by GitHub
commit b3a00da554
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
48 changed files with 575 additions and 589 deletions

View file

@ -1,19 +1,20 @@
#nullable enable
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.Levels.Categories;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Authorize]
[Route("LITTLEBIGPLANETPS3_XML/")]
[Produces("text/xml")]
public class CollectionController : ControllerBase
@ -28,9 +29,6 @@ public class CollectionController : ControllerBase
[HttpGet("playlists/{playlistId:int}/slots")]
public async Task<IActionResult> GetPlaylistSlots(int playlistId)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
Playlist? targetPlaylist = await this.database.Playlists.FirstOrDefaultAsync(p => p.PlaylistId == playlistId);
if (targetPlaylist == null) return this.BadRequest();
@ -50,8 +48,7 @@ public class CollectionController : ControllerBase
[HttpPost("playlists/{playlistId:int}/order_slots")]
public async Task<IActionResult> UpdatePlaylist(int playlistId, int slotId)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
Playlist? targetPlaylist = await this.database.Playlists.FirstOrDefaultAsync(p => p.PlaylistId == playlistId);
if (targetPlaylist == null) return this.BadRequest();
@ -66,7 +63,7 @@ public class CollectionController : ControllerBase
return this.Ok(this.GetUserPlaylists(token.UserId));
}
Playlist? newPlaylist = await this.getPlaylistFromBody();
Playlist? newPlaylist = await this.DeserializeBody<Playlist>("playlist", "levels");
if (newPlaylist == null) return this.BadRequest();
@ -116,14 +113,13 @@ public class CollectionController : ControllerBase
[HttpPost("playlists")]
public async Task<IActionResult> CreatePlaylist()
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
int playlistCount = await this.database.Playlists.CountAsync(p => p.CreatorId == token.UserId);
if (playlistCount > ServerConfiguration.Instance.UserGeneratedContentLimits.ListsQuota) return this.BadRequest();
Playlist? playlist = await this.getPlaylistFromBody();
Playlist? playlist = await this.DeserializeBody<Playlist>("playlist");
if (playlist == null) return this.BadRequest();
@ -139,10 +135,7 @@ public class CollectionController : ControllerBase
[HttpGet("user/{username}/playlists")]
public async Task<IActionResult> GetUserPlaylists(string username)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
int targetUserId = await this.database.Users.Where(u => u.Username == username).Select(u => u.UserId).FirstOrDefaultAsync();
int targetUserId = await this.database.UserIdFromUsername(username);
if (targetUserId == 0) return this.BadRequest();
return this.Ok(this.GetUserPlaylists(targetUserId));
@ -152,8 +145,9 @@ public class CollectionController : ControllerBase
[HttpGet("genres")]
public async Task<IActionResult> GenresAndSearches()
{
User? user = await this.database.UserFromGameRequest(this.Request);
if (user == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
User? user = await this.database.UserFromGameToken(token);
string categoriesSerialized = CategoryHelper.Categories.Aggregate
(
@ -196,13 +190,9 @@ public class CollectionController : ControllerBase
[HttpGet("searches/{endpointName}")]
public async Task<IActionResult> GetCategorySlots(string endpointName, [FromQuery] int pageStart, [FromQuery] int pageSize)
{
(User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request);
GameToken token = this.GetToken();
if (userAndToken == null) return this.StatusCode(403, "");
// ReSharper disable once PossibleInvalidOperationException
User user = userAndToken.Value.Item1;
GameToken gameToken = userAndToken.Value.Item2;
User? user = await this.database.UserFromGameToken(token);
Category? category = CategoryHelper.Categories.FirstOrDefault(c => c.Endpoint == endpointName);
if (category == null) return this.NotFound();
@ -223,7 +213,7 @@ public class CollectionController : ControllerBase
totalSlots = category.GetTotalSlots(this.database);
}
string slotsSerialized = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize(gameToken.GameVersion));
string slotsSerialized = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize(token.GameVersion));
return this.Ok
(
@ -243,19 +233,4 @@ public class CollectionController : ControllerBase
)
);
}
private async Task<Playlist?> getPlaylistFromBody()
{
this.Request.Body.Position = 0;
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
string rootElement = bodyString.StartsWith("<playlist>") ? "playlist" : "levels";
XmlSerializer serializer = new(typeof(Playlist), new XmlRootAttribute(rootElement));
Playlist? playlist = (Playlist?)serializer.Deserialize(new StringReader(bodyString));
SanitizationHelper.SanitizeStringsInClass(playlist);
return playlist;
}
}

View file

@ -1,12 +1,15 @@
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Authorize]
[Route("LITTLEBIGPLANETPS3_XML")]
[Produces("text/plain")]
public class LevelTagsController : ControllerBase
@ -34,15 +37,14 @@ public class LevelTagsController : ControllerBase
}
[HttpPost("tag/{slotType}/{id:int}")]
public async Task<IActionResult> PostTag([FromForm] string t, [FromRoute] string slotType, [FromRoute] int id)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
public async Task<IActionResult> PostTag([FromForm(Name = "t")] string tagName, [FromRoute] string slotType, [FromRoute] int id)
{
GameToken token = this.GetToken();
Slot? slot = await this.database.Slots.Where(s => s.SlotId == id).FirstOrDefaultAsync();
if (slot == null) return this.BadRequest();
if (!LabelHelper.IsValidTag(t)) return this.BadRequest();
if (!LabelHelper.IsValidTag(tagName)) return this.BadRequest();
if (token.UserId == slot.CreatorId) return this.BadRequest();
@ -53,7 +55,7 @@ public class LevelTagsController : ControllerBase
RatedLevel? rating = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.UserId == token.UserId && r.SlotId == slot.SlotId);
if (rating == null) return this.BadRequest();
rating.TagLBP1 = t;
rating.TagLBP1 = tagName;
await this.database.SaveChangesAsync();

View file

@ -5,12 +5,14 @@ using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Authorize]
[Route("LITTLEBIGPLANETPS3_XML/")]
[Produces("text/xml")]
public class ListController : ControllerBase
@ -37,8 +39,7 @@ public class ListController : ControllerBase
[FromQuery] string? dateFilterType = null
)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -64,8 +65,7 @@ public class ListController : ControllerBase
[HttpPost("lolcatftw/add/user/{id:int}")]
public async Task<IActionResult> AddQueuedLevel(int id)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
if (slot == null) return this.NotFound();
@ -78,8 +78,7 @@ public class ListController : ControllerBase
[HttpPost("lolcatftw/remove/user/{id:int}")]
public async Task<IActionResult> RemoveQueuedLevel(int id)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == id);
if (slot == null) return this.NotFound();
@ -92,8 +91,7 @@ public class ListController : ControllerBase
[HttpPost("lolcatftw/clear")]
public async Task<IActionResult> ClearQueuedLevels()
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
this.database.QueuedLevels.RemoveRange(this.database.QueuedLevels.Where(q => q.UserId == token.UserId));
@ -118,8 +116,7 @@ public class ListController : ControllerBase
[FromQuery] string? dateFilterType = null
)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -150,8 +147,7 @@ public class ListController : ControllerBase
[HttpPost("favourite/slot/{slotType}/{id:int}")]
public async Task<IActionResult> AddFavouriteSlot(string slotType, int id)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (SlotHelper.IsTypeInvalid(slotType)) return this.BadRequest();
@ -174,8 +170,7 @@ public class ListController : ControllerBase
[HttpPost("unfavourite/slot/{slotType}/{id:int}")]
public async Task<IActionResult> RemoveFavouriteSlot(string slotType, int id)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (SlotHelper.IsTypeInvalid(slotType)) return this.BadRequest();
@ -202,12 +197,9 @@ public class ListController : ControllerBase
[HttpGet("favouritePlaylists/{username}")]
public async Task<IActionResult> GetFavouritePlaylists(string username, [FromQuery] int pageStart, [FromQuery] int pageSize)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
if (pageSize <= 0) return this.BadRequest();
int targetUserId = await this.database.Users.Where(u => u.Username == username).Select(u => u.UserId).FirstOrDefaultAsync();
int targetUserId = await this.database.UserIdFromUsername(username);
if (targetUserId == 0) return this.StatusCode(403, "");
IEnumerable<Playlist> heartedPlaylists = this.database.HeartedPlaylists.Where(p => p.UserId == targetUserId)
@ -228,8 +220,7 @@ public class ListController : ControllerBase
[HttpPost("favourite/playlist/{playlistId:int}")]
public async Task<IActionResult> AddFavouritePlaylist(int playlistId)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
Playlist? playlist = await this.database.Playlists.FirstOrDefaultAsync(s => s.PlaylistId == playlistId);
if (playlist == null) return this.NotFound();
@ -242,8 +233,7 @@ public class ListController : ControllerBase
[HttpPost("unfavourite/playlist/{playlistId:int}")]
public async Task<IActionResult> RemoveFavouritePlaylist(int playlistId)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
Playlist? playlist = await this.database.Playlists.FirstOrDefaultAsync(s => s.PlaylistId == playlistId);
if (playlist == null) return this.NotFound();
@ -262,8 +252,7 @@ public class ListController : ControllerBase
[HttpGet("favouriteUsers/{username}")]
public async Task<IActionResult> GetFavouriteUsers(string username, [FromQuery] int pageSize, [FromQuery] int pageStart)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
User? targetUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
if (targetUser == null) return this.StatusCode(403, "");
@ -295,8 +284,7 @@ public class ListController : ControllerBase
[HttpPost("favourite/user/{username}")]
public async Task<IActionResult> AddFavouriteUser(string username)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
if (heartedUser == null) return this.NotFound();
@ -309,8 +297,7 @@ public class ListController : ControllerBase
[HttpPost("unfavourite/user/{username}")]
public async Task<IActionResult> RemoveFavouriteUser(string username)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == username);
if (heartedUser == null) return this.NotFound();

View file

@ -1,6 +1,6 @@
#nullable enable
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Configuration;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Files;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Levels;
@ -8,12 +8,14 @@ using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Authorize]
[Route("LITTLEBIGPLANETPS3_XML/")]
[Produces("text/xml")]
public class PublishController : ControllerBase
@ -31,15 +33,12 @@ public class PublishController : ControllerBase
[HttpPost("startPublish")]
public async Task<IActionResult> StartPublish()
{
(User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request);
GameToken token = this.GetToken();
if (userAndToken == null) return this.StatusCode(403, "");
User? user = await this.database.UserFromGameToken(token);
if (user == null) return this.StatusCode(403, "");
// ReSharper disable once PossibleInvalidOperationException
User user = userAndToken.Value.Item1;
GameToken gameToken = userAndToken.Value.Item2;
Slot? slot = await this.getSlotFromBody();
Slot? slot = await this.DeserializeBody<Slot>();
if (slot == null)
{
Logger.Warn("Rejecting level upload, slot is null", LogArea.Publish);
@ -69,7 +68,7 @@ public class PublishController : ControllerBase
return this.BadRequest();
}
}
else if (user.GetUsedSlotsForGame(gameToken.GameVersion) > user.EntitledSlots)
else if (user.GetUsedSlotsForGame(token.GameVersion) > user.EntitledSlots)
{
return this.StatusCode(403, "");
}
@ -89,14 +88,12 @@ public class PublishController : ControllerBase
[HttpPost("publish")]
public async Task<IActionResult> Publish([FromQuery] string? game)
{
(User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request);
GameToken token = this.GetToken();
if (userAndToken == null) return this.StatusCode(403, "");
User? user = await this.database.UserFromGameToken(token);
if (user == null) return this.StatusCode(403, "");
// ReSharper disable once PossibleInvalidOperationException
User user = userAndToken.Value.Item1;
GameToken gameToken = userAndToken.Value.Item2;
Slot? slot = await this.getSlotFromBody();
Slot? slot = await this.DeserializeBody<Slot>();
if (slot == null)
{
@ -156,7 +153,7 @@ public class PublishController : ControllerBase
GameVersion slotVersion = FileHelper.ParseLevelVersion(rootLevel);
slot.GameVersion = slotVersion;
if (slotVersion == GameVersion.Unknown) slot.GameVersion = gameToken.GameVersion;
if (slotVersion == GameVersion.Unknown) slot.GameVersion = token.GameVersion;
slot.AuthorLabels = LabelHelper.RemoveInvalidLabels(slot.AuthorLabels);
@ -185,7 +182,7 @@ public class PublishController : ControllerBase
if (intendedVersion != GameVersion.Unknown && intendedVersion != slotVersion)
{
// Delete the useless rootLevel that lbp3 just uploaded
if(slotVersion == GameVersion.LittleBigPlanet3)
if (slotVersion == GameVersion.LittleBigPlanet3)
FileHelper.DeleteResource(slot.RootLevel);
slot.GameVersion = oldSlot.GameVersion;
@ -230,7 +227,7 @@ public class PublishController : ControllerBase
this.database.Entry(oldSlot).CurrentValues.SetValues(slot);
await this.database.SaveChangesAsync();
return this.Ok(oldSlot.Serialize(gameToken.GameVersion));
return this.Ok(oldSlot.Serialize(token.GameVersion));
}
if (user.GetUsedSlotsForGame(slotVersion) > user.EntitledSlots)
@ -269,14 +266,13 @@ public class PublishController : ControllerBase
Logger.Success($"Successfully published level {slot.Name} (id: {slot.SlotId}) by {user.Username} (id: {user.UserId})", LogArea.Publish);
return this.Ok(slot.Serialize(gameToken.GameVersion));
return this.Ok(slot.Serialize(token.GameVersion));
}
[HttpPost("unpublish/{id:int}")]
public async Task<IActionResult> Unpublish(int id)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
Slot? slot = await this.database.Slots.Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == id);
if (slot == null) return this.NotFound();
@ -305,17 +301,4 @@ public class PublishController : ControllerBase
_ => GameVersion.Unknown,
};
}
private async Task<Slot?> getSlotFromBody()
{
this.Request.Body.Position = 0;
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
XmlSerializer serializer = new(typeof(Slot));
Slot? slot = (Slot?)serializer.Deserialize(new StringReader(bodyString));
SanitizationHelper.SanitizeStringsInClass(slot);
return slot;
}
}

View file

@ -1,5 +1,4 @@
#nullable enable
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Administration;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Helpers;
@ -7,12 +6,14 @@ using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Reviews;
using LBPUnion.ProjectLighthouse.Serialization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Authorize]
[Route("LITTLEBIGPLANETPS3_XML/")]
[Produces("text/xml")]
public class ReviewController : ControllerBase
@ -28,8 +29,7 @@ public class ReviewController : ControllerBase
[HttpPost("rate/user/{slotId:int}")]
public async Task<IActionResult> Rate(int slotId, [FromQuery] int rating)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
Slot? slot = await this.database.Slots.Include(s => s.Creator).Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == slotId);
if (slot == null) return this.StatusCode(403, "");
@ -58,8 +58,7 @@ public class ReviewController : ControllerBase
[HttpPost("dpadrate/user/{slotId:int}")]
public async Task<IActionResult> DPadRate(int slotId, [FromQuery] int rating)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
Slot? slot = await this.database.Slots.Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == slotId);
if (slot == null) return this.StatusCode(403, "");
@ -90,10 +89,9 @@ public class ReviewController : ControllerBase
[HttpPost("postReview/user/{slotId:int}")]
public async Task<IActionResult> PostReview(int slotId)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
Review? newReview = await this.getReviewFromBody();
Review? newReview = await this.DeserializeBody<Review>();
if (newReview == null) return this.BadRequest();
if (newReview.Text.Length > 512) return this.BadRequest();
@ -143,8 +141,7 @@ public class ReviewController : ControllerBase
[HttpGet("reviewsFor/user/{slotId:int}")]
public async Task<IActionResult> ReviewsFor(int slotId, [FromQuery] int pageStart = 1, [FromQuery] int pageSize = 10)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -195,14 +192,13 @@ public class ReviewController : ControllerBase
[HttpGet("reviewsBy/{username}")]
public async Task<IActionResult> ReviewsBy(string username, [FromQuery] int pageStart = 1, [FromQuery] int pageSize = 10)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
GameVersion gameVersion = token.GameVersion;
int targetUserId = await this.database.Users.Where(u => u.Username == username).Select(u => u.UserId).FirstOrDefaultAsync();
int targetUserId = await this.database.UserIdFromUsername(username);
if (targetUserId == 0) return this.BadRequest();
@ -249,10 +245,9 @@ public class ReviewController : ControllerBase
[HttpPost("rateReview/user/{slotId:int}/{username}")]
public async Task<IActionResult> RateReview(int slotId, string username, [FromQuery] int rating = 0)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
int reviewerId = await this.database.Users.Where(u => u.Username == username).Select(u => u.UserId).FirstOrDefaultAsync();
int reviewerId = await this.database.UserIdFromUsername(username);
if (reviewerId == 0) return this.StatusCode(400, "");
Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == reviewerId);
@ -303,15 +298,14 @@ public class ReviewController : ControllerBase
[HttpPost("deleteReview/user/{slotId:int}/{username}")]
public async Task<IActionResult> DeleteReview(int slotId, string username)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
int creatorId = await this.database.Slots.Where(s => s.SlotId == slotId).Select(s => s.CreatorId).FirstOrDefaultAsync();
if (creatorId == 0) return this.StatusCode(400, "");
if (token.UserId != creatorId) return this.StatusCode(403, "");
int reviewerId = await this.database.Users.Where(u => u.Username == username).Select(u => u.UserId).FirstOrDefaultAsync();
int reviewerId = await this.database.UserIdFromUsername(username);
if (reviewerId == 0) return this.StatusCode(400, "");
Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == slotId && r.ReviewerId == reviewerId);
@ -323,15 +317,4 @@ public class ReviewController : ControllerBase
await this.database.SaveChangesAsync();
return this.Ok();
}
private async Task<Review?> getReviewFromBody()
{
this.Request.Body.Position = 0;
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
XmlSerializer serializer = new(typeof(Review));
Review? review = (Review?)serializer.Deserialize(new StringReader(bodyString));
SanitizationHelper.SanitizeStringsInClass(review);
return review;
}
}

View file

@ -1,6 +1,7 @@
#nullable enable
using System.Diagnostics.CodeAnalysis;
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.Logging;
@ -30,8 +31,7 @@ public class ScoreController : ControllerBase
[HttpPost("scoreboard/{slotType}/{id:int}/{childId:int}")]
public async Task<IActionResult> SubmitScore(string slotType, int id, int childId, [FromQuery] bool lbp1 = false, [FromQuery] bool lbp2 = false, [FromQuery] bool lbp3 = false)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
string username = await this.database.UsernameFromGameToken(token);
@ -41,11 +41,7 @@ public class ScoreController : ControllerBase
return this.BadRequest();
}
this.Request.Body.Position = 0;
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
XmlSerializer serializer = new(typeof(Score));
Score? score = (Score?)serializer.Deserialize(new StringReader(bodyString));
Score? score = await this.DeserializeBody<Score>();
if (score == null)
{
Logger.Warn($"Rejecting score upload, score is null (slotType={slotType}, slotId={id}, user={username})", LogArea.Score);
@ -157,8 +153,7 @@ public class ScoreController : ControllerBase
[HttpGet("friendscores/{slotType}/{slotId:int}/{childId:int}/{type:int}")]
public async Task<IActionResult> FriendScores(string slotType, int slotId, int? childId, int type, [FromQuery] int pageStart = -1, [FromQuery] int pageSize = 5)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -189,8 +184,7 @@ public class ScoreController : ControllerBase
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
public async Task<IActionResult> TopScores(string slotType, int slotId, int? childId, int type, [FromQuery] int pageStart = -1, [FromQuery] int pageSize = 5)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();

View file

@ -3,12 +3,14 @@ using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.Serialization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Authorize]
[Route("LITTLEBIGPLANETPS3_XML/slots")]
[Produces("text/xml")]
public class SearchController : ControllerBase
@ -31,8 +33,7 @@ public class SearchController : ControllerBase
string? keyName = "slots"
)
{
GameToken? gameToken = await this.database.GameTokenFromRequest(this.Request);
if (gameToken == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -42,7 +43,7 @@ public class SearchController : ControllerBase
string[] keywords = query.Split(" ");
IQueryable<Slot> dbQuery = this.database.Slots.ByGameVersion(gameToken.GameVersion, false, true)
IQueryable<Slot> dbQuery = this.database.Slots.ByGameVersion(token.GameVersion, false, true)
.Where(s => s.Type == SlotType.User)
.OrderBy(s => !s.TeamPick)
.ThenByDescending(s => s.FirstUploaded)
@ -60,7 +61,7 @@ public class SearchController : ControllerBase
List<Slot> slots = await dbQuery.Skip(Math.Max(0, pageStart - 1)).Take(Math.Min(pageSize, 30)).ToListAsync();
string response = slots.Aggregate("", (current, slot) => current + slot.Serialize(gameToken.GameVersion));
string response = slots.Aggregate("", (current, slot) => current + slot.Serialize(token.GameVersion));
return this.Ok(LbpSerializer.TaggedStringElement(keyName, response, "total", dbQuery.Count()));
}

View file

@ -8,12 +8,14 @@ using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.PlayerData.Reviews;
using LBPUnion.ProjectLighthouse.Serialization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers.Slots;
[ApiController]
[Authorize]
[Route("LITTLEBIGPLANETPS3_XML/")]
[Produces("text/xml")]
public class SlotsController : ControllerBase
@ -38,38 +40,36 @@ public class SlotsController : ControllerBase
});
[HttpGet("slots/by")]
public async Task<IActionResult> SlotsBy([FromQuery] string u, [FromQuery] int pageStart, [FromQuery] int pageSize)
public async Task<IActionResult> SlotsBy([FromQuery(Name="u")] string username, [FromQuery] int pageStart, [FromQuery] int pageSize)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
GameVersion gameVersion = token.GameVersion;
User? targetUser = await this.database.Users.Where(dbUser => dbUser.Username == u).FirstOrDefaultAsync();
if (targetUser == null) return this.NotFound();
int targetUserId = await this.database.UserIdFromUsername(username);
if (targetUserId == 0) return this.NotFound();
int usedSlots = this.database.Slots.Count(s => s.CreatorId == targetUserId);
string response = Enumerable.Aggregate
(
this.database.Slots.ByGameVersion(gameVersion, token.UserId == targetUser.UserId, true)
.Where(s => s.CreatorId == targetUser.UserId)
this.database.Slots.Where(s => s.CreatorId == targetUserId)
.ByGameVersion(gameVersion, token.UserId == targetUserId, true)
.Skip(Math.Max(0, pageStart - 1))
.Take(Math.Min(pageSize, targetUser.UsedSlots)),
.Take(Math.Min(pageSize, usedSlots)),
string.Empty,
(current, slot) => current + slot.Serialize(token.GameVersion)
);
int start = pageStart + Math.Min(pageSize, targetUser.UsedSlots);
int total = await this.database.Slots.CountAsync(s => s.CreatorId == targetUser.UserId);
int start = pageStart + Math.Min(pageSize, usedSlots);
int total = await this.database.Slots.CountAsync(s => s.CreatorId == targetUserId);
return this.Ok(generateSlotsResponse(response, start, total));
}
[HttpGet("slotList")]
public async Task<IActionResult> GetSlotListAlt([FromQuery] int[] s)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
List<string?> serializedSlots = new();
foreach (int slotId in s)
{
@ -93,9 +93,6 @@ public class SlotsController : ControllerBase
[HttpGet("slots/developer")]
public async Task<IActionResult> StoryPlayers()
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
List<int> activeSlotIds = RoomHelper.Rooms.Where(r => r.Slot.SlotType == SlotType.Developer).Select(r => r.Slot.SlotId).ToList();
List<string> serializedSlots = new();
@ -115,9 +112,6 @@ public class SlotsController : ControllerBase
[HttpGet("s/developer/{id:int}")]
public async Task<IActionResult> SDev(int id)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
int slotId = await SlotHelper.GetPlaceholderSlotId(this.database, id, SlotType.Developer);
Slot slot = await this.database.Slots.FirstAsync(s => s.SlotId == slotId);
@ -127,8 +121,7 @@ public class SlotsController : ControllerBase
[HttpGet("s/user/{id:int}")]
public async Task<IActionResult> SUser(int id)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
GameVersion gameVersion = token.GameVersion;
@ -168,8 +161,7 @@ public class SlotsController : ControllerBase
[HttpGet("slots")]
public async Task<IActionResult> NewestSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -189,8 +181,7 @@ public class SlotsController : ControllerBase
[HttpGet("slots/like/{slotType}/{slotId:int}")]
public async Task<IActionResult> SimilarSlots([FromRoute] string slotType, [FromRoute] int slotId, [FromQuery] int pageStart, [FromQuery] int pageSize)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -225,8 +216,7 @@ public class SlotsController : ControllerBase
[HttpGet("slots/highestRated")]
public async Task<IActionResult> HighestRatedSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -248,8 +238,7 @@ public class SlotsController : ControllerBase
[HttpGet("slots/tag")]
public async Task<IActionResult> SimilarSlots([FromQuery] string tag, [FromQuery] int pageStart, [FromQuery] int pageSize)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -260,8 +249,8 @@ public class SlotsController : ControllerBase
.Select(s => s.SlotId)
.ToListAsync();
IQueryable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion, false, true)
.Where(s => slotIdsWithTag.Contains(s.SlotId))
IQueryable<Slot> slots = this.database.Slots.Where(s => slotIdsWithTag.Contains(s.SlotId))
.ByGameVersion(gameVersion, false, true)
.OrderByDescending(s => s.PlaysLBP1)
.Skip(Math.Max(0, pageStart - 1))
.Take(Math.Min(pageSize, 30));
@ -276,15 +265,14 @@ public class SlotsController : ControllerBase
[HttpGet("slots/mmpicks")]
public async Task<IActionResult> TeamPickedSlots([FromQuery] int pageStart, [FromQuery] int pageSize)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
GameVersion gameVersion = token.GameVersion;
IQueryable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion, false, true)
.Where(s => s.TeamPick)
IQueryable<Slot> slots = this.database.Slots.Where(s => s.TeamPick)
.ByGameVersion(gameVersion, false, true)
.OrderByDescending(s => s.LastUpdated)
.Skip(Math.Max(0, pageStart - 1))
.Take(Math.Min(pageSize, 30));
@ -298,8 +286,7 @@ public class SlotsController : ControllerBase
[HttpGet("slots/lbp2luckydip")]
public async Task<IActionResult> LuckyDipSlots([FromQuery] int pageStart, [FromQuery] int pageSize, [FromQuery] int seed)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -325,8 +312,7 @@ public class SlotsController : ControllerBase
[FromQuery] string? dateFilterType = null
)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -357,8 +343,7 @@ public class SlotsController : ControllerBase
[FromQuery] string? dateFilterType = null
)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -403,8 +388,7 @@ public class SlotsController : ControllerBase
[FromQuery] string? dateFilterType = null
)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -435,8 +419,7 @@ public class SlotsController : ControllerBase
[FromQuery] bool? move = null
)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (pageSize <= 0) return this.BadRequest();
@ -445,7 +428,7 @@ public class SlotsController : ControllerBase
foreach (Room room in RoomHelper.Rooms)
{
// TODO: support developer slotTypes?
if(room.Slot.SlotType != SlotType.User) continue;
if (room.Slot.SlotType != SlotType.User) continue;
if (!playersBySlotId.TryGetValue(room.Slot.SlotId, out int playerCount))
playersBySlotId.Add(room.Slot.SlotId, 0);
@ -468,7 +451,7 @@ public class SlotsController : ControllerBase
{
Slot? slot = await this.database.Slots.ByGameVersion(token.GameVersion, false, true)
.FirstOrDefaultAsync(s => s.SlotId == slotId);
if(slot == null) continue; // shouldn't happen ever unless the room is borked
if (slot == null) continue; // shouldn't happen ever unless the room is borked
slots.Add(slot);
}