public async Task <IActionResult> SetAvatarAsUploaded([FromRoute(Name = "id")] long worldId, [FromServices] IAvatarEntryRepository avatarEntryRepository, [FromServices] IContentResourceExistenceVerifier contentExistenceVerifier) { //At this point, the user is telling us they finished uploading the world. //They could be lying so we should check that the resource exists AND //we should also check that it's an asset bundle and gather some information from the header. //First we verify a world exists with this id if (!await avatarEntryRepository.ContainsAsync(worldId).ConfigureAwaitFalse()) { //TODO: We should say something more specific return(BadRequest()); } AvatarEntryModel model = await avatarEntryRepository.RetrieveAsync(worldId) .ConfigureAwaitFalse(); //Check the model is associated with this account. Only 1 account can own a world resource if (model.AccountId != ClaimsReader.GetAccountIdInt(User)) { return(Unauthorized()); } //Now that we know the world is in the database and the account making this authorized requests owns it //we can now actually check that the resource exists on the storeage system //TODO: This relies on some outdated API/deprecated stuff. bool resourceExists = await contentExistenceVerifier.VerifyResourceExists(UserContentType.Avatar, model.StorageGuid) .ConfigureAwaitFalse(); //TODO: Don't hardcore bucket name //TODO: Be more descriptive if (!resourceExists) { return(NotFound()); } //Ok, so the user IS the resource owner AND he did upload something, so let's validate the assetbundle header. //TODO: Refactor this into an object that does the validation and generates readable data //TODO: Actually implement asset bundle validation //We haven't implemented this yet, we should do asset bundle parsing and validation //This REALLY important to prevent invalid bundles from being uploaded //or content that isn't even an asset bundle being uploaded //See: https://github.com/HearthSim/UnityPack/wiki/Format-Documentation //For now, since it's unimplemented let's just set it validated await avatarEntryRepository.SetWorldValidated(model.AvatarId) .ConfigureAwaitFalseVoid(); return(Ok()); }
public async Task <IActionResult> RequestAvatarDownloadUrl( [FromRoute(Name = "id")] long avatarId, [FromServices] IAvatarEntryRepository avatarEntryRepository, [FromServices] IStorageUrlBuilder urlBuilder, [FromServices] IContentDownloadAuthroizationValidator downloadAuthorizer) { if (avatarEntryRepository == null) { throw new ArgumentNullException(nameof(avatarEntryRepository)); } //TODO: We want to rate limit access to this API //TODO: We should use both app logging but also another logging service that always gets hit //TODO: Consolidate this shared logic between controllers if (Logger.IsEnabled(LogLevel.Information)) { Logger.LogInformation($"Recieved {nameof(RequestAvatarDownloadUrl)} request from {ClaimsReader.GetUserName(User)}:{ClaimsReader.GetUserId(User)}."); } //TODO: We should probably check the flags of world to see if it's private (IE hidden from user). Or if it's unlisted or removed. //It's possible a user is requesting a world that doesn't exist //Could be malicious or it could have been deleted for whatever reason if (!await avatarEntryRepository.ContainsAsync(avatarId).ConfigureAwait(false)) { return(Json(new ContentDownloadURLResponse(ContentDownloadURLResponseCode.NoContentId))); } //TODO: Refactor this into a validation dependency //Now we need to do some validation to determine if they should even be downloading this world //we do not want people downloading a world they have no business of going to int userId = ClaimsReader.GetUserIdInt(User); if (!await downloadAuthorizer.CanUserAccessWorldContet(userId, avatarId)) { return(Json(new ContentDownloadURLResponse(ContentDownloadURLResponseCode.AuthorizationFailed))); } //We can get the URL from the urlbuilder if we provide the world storage GUID string downloadUrl = await urlBuilder.BuildRetrivalUrl(UserContentType.Avatar, (await avatarEntryRepository.RetrieveAsync(avatarId)).StorageGuid); //TODO: Should we be validating S3 availability? if (String.IsNullOrEmpty(downloadUrl)) { if (Logger.IsEnabled(LogLevel.Error)) { Logger.LogError($"Failed to create avatar upload URL for {ClaimsReader.GetUserName(User)}:{ClaimsReader.GetUserId(User)} with ID: {avatarId}."); } return(Json(new ContentDownloadURLResponse(ContentDownloadURLResponseCode.ContentDownloadServiceUnavailable))); } if (Logger.IsEnabled(LogLevel.Information)) { Logger.LogInformation($"Success. Sending {ClaimsReader.GetUserName(User)} URL: {downloadUrl}"); } return(Json(new ContentDownloadURLResponse(downloadUrl))); }