Repository navigation
Reject invalid demo uploads before storage #885
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| using Microsoft.Extensions.Configuration; | ||
| using Microsoft.Extensions.Logging; | ||
| using Moq; | ||
| using Xunit; | ||
| using XtremeIdiots.Portal.Repository.Abstractions.Constants.V1; | ||
| using XtremeIdiots.Portal.Repository.Api.V1.Services; | ||
|
|
||
| namespace XtremeIdiots.Portal.Repository.Api.Tests.V1.Services; | ||
|
|
||
| public class DemoFileProcessorTests | ||
|
Check warning on line 10 in src/XtremeIdiots.Portal.Repository.Api.Tests.V1/Services/DemoFileProcessorTests.cs
|
||
| { | ||
| [Fact] | ||
| public async Task ProcessAsync_WithInvalidDemo_ThrowsBeforeStorageAccess() | ||
|
Check warning on line 13 in src/XtremeIdiots.Portal.Repository.Api.Tests.V1/Services/DemoFileProcessorTests.cs
|
||
| { | ||
| var filePath = Path.GetTempFileName(); | ||
| try | ||
| { | ||
| var configuration = new ConfigurationBuilder().Build(); | ||
| var processor = new DemoFileProcessor( | ||
| configuration, | ||
| Mock.Of<ILogger<DemoFileProcessor>>()); | ||
|
|
||
| _ = await Assert.ThrowsAsync<InvalidDataException>(() => | ||
| processor.ProcessAsync(filePath, GameType.CallOfDuty5, CancellationToken.None)); | ||
| } | ||
| finally | ||
| { | ||
| File.Delete(filePath); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| using Azure.Identity; | ||
| using Azure.Storage.Blobs; | ||
| using MX.CodDemoReader.Models; | ||
| using XtremeIdiots.Portal.Repository.Abstractions.Constants.V1; | ||
| using XtremeIdiots.Portal.Repository.Api.V1.Extensions; | ||
|
|
||
| namespace XtremeIdiots.Portal.Repository.Api.V1.Services | ||
|
Check warning on line 7 in src/XtremeIdiots.Portal.Repository.Api.V1/Services/DemoFileProcessor.cs
|
||
| { | ||
| /// <summary> | ||
| /// Parses demo metadata before uploading valid files to blob storage. | ||
| /// </summary> | ||
| public sealed class DemoFileProcessor : IDemoFileProcessor | ||
| { | ||
| private readonly IConfiguration configuration; | ||
| private readonly ILogger<DemoFileProcessor> logger; | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="DemoFileProcessor"/> class. | ||
| /// </summary> | ||
| public DemoFileProcessor( | ||
| IConfiguration configuration, | ||
| ILogger<DemoFileProcessor> logger) | ||
| { | ||
| ArgumentNullException.ThrowIfNull(configuration); | ||
| ArgumentNullException.ThrowIfNull(logger); | ||
| this.configuration = configuration; | ||
| this.logger = logger; | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public async Task<DemoFileProcessingResult> ProcessAsync( | ||
| string filePath, | ||
| GameType gameType, | ||
| CancellationToken cancellationToken) | ||
| { | ||
| var localDemo = new LocalDemo(filePath, gameType.ToGameTypeInt().ToCodDemoReaderGameVersion()); | ||
| if (!localDemo.IsValid) | ||
| { | ||
| logger.LogWarning("Unable to parse uploaded demo for game type {GameType}", gameType); | ||
|
Check warning on line 39 in src/XtremeIdiots.Portal.Repository.Api.V1/Services/DemoFileProcessor.cs
|
||
| throw new InvalidDataException("The uploaded file could not be parsed as a valid demo"); | ||
| } | ||
|
|
||
| var blobEndpoint = configuration["appdata_storage_blob_endpoint"]; | ||
| if (string.IsNullOrWhiteSpace(blobEndpoint)) | ||
| { | ||
| throw new InvalidOperationException("Demo blob storage endpoint is not configured"); | ||
| } | ||
|
|
||
| var blobServiceClient = new BlobServiceClient(new Uri(blobEndpoint), new DefaultAzureCredential()); | ||
| var containerClient = blobServiceClient.GetBlobContainerClient("demos"); | ||
| var blobKey = $"{Guid.NewGuid()}.{gameType.DemoExtension()}"; | ||
| var blobClient = containerClient.GetBlobClient(blobKey); | ||
|
|
||
| await blobClient.UploadAsync(filePath, cancellationToken).ConfigureAwait(false); | ||
|
Check warning on line 54 in src/XtremeIdiots.Portal.Repository.Api.V1/Services/DemoFileProcessor.cs
|
||
|
|
||
| return new DemoFileProcessingResult( | ||
| blobKey, | ||
| blobClient.Uri, | ||
| localDemo.Created, | ||
| localDemo.Map, | ||
| localDemo.Mod, | ||
| localDemo.GameMode, | ||
| localDemo.ServerName, | ||
| localDemo.FileSize); | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.