mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-05-17 15:22:26 +00:00
Fix slot version bug and other improvements (#281)
* Fix slot version bug and other improvements * Fix upload tests not authenticating Co-authored-by: jvyden <jvyden@jvyden.xyz>
This commit is contained in:
parent
3aecccedf2
commit
216cd2e198
7 changed files with 104 additions and 35 deletions
|
@ -4,6 +4,7 @@ using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using LBPUnion.ProjectLighthouse.Tests;
|
using LBPUnion.ProjectLighthouse.Tests;
|
||||||
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace ProjectLighthouse.Tests.GameApiTests;
|
namespace ProjectLighthouse.Tests.GameApiTests;
|
||||||
|
@ -19,7 +20,9 @@ public class UploadTests : LighthouseServerTest
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ShouldNotAcceptScript()
|
public async Task ShouldNotAcceptScript()
|
||||||
{
|
{
|
||||||
HttpResponseMessage response = await this.UploadFileEndpointRequest("ExampleFiles/TestScript.ff");
|
LoginResult loginResult = await this.Authenticate();
|
||||||
|
|
||||||
|
HttpResponseMessage response = await this.AuthenticatedUploadFileEndpointRequest("ExampleFiles/TestScript.ff", loginResult.AuthTicket);
|
||||||
Assert.False(response.StatusCode == HttpStatusCode.Forbidden);
|
Assert.False(response.StatusCode == HttpStatusCode.Forbidden);
|
||||||
Assert.False(response.IsSuccessStatusCode);
|
Assert.False(response.IsSuccessStatusCode);
|
||||||
}
|
}
|
||||||
|
@ -27,7 +30,9 @@ public class UploadTests : LighthouseServerTest
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ShouldNotAcceptFarc()
|
public async Task ShouldNotAcceptFarc()
|
||||||
{
|
{
|
||||||
HttpResponseMessage response = await this.UploadFileEndpointRequest("ExampleFiles/TestFarc.farc");
|
LoginResult loginResult = await this.Authenticate();
|
||||||
|
|
||||||
|
HttpResponseMessage response = await this.AuthenticatedUploadFileEndpointRequest("ExampleFiles/TestFarc.farc", loginResult.AuthTicket);
|
||||||
Assert.False(response.StatusCode == HttpStatusCode.Forbidden);
|
Assert.False(response.StatusCode == HttpStatusCode.Forbidden);
|
||||||
Assert.False(response.IsSuccessStatusCode);
|
Assert.False(response.IsSuccessStatusCode);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +40,9 @@ public class UploadTests : LighthouseServerTest
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ShouldNotAcceptGarbage()
|
public async Task ShouldNotAcceptGarbage()
|
||||||
{
|
{
|
||||||
HttpResponseMessage response = await this.UploadFileEndpointRequest("ExampleFiles/TestGarbage.bin");
|
LoginResult loginResult = await this.Authenticate();
|
||||||
|
|
||||||
|
HttpResponseMessage response = await this.AuthenticatedUploadFileEndpointRequest("ExampleFiles/TestGarbage.bin", loginResult.AuthTicket);
|
||||||
Assert.False(response.StatusCode == HttpStatusCode.Forbidden);
|
Assert.False(response.StatusCode == HttpStatusCode.Forbidden);
|
||||||
Assert.False(response.IsSuccessStatusCode);
|
Assert.False(response.IsSuccessStatusCode);
|
||||||
}
|
}
|
||||||
|
@ -43,7 +50,9 @@ public class UploadTests : LighthouseServerTest
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ShouldAcceptTexture()
|
public async Task ShouldAcceptTexture()
|
||||||
{
|
{
|
||||||
HttpResponseMessage response = await this.UploadFileEndpointRequest("ExampleFiles/TestTexture.tex");
|
LoginResult loginResult = await this.Authenticate();
|
||||||
|
|
||||||
|
HttpResponseMessage response = await this.AuthenticatedUploadFileEndpointRequest("ExampleFiles/TestTexture.tex", loginResult.AuthTicket);
|
||||||
Assert.False(response.StatusCode == HttpStatusCode.Forbidden);
|
Assert.False(response.StatusCode == HttpStatusCode.Forbidden);
|
||||||
Assert.True(response.IsSuccessStatusCode);
|
Assert.True(response.IsSuccessStatusCode);
|
||||||
}
|
}
|
||||||
|
@ -51,7 +60,9 @@ public class UploadTests : LighthouseServerTest
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ShouldAcceptLevel()
|
public async Task ShouldAcceptLevel()
|
||||||
{
|
{
|
||||||
HttpResponseMessage response = await this.UploadFileEndpointRequest("ExampleFiles/TestLevel.lvl");
|
LoginResult loginResult = await this.Authenticate();
|
||||||
|
|
||||||
|
HttpResponseMessage response = await this.AuthenticatedUploadFileEndpointRequest("ExampleFiles/TestLevel.lvl", loginResult.AuthTicket);
|
||||||
Assert.False(response.StatusCode == HttpStatusCode.Forbidden);
|
Assert.False(response.StatusCode == HttpStatusCode.Forbidden);
|
||||||
Assert.True(response.IsSuccessStatusCode);
|
Assert.True(response.IsSuccessStatusCode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,6 +73,16 @@ public class LighthouseServerTest
|
||||||
return await this.Client.PostAsync($"/LITTLEBIGPLANETPS3_XML/upload/{hash}", new ByteArrayContent(bytes));
|
return await this.Client.PostAsync($"/LITTLEBIGPLANETPS3_XML/upload/{hash}", new ByteArrayContent(bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<HttpResponseMessage> AuthenticatedUploadFileEndpointRequest(string filePath, string mmAuth)
|
||||||
|
{
|
||||||
|
byte[] bytes = await File.ReadAllBytesAsync(filePath);
|
||||||
|
string hash = HashHelper.Sha1Hash(bytes).ToLower();
|
||||||
|
using HttpRequestMessage requestMessage = new(HttpMethod.Post, $"/LITTLEBIGPLANETPS3_XML/upload/{hash}");
|
||||||
|
requestMessage.Headers.Add("Cookie", mmAuth);
|
||||||
|
requestMessage.Content = new ByteArrayContent(bytes);
|
||||||
|
return await this.Client.SendAsync(requestMessage);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<HttpResponseMessage> UploadFileRequest(string endpoint, string filePath)
|
public async Task<HttpResponseMessage> UploadFileRequest(string endpoint, string filePath)
|
||||||
=> await this.Client.PostAsync(endpoint, new StringContent(await File.ReadAllTextAsync(filePath)));
|
=> await this.Client.PostAsync(endpoint, new StringContent(await File.ReadAllTextAsync(filePath)));
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -20,6 +19,13 @@ namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Resources;
|
||||||
[Route("LITTLEBIGPLANETPS3_XML")]
|
[Route("LITTLEBIGPLANETPS3_XML")]
|
||||||
public class ResourcesController : ControllerBase
|
public class ResourcesController : ControllerBase
|
||||||
{
|
{
|
||||||
|
private readonly Database database;
|
||||||
|
|
||||||
|
public ResourcesController(Database database)
|
||||||
|
{
|
||||||
|
this.database = database;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("showModerated")]
|
[HttpPost("showModerated")]
|
||||||
public IActionResult ShowModerated() => this.Ok(LbpSerializer.BlankElement("resources"));
|
public IActionResult ShowModerated() => this.Ok(LbpSerializer.BlankElement("resources"));
|
||||||
|
|
||||||
|
@ -27,6 +33,9 @@ public class ResourcesController : ControllerBase
|
||||||
[HttpPost("showNotUploaded")]
|
[HttpPost("showNotUploaded")]
|
||||||
public async Task<IActionResult> FilterResources()
|
public async Task<IActionResult> FilterResources()
|
||||||
{
|
{
|
||||||
|
User? user = await this.database.UserFromGameRequest(this.Request);
|
||||||
|
if (user == null) return this.StatusCode(403, "");
|
||||||
|
|
||||||
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||||
|
|
||||||
XmlSerializer serializer = new(typeof(ResourceList));
|
XmlSerializer serializer = new(typeof(ResourceList));
|
||||||
|
@ -42,8 +51,11 @@ public class ResourcesController : ControllerBase
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("r/{hash}")]
|
[HttpGet("r/{hash}")]
|
||||||
public IActionResult GetResource(string hash)
|
public async Task<IActionResult> GetResource(string hash)
|
||||||
{
|
{
|
||||||
|
User? user = await this.database.UserFromGameRequest(this.Request);
|
||||||
|
if (user == null) return this.StatusCode(403, "");
|
||||||
|
|
||||||
string path = FileHelper.GetResourcePath(hash);
|
string path = FileHelper.GetResourcePath(hash);
|
||||||
|
|
||||||
if (FileHelper.ResourceExists(hash)) return this.File(IOFile.OpenRead(path), "application/octet-stream");
|
if (FileHelper.ResourceExists(hash)) return this.File(IOFile.OpenRead(path), "application/octet-stream");
|
||||||
|
@ -63,21 +75,21 @@ public class ResourcesController : ControllerBase
|
||||||
}
|
}
|
||||||
|
|
||||||
LbpFile? file = LbpFile.FromHash(hash);
|
LbpFile? file = LbpFile.FromHash(hash);
|
||||||
if (file != null)
|
if (file != null && ImageHelper.LbpFileToPNG(file))
|
||||||
{
|
{
|
||||||
if (ImageHelper.LbpFileToPNG(file))
|
return this.File(IOFile.OpenRead(path), "image/png");
|
||||||
{
|
|
||||||
return this.File(IOFile.OpenRead(path), "image/png");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.NotFound();
|
return this.NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check if this is a valid hash
|
// TODO: check if this is a valid hash
|
||||||
|
[HttpPost("upload/{hash}/unattributed")]
|
||||||
[HttpPost("upload/{hash}")]
|
[HttpPost("upload/{hash}")]
|
||||||
public async Task<IActionResult> UploadResource(string hash)
|
public async Task<IActionResult> UploadResource(string hash)
|
||||||
{
|
{
|
||||||
|
User? user = await this.database.UserFromGameRequest(this.Request);
|
||||||
|
if (user == null) return this.StatusCode(403, "");
|
||||||
|
|
||||||
string assetsDirectory = FileHelper.ResourcePath;
|
string assetsDirectory = FileHelper.ResourcePath;
|
||||||
string path = FileHelper.GetResourcePath(hash);
|
string path = FileHelper.GetResourcePath(hash);
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,6 @@ public class PublishController : ControllerBase
|
||||||
[HttpPost("publish")]
|
[HttpPost("publish")]
|
||||||
public async Task<IActionResult> Publish()
|
public async Task<IActionResult> Publish()
|
||||||
{
|
{
|
||||||
// User user = await this.database.UserFromGameRequest(this.Request);
|
|
||||||
(User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request);
|
(User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request);
|
||||||
|
|
||||||
if (userAndToken == null) return this.StatusCode(403, "");
|
if (userAndToken == null) return this.StatusCode(403, "");
|
||||||
|
@ -94,9 +93,9 @@ public class PublishController : ControllerBase
|
||||||
|
|
||||||
if (slot.Name.Length > 100) return this.BadRequest();
|
if (slot.Name.Length > 100) return this.BadRequest();
|
||||||
|
|
||||||
foreach (string resource in slot.Resources)
|
if (slot.Resources.Any(resource => !FileHelper.ResourceExists(resource)))
|
||||||
{
|
{
|
||||||
if (!FileHelper.ResourceExists(resource)) return this.BadRequest();
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
LbpFile? rootLevel = LbpFile.FromHash(slot.RootLevel);
|
LbpFile? rootLevel = LbpFile.FromHash(slot.RootLevel);
|
||||||
|
@ -148,7 +147,14 @@ public class PublishController : ControllerBase
|
||||||
slot.TeamPick = oldSlot.TeamPick;
|
slot.TeamPick = oldSlot.TeamPick;
|
||||||
|
|
||||||
// Only update a slot's gameVersion if the level was actually change
|
// Only update a slot's gameVersion if the level was actually change
|
||||||
if (oldSlot.RootLevel != slot.RootLevel) slot.GameVersion = gameToken.GameVersion;
|
if (oldSlot.RootLevel != slot.RootLevel)
|
||||||
|
{
|
||||||
|
slot.GameVersion = gameToken.GameVersion;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slot.GameVersion = oldSlot.GameVersion;
|
||||||
|
}
|
||||||
|
|
||||||
if (slot.MinimumPlayers == 0 || slot.MaximumPlayers == 0)
|
if (slot.MinimumPlayers == 0 || slot.MaximumPlayers == 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
</div>
|
</div>
|
||||||
<input type="submit" class="ui blue button">
|
<input type="submit" class="ui blue button">
|
||||||
</form>
|
</form>
|
||||||
<br>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@for(int i = 0; i < Model.Comments.Count; i++)
|
@for(int i = 0; i < Model.Comments.Count; i++)
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
}
|
}
|
||||||
<div class="cardStatsUnderTitle">
|
<div class="cardStatsUnderTitle">
|
||||||
<i class="pink heart icon" title="Hearts"></i> <span>@Model.Hearts</span>
|
<i class="pink heart icon" title="Hearts"></i> <span>@Model.Hearts</span>
|
||||||
<i class="blue play icon" title="Plays"></i> <span>@Model.Plays</span>
|
<i class="blue play icon" title="Plays"></i> <span>@Model.PlaysUnique</span>
|
||||||
<i class="green thumbs up icon" title="Yays"></i> <span>@Model.Thumbsup</span>
|
<i class="green thumbs up icon" title="Yays"></i> <span>@Model.Thumbsup</span>
|
||||||
<i class="red thumbs down icon" title="Boos"></i> <span>@Model.Thumbsdown</span>
|
<i class="red thumbs down icon" title="Boos"></i> <span>@Model.Thumbsdown</span>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
@page "/slot/{id:int}"
|
@page "/slot/{id:int}"
|
||||||
@using System.Web
|
@using System.Web
|
||||||
@using LBPUnion.ProjectLighthouse.Helpers.Extensions
|
@using LBPUnion.ProjectLighthouse.Helpers.Extensions
|
||||||
|
@using LBPUnion.ProjectLighthouse.Types
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Reviews
|
@using LBPUnion.ProjectLighthouse.Types.Reviews
|
||||||
@using LBPUnion.ProjectLighthouse.Types.Settings
|
@using LBPUnion.ProjectLighthouse.Types.Settings
|
||||||
@model LBPUnion.ProjectLighthouse.Pages.SlotPage
|
@model LBPUnion.ProjectLighthouse.Pages.SlotPage
|
||||||
|
@ -81,16 +82,23 @@
|
||||||
}
|
}
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
@foreach (Review review in Model.Reviews)
|
@for (int i = 0; i < Model.Reviews.Count; i++)
|
||||||
{
|
{
|
||||||
|
Review review = Model.Reviews[i];
|
||||||
string faceHash = review.Thumb switch {
|
string faceHash = review.Thumb switch {
|
||||||
-1 => review.Reviewer.BooHash,
|
-1 => review.Reviewer?.BooHash,
|
||||||
0 => review.Reviewer.MehHash,
|
0 => review.Reviewer?.MehHash,
|
||||||
1 => review.Reviewer.YayHash,
|
1 => review.Reviewer?.YayHash,
|
||||||
|
|
||||||
_ => throw new ArgumentOutOfRangeException(),
|
_ => throw new ArgumentOutOfRangeException(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(faceHash))
|
||||||
|
{
|
||||||
|
faceHash = ServerSettings.Instance.MissingIconHash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
string faceAlt = review.Thumb switch {
|
string faceAlt = review.Thumb switch {
|
||||||
-1 => "Boo!",
|
-1 => "Boo!",
|
||||||
0 => "Meh.",
|
0 => "Meh.",
|
||||||
|
@ -106,27 +114,50 @@
|
||||||
<img class="cardIcon slotCardIcon" src="@ServerSettings.Instance.ExternalUrl/gameAssets/@faceHash" alt="@faceAlt" title="@faceAlt" style="min-width: @(size)px; width: @(size)px; height: @(size)px">
|
<img class="cardIcon slotCardIcon" src="@ServerSettings.Instance.ExternalUrl/gameAssets/@faceHash" alt="@faceAlt" title="@faceAlt" style="min-width: @(size)px; width: @(size)px; height: @(size)px">
|
||||||
</div>
|
</div>
|
||||||
<div class="cardStats">
|
<div class="cardStats">
|
||||||
<h3 style="margin-bottom: 5px;">@review.Reviewer.Username</h3>
|
<h3 style="margin-bottom: 5px;">@review.Reviewer?.Username</h3>
|
||||||
@if (review.Labels.Length > 1)
|
@if (review.Deleted)
|
||||||
{
|
{
|
||||||
@foreach (string reviewLabel in review.Labels)
|
if (review.DeletedBy == DeletedBy.LevelAuthor)
|
||||||
{
|
{
|
||||||
<div class="ui blue label">@reviewLabel.Replace("LABEL_", "")</div>
|
<p>
|
||||||
|
<i>This review has been deleted by the level author.</i>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<p>
|
||||||
|
<i>This review has been deleted by a moderator.</i>
|
||||||
|
</p>
|
||||||
}
|
}
|
||||||
}
|
|
||||||
@if (string.IsNullOrWhiteSpace(review.Text))
|
|
||||||
{
|
|
||||||
<p>
|
|
||||||
<i>This review contains no text.</i>
|
|
||||||
</p>
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
<p>@review.Text</p>
|
@if (review.Labels.Length > 1)
|
||||||
|
{
|
||||||
|
@foreach (string reviewLabel in review.Labels)
|
||||||
|
{
|
||||||
|
<div class="ui blue label">@reviewLabel.Replace("LABEL_", "")</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@if (string.IsNullOrWhiteSpace(review.Text))
|
||||||
|
{
|
||||||
|
<p>
|
||||||
|
<i>This review contains no text.</i>
|
||||||
|
</p>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
{
|
||||||
|
<p>@review.Text</p>
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
@if (i != Model.Reviews.Count - 1)
|
||||||
|
{
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue