namespace Giants.WebApi.Controllers { using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; using Giants.Services.Services; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; [ApiController] [ApiVersion("1.0")] [ApiVersion("1.1")] [Route("api/[controller]")] public class CrashReportsController : ControllerBase { private readonly ICrashReportService crashReportService; private readonly IHttpContextAccessor httpContextAccessor; private readonly ILogger logger; private readonly IConfiguration configuration; private const long MaximumSizeInBytes = 10485760; // 10MB public CrashReportsController( ICrashReportService crashReportService, IHttpContextAccessor httpContextAccessor, ILogger logger, IConfiguration configuration) { this.crashReportService = crashReportService; this.httpContextAccessor = httpContextAccessor; this.logger = logger; this.configuration = configuration; } [HttpPost] public async Task Upload() { this.ValidateFiles(this.Request.Form.Files); var file = this.Request.Form.Files.First(); using (var stream = file.OpenReadStream()) { await this.crashReportService.ProcessReport(file.FileName, this.GetRequestIpAddress(), stream).ConfigureAwait(false); } bool sentryEnabled = Convert.ToBoolean(this.configuration["SentryEnabled"]); if (!sentryEnabled) { this.logger.LogInformation("Skipping Sentry upload; disabled."); return; } using (var stream = file.OpenReadStream()) { await this.crashReportService.UploadMinidumpToSentry(file.FileName, stream).ConfigureAwait(false); } } private void ValidateFiles(IEnumerable formFiles) { if (formFiles.Count() != 1) { // We only expect one .zip file throw new ArgumentException("Only one file is accepted.", nameof(formFiles)); } var file = this.Request.Form.Files.First(); if (file.Length > MaximumSizeInBytes) { throw new ArgumentException("File too large.", nameof(formFiles)); } string fileName = Path.GetFileNameWithoutExtension(file.FileName); if (!Guid.TryParse(fileName, out Guid _) || file.Name != "crashrpt") { throw new ArgumentException("Unexpected file name.", nameof(formFiles)); } } private string GetRequestIpAddress() { return this.httpContextAccessor.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString(); } } }