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
parent 505b5eb03b
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,17 +1,19 @@
#nullable enable
using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Extensions;
using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Levels;
using LBPUnion.ProjectLighthouse.PlayerData;
using LBPUnion.ProjectLighthouse.PlayerData.Profiles;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace LBPUnion.ProjectLighthouse.Servers.GameServer.Controllers;
[ApiController]
[Authorize]
[Route("LITTLEBIGPLANETPS3_XML/")]
[Produces("text/xml")]
public class CommentController : ControllerBase
@ -26,10 +28,10 @@ public class CommentController : ControllerBase
[HttpPost("rateComment/{slotType}/{slotId:int}")]
public async Task<IActionResult> RateComment([FromQuery] int commentId, [FromQuery] int rating, string? username, string? slotType, int slotId)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if (username == null && (SlotHelper.IsTypeInvalid(slotType) || slotId == 0)) return this.BadRequest();
// Return bad request if both are true or both are false
if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest();
bool success = await this.database.RateComment(token.UserId, commentId, rating);
if (!success) return this.BadRequest();
@ -41,37 +43,33 @@ public class CommentController : ControllerBase
[HttpGet("userComments/{username}")]
public async Task<IActionResult> GetComments([FromQuery] int pageStart, [FromQuery] int pageSize, string? username, string? slotType, int slotId)
{
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();
if (pageSize <= 0 || pageStart < 0) return this.BadRequest();
int targetId = slotId;
CommentType type = CommentType.Level;
if (!string.IsNullOrWhiteSpace(username))
if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest();
if (slotType == "developer") slotId = await SlotHelper.GetPlaceholderSlotId(this.database, slotId, SlotType.Developer);
int targetId;
CommentType type = username == null ? CommentType.Level : CommentType.Profile;
if (type == CommentType.Level)
{
targetId = this.database.Users.First(u => u.Username.Equals(username)).UserId;
type = CommentType.Profile;
targetId = await this.database.Slots.Where(s => s.SlotId == slotId)
.Where(s => s.CommentsEnabled && !s.Hidden)
.Select(s => s.SlotId)
.FirstOrDefaultAsync();
}
else
{
if (SlotHelper.IsTypeInvalid(slotType) || slotId == 0) return this.BadRequest();
targetId = await this.database.Users.Where(u => u.Username == username)
.Where(u => u.CommentsEnabled)
.Select(u => u.UserId)
.FirstOrDefaultAsync();
}
if (type == CommentType.Level && slotType == "developer") targetId = await SlotHelper.GetPlaceholderSlotId(this.database, slotId, SlotType.Developer);
if (type == CommentType.Profile)
{
User? profile = await this.database.Users.FirstOrDefaultAsync(s => s.UserId == targetId);
if (profile == null) return this.BadRequest();
if (!profile.CommentsEnabled) return this.NotFound();
}
else
{
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == targetId);
if (slot == null) return this.BadRequest();
if (!slot.CommentsEnabled) return this.NotFound();
}
if (targetId == 0) return this.NotFound();
List<Comment> comments = await this.database.Comments.Include
(c => c.Poster)
@ -88,7 +86,8 @@ public class CommentController : ControllerBase
private async Task<int> getReaction(int userId, int commentId)
{
return await this.database.Reactions.Where(r => r.UserId == userId && r.TargetId == commentId)
return await this.database.Reactions.Where(r => r.UserId == userId)
.Where(r => r.TargetId == commentId)
.Select(r => r.Rating)
.FirstOrDefaultAsync();
}
@ -97,28 +96,28 @@ public class CommentController : ControllerBase
[HttpPost("postComment/{slotType}/{slotId:int}")]
public async Task<IActionResult> PostComment(string? username, string? slotType, int slotId)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
this.Request.Body.Position = 0;
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
XmlSerializer serializer = new(typeof(Comment));
Comment? comment = (Comment?)serializer.Deserialize(new StringReader(bodyString));
SanitizationHelper.SanitizeStringsInClass(comment);
CommentType type = (slotId == 0 ? CommentType.Profile : CommentType.Level);
if (type == CommentType.Level && (SlotHelper.IsTypeInvalid(slotType) || slotId == 0)) return this.BadRequest();
GameToken token = this.GetToken();
Comment? comment = await this.DeserializeBody<Comment>();
if (comment == null) return this.BadRequest();
int targetId = slotId;
if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest();
if (type == CommentType.Profile) targetId = this.database.Users.First(u => u.Username == username).UserId;
CommentType type = username == null ? CommentType.Level : CommentType.Profile;
if (slotType == "developer") targetId = await SlotHelper.GetPlaceholderSlotId(this.database, targetId, SlotType.Developer);
int targetId;
if (type == CommentType.Level)
{
slotId = await SlotHelper.GetPlaceholderSlotId(this.database, slotId, SlotType.Developer);
targetId = await this.database.Slots.Where(s => s.SlotId == slotId)
.Where(s => s.CommentsEnabled && !s.Hidden)
.Select(s => s.SlotId)
.FirstOrDefaultAsync();
}
else
{
targetId = await this.database.UserIdFromUsername(username!);
}
bool success = await this.database.PostComment(token.UserId, targetId, type, comment.Message);
if (success) return this.Ok();
@ -130,44 +129,44 @@ public class CommentController : ControllerBase
[HttpPost("deleteComment/{slotType}/{slotId:int}")]
public async Task<IActionResult> DeleteComment([FromQuery] int commentId, string? username, string? slotType, int slotId)
{
GameToken? token = await this.database.GameTokenFromRequest(this.Request);
if (token == null) return this.StatusCode(403, "");
GameToken token = this.GetToken();
if ((slotId == 0 || SlotHelper.IsTypeInvalid(slotType)) == (username == null)) return this.BadRequest();
Comment? comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId);
if (comment == null) return this.NotFound();
if (comment.Type == CommentType.Level && (SlotHelper.IsTypeInvalid(slotType) || slotId == 0)) return this.BadRequest();
if (comment.Deleted) return this.Ok();
if (slotType == "developer") slotId = await SlotHelper.GetPlaceholderSlotId(this.database, slotId, SlotType.Developer);
// if you are not the poster
if (comment.PosterUserId != token.UserId)
bool canDelete;
if (comment.Type == CommentType.Profile)
{
if (comment.Type == CommentType.Profile)
{
// if you aren't the poster and aren't the profile owner
if (comment.TargetId != token.UserId)
{
return this.StatusCode(403, "");
}
}
else
{
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == comment.TargetId);
// if you aren't the creator of the level
if (slot == null || slot.CreatorId != token.UserId || slotId != slot.SlotId)
{
return this.StatusCode(403, "");
}
}
canDelete = comment.PosterUserId == token.UserId || comment.TargetId == token.UserId;
}
else
{
if (slotType == "developer") slotId = await SlotHelper.GetPlaceholderSlotId(this.database, slotId, SlotType.Developer);
if (slotId != comment.TargetId) return this.BadRequest();
int slotCreator = await this.database.Slots.Where(s => s.SlotId == comment.TargetId)
.Where(s => s.CommentsEnabled)
.Select(s => s.CreatorId)
.FirstOrDefaultAsync();
// Comments are disabled or the slot doesn't have a creator
if (slotCreator == 0) return this.BadRequest();
canDelete = comment.PosterUserId == token.UserId || slotCreator == token.UserId;
}
if (!canDelete) return this.StatusCode(403, "");
comment.Deleted = true;
comment.DeletedBy = await this.database.UsernameFromGameToken(token);
comment.DeletedType = "user";
await this.database.SaveChangesAsync();
return this.Ok();
}
}