public async Task <StorageFile> HandleFinishedUploadToken(ApplicationDbContext database, StorageUploadVerifyToken token) { var file = await database.StorageFiles.Include(f => f.StorageItemVersions) .ThenInclude(v => v.StorageItem).FirstOrDefaultAsync(f => f.Id == token.FileId); if (file == null) { throw new Exception("StorageFile not found"); } if (!TokenMatchesFile(token, file)) { throw new Exception("Token doesn't match file"); } if (!file.Uploading) { throw new Exception("File is already marked as uploaded"); } if (file.StorageItemVersions.Count < 1) { throw new Exception("Uploaded StorageFile has no associated item version object(s)"); } foreach (var version in file.StorageItemVersions) { if (!version.Uploading) { throw new Exception("Can't use token on item that has already uploaded version object"); } } // Verify that upload to S3 was successful long actualSize; try { actualSize = await GetObjectSize(file.UploadPath); } catch (Exception e) { throw new Exception("Checking item size in remote storage failed", e); } if (actualSize != file.Size) { throw new Exception($"File size in storage doesn't match expected. {actualSize} != {file.Size}"); } // Move file to the actual target location await MoveObject(file.UploadPath, file.StoragePath); return(file); }
public async Task <ActionResult <DebugSymbolOfferResponse> > FinishUpload([Required][FromBody] TokenForm request) { if (!remoteStorage.Configured) { throw new HttpResponseException() { Status = StatusCodes.Status500InternalServerError, Value = "Remote storage is not configured" }; } var decodedToken = StorageUploadVerifyToken.TryToLoadFromString(dataProtector, request.Token); if (decodedToken == null || decodedToken.ParentId == null) { return(BadRequest("Invalid finished upload token")); } StorageFile file; try { file = await remoteStorage.HandleFinishedUploadToken(database, decodedToken); } catch (Exception e) { logger.LogWarning(e, "Failed to check upload token / resulting file"); return(BadRequest("Failed to verify that uploaded file is valid")); } // This is used in the token here to store the devbuild ID var symbol = await database.DebugSymbols.FindAsync(decodedToken.ParentId.Value); if (symbol == null) { return(BadRequest("No symbol found with the id in the token")); } // Mark it as ready to use for stackwalk operations happening in the future symbol.Active = true; symbol.Uploaded = true; symbol.BumpUpdatedAt(); await remoteStorage.PerformFileUploadSuccessActions(file, database); await database.SaveChangesAsync(); logger.LogInformation("DebugSymbol {Id} ({StoragePath}) is now uploaded", symbol.Id, file.StoragePath); return(Ok()); }
public bool TokenMatchesFile(StorageUploadVerifyToken token, StorageFile file) { return(token.FileStoragePath == file.StoragePath && token.FileUploadPath == file.UploadPath && token.FileSize == file.Size && token.FileId == file.Id); }