Add basic manifest checking in uploaded archives
parent
91b9328afc
commit
f5b136720a
|
@ -1,8 +1,12 @@
|
|||
using LANCommander.Data;
|
||||
using LANCommander.Data.Models;
|
||||
using LANCommander.Extensions;
|
||||
using LANCommander.Models;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.IO.Compression;
|
||||
using YamlDotNet.Serialization;
|
||||
using YamlDotNet.Serialization.NamingConventions;
|
||||
|
||||
namespace LANCommander.Controllers
|
||||
{
|
||||
|
@ -98,5 +102,68 @@ namespace LANCommander.Controllers
|
|||
|
||||
return RedirectToAction("Edit", "Games", new { id = gameId });
|
||||
}
|
||||
|
||||
public async Task<IActionResult> ValidateManifest(Guid id)
|
||||
{
|
||||
var path = Path.Combine("Upload", id.ToString());
|
||||
|
||||
string manifestContents = String.Empty;
|
||||
|
||||
if (!System.IO.File.Exists(path))
|
||||
return BadRequest("Specified object does not exist");
|
||||
|
||||
try
|
||||
{
|
||||
using (ZipArchive archive = ZipFile.OpenRead(path))
|
||||
{
|
||||
var manifest = archive.Entries.FirstOrDefault(e => e.FullName == "_manifest.yml");
|
||||
|
||||
if (manifest == null)
|
||||
throw new FileNotFoundException("Manifest file not found. Add a _manifest.yml file to your archive and try again.");
|
||||
|
||||
foreach (ZipArchiveEntry entry in archive.Entries)
|
||||
{
|
||||
if (entry.FullName == "_manifest.yml")
|
||||
{
|
||||
using (StreamReader sr = new StreamReader(entry.Open()))
|
||||
{
|
||||
manifestContents = await sr.ReadToEndAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InvalidDataException ex)
|
||||
{
|
||||
System.IO.File.Delete(path);
|
||||
return BadRequest("Uploaded archive is corrupt or not a .zip file.");
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
System.IO.File.Delete(path);
|
||||
return BadRequest(ex.Message);
|
||||
}
|
||||
catch
|
||||
{
|
||||
System.IO.File.Delete(path);
|
||||
return BadRequest("An unknown error occurred.");
|
||||
}
|
||||
|
||||
var deserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||
.Build();
|
||||
|
||||
try
|
||||
{
|
||||
var manifest = deserializer.Deserialize<GameManifest>(manifestContents);
|
||||
}
|
||||
catch
|
||||
{
|
||||
System.IO.File.Delete(path);
|
||||
return BadRequest("The manifest file is invalid or corrupt.");
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.11" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.0" />
|
||||
<PackageReference Include="YamlDotNet" Version="12.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
namespace LANCommander.Models
|
||||
{
|
||||
public class GameManifest
|
||||
{
|
||||
public string Title { get; set; }
|
||||
public string SortTitle { get; set; }
|
||||
public string Description { get; set; }
|
||||
public DateTime ReleasedOn { get; set; }
|
||||
public string[] Genre { get; set; }
|
||||
public string[] Tags { get; set; }
|
||||
public string[] Publishers { get; set; }
|
||||
public string[] Developers { get; set; }
|
||||
public string Version { get; set; }
|
||||
public string Icon { get; set; }
|
||||
public GameAction[] Actions { get; set; }
|
||||
public bool Singleplayer { get; set; }
|
||||
public MultiplayerInfo LocalMultiplayer { get; set; }
|
||||
public MultiplayerInfo LanMultiplayer { get; set; }
|
||||
public MultiplayerInfo OnlineMultiplayer { get; set; }
|
||||
}
|
||||
|
||||
public class GameAction
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Arguments { get; set; }
|
||||
public string Path { get; set; }
|
||||
public string WorkingDirectory { get; set; }
|
||||
public bool IsPrimaryAction { get; set; }
|
||||
}
|
||||
|
||||
public class MultiplayerInfo
|
||||
{
|
||||
public int MinPlayers { get; set; }
|
||||
public int MaxPlayers { get; set; }
|
||||
}
|
||||
}
|
|
@ -122,7 +122,7 @@
|
|||
.removeClass('progress-bar-striped')
|
||||
.removeClass('progress-bar-animated')
|
||||
.addClass('bg-danger')
|
||||
.text('Error!');
|
||||
.text('Upload Error!');
|
||||
|
||||
$('#UploadButton').show();
|
||||
$('#SaveButton').hide();
|
||||
|
|
|
@ -59,8 +59,37 @@
|
|||
© 2022 - LANCommander - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<div class="modal modal-blur fade" id="ErrorModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-sm" role="document">
|
||||
<div class="modal-content">
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
<div class="modal-status bg-danger"></div>
|
||||
<div class="modal-body text-center py-4">
|
||||
<!-- Download SVG icon from http://tabler-icons.io/i/alert-triangle -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="icon mb-2 text-danger icon-lg" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M12 9v2m0 4v.01" /><path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75" /></svg>
|
||||
<h3 id="ErrorModalHeader"></h3>
|
||||
<div class="text-muted" id="ErrorModalMessage"></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="w-100">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<a href="#" class="btn btn-danger w-100" data-bs-dismiss="modal">
|
||||
Close
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="~/lib/jquery/dist/jquery.min.js"></script>
|
||||
<script src="~/js/tabler.min.js"></script>
|
||||
<script src="~/js/Modal.js"></script>
|
||||
|
||||
@await RenderSectionAsync("Scripts", required: false)
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
class Modal {
|
||||
constructor(id) {
|
||||
this.ElementId = id;
|
||||
// @ts-ignore
|
||||
this.Instance = new bootstrap.Modal(`#${this.ElementId}`, {
|
||||
keyboard: false
|
||||
});
|
||||
}
|
||||
Show(header, message) {
|
||||
document.getElementById(`${this.ElementId}Header`).innerText = header;
|
||||
document.getElementById(`${this.ElementId}Message`).innerText = message;
|
||||
this.Instance.show();
|
||||
}
|
||||
}
|
||||
const ErrorModal = new Modal('ErrorModal');
|
||||
//# sourceMappingURL=Modal.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"Modal.js","sourceRoot":"","sources":["Modal.ts"],"names":[],"mappings":"AAAA,MAAM,KAAK;IAIP,YAAY,EAAU;QAClB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QAEpB,aAAa;QACb,IAAI,CAAC,QAAQ,GAAG,IAAI,SAAS,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE;YACtD,QAAQ,EAAE,KAAK;SAClB,CAAC,CAAC;IACP,CAAC;IAED,IAAI,CAAC,MAAc,EAAE,OAAe;QAChC,QAAQ,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,SAAS,QAAQ,CAAC,CAAC,SAAS,GAAG,MAAM,CAAC;QACtE,QAAQ,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,SAAS,SAAS,CAAC,CAAC,SAAS,GAAG,OAAO,CAAC;QAExE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC;CACJ;AAED,MAAM,UAAU,GAAG,IAAI,KAAK,CAAC,YAAY,CAAC,CAAC"}
|
|
@ -0,0 +1,22 @@
|
|||
class Modal {
|
||||
Instance: any;
|
||||
ElementId: string;
|
||||
|
||||
constructor(id: string) {
|
||||
this.ElementId = id;
|
||||
|
||||
// @ts-ignore
|
||||
this.Instance = new bootstrap.Modal(`#${this.ElementId}`, {
|
||||
keyboard: false
|
||||
});
|
||||
}
|
||||
|
||||
Show(header: string, message: string) {
|
||||
document.getElementById(`${this.ElementId}Header`).innerText = header;
|
||||
document.getElementById(`${this.ElementId}Message`).innerText = message;
|
||||
|
||||
this.Instance.show();
|
||||
}
|
||||
}
|
||||
|
||||
const ErrorModal = new Modal('ErrorModal');
|
|
@ -18,6 +18,7 @@ class Uploader {
|
|||
constructor() {
|
||||
this.InitRoute = "/Upload/Init";
|
||||
this.ChunkRoute = "/Upload/Chunk";
|
||||
this.ValidateManifestRoute = "/Archives/ValidateManifest";
|
||||
this.MaxChunkSize = 1024 * 1024 * 25;
|
||||
}
|
||||
Init(fileInputId, uploadButtonId) {
|
||||
|
@ -44,6 +45,22 @@ class Uploader {
|
|||
this.GetChunks();
|
||||
try {
|
||||
for (let chunk of this.Chunks) {
|
||||
yield this.UploadChunk(chunk);
|
||||
}
|
||||
var isValid = yield this.ValidateManifest();
|
||||
if (isValid)
|
||||
this.OnComplete(this.Key);
|
||||
else
|
||||
this.OnError();
|
||||
}
|
||||
catch (_a) {
|
||||
this.OnError();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
UploadChunk(chunk) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let formData = new FormData();
|
||||
formData.append('file', this.File.slice(chunk.Start, chunk.End + 1));
|
||||
formData.append('start', chunk.Start.toString());
|
||||
|
@ -58,13 +75,18 @@ class Uploader {
|
|||
if (!chunkResponse)
|
||||
throw `Error uploading chunk ${chunk.Index}/${this.TotalChunks}`;
|
||||
this.OnProgress(chunk.Index / this.TotalChunks);
|
||||
});
|
||||
}
|
||||
this.OnComplete(this.Key);
|
||||
}
|
||||
catch (_a) {
|
||||
this.OnError();
|
||||
}
|
||||
ValidateManifest() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
let validationResponse = yield fetch(`${this.ValidateManifestRoute}/${this.Key}`, {
|
||||
method: "GET"
|
||||
});
|
||||
if (!validationResponse.ok) {
|
||||
ErrorModal.Show("Archive Invalid", yield validationResponse.text());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
GetChunks() {
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"version":3,"file":"Upload.js","sourceRoot":"","sources":["Upload.ts"],"names":[],"mappings":"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"}
|
||||
{"version":3,"file":"Upload.js","sourceRoot":"","sources":["Upload.ts"],"names":[],"mappings":"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"}
|
|
@ -18,6 +18,7 @@ class Uploader {
|
|||
|
||||
InitRoute: string = "/Upload/Init";
|
||||
ChunkRoute: string = "/Upload/Chunk";
|
||||
ValidateManifestRoute: string = "/Archives/ValidateManifest";
|
||||
|
||||
MaxChunkSize: number = 1024 * 1024 * 25;
|
||||
TotalChunks: number;
|
||||
|
@ -59,6 +60,23 @@ class Uploader {
|
|||
|
||||
try {
|
||||
for (let chunk of this.Chunks) {
|
||||
await this.UploadChunk(chunk);
|
||||
}
|
||||
|
||||
var isValid = await this.ValidateManifest();
|
||||
|
||||
if (isValid)
|
||||
this.OnComplete(this.Key);
|
||||
else
|
||||
this.OnError();
|
||||
}
|
||||
catch {
|
||||
this.OnError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async UploadChunk(chunk: Chunk) {
|
||||
let formData = new FormData();
|
||||
|
||||
formData.append('file', this.File.slice(chunk.Start, chunk.End + 1));
|
||||
|
@ -80,12 +98,18 @@ class Uploader {
|
|||
this.OnProgress(chunk.Index / this.TotalChunks);
|
||||
}
|
||||
|
||||
this.OnComplete(this.Key);
|
||||
}
|
||||
catch {
|
||||
this.OnError();
|
||||
}
|
||||
async ValidateManifest(): Promise<boolean> {
|
||||
let validationResponse = await fetch(`${this.ValidateManifestRoute}/${this.Key}`, {
|
||||
method: "GET"
|
||||
});
|
||||
|
||||
if (!validationResponse.ok) {
|
||||
ErrorModal.Show("Archive Invalid", await validationResponse.text())
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GetChunks() {
|
||||
|
|
Loading…
Reference in New Issue