public async Task <(string attachmentId, string uploadUrl)> CreateAttachmentForDelayedUploadAsync(Cipher cipher, AttachmentRequestModel request, Guid savingUserId) { await ValidateCipherEditForAttachmentAsync(cipher, savingUserId, request.AdminRequest, request.FileSize); var attachmentId = Utilities.CoreHelpers.SecureRandomString(32, upper: false, special: false); var data = new CipherAttachment.MetaData { AttachmentId = attachmentId, FileName = request.FileName, Key = request.Key, Size = request.FileSize, Validated = false, }; var uploadUrl = await _attachmentStorageService.GetAttachmentUploadUrlAsync(cipher, data); await _cipherRepository.UpdateAttachmentAsync(new CipherAttachment { Id = cipher.Id, UserId = cipher.UserId, OrganizationId = cipher.OrganizationId, AttachmentId = attachmentId, AttachmentData = JsonConvert.SerializeObject(data) }); cipher.AddAttachment(attachmentId, data); await _pushService.PushSyncCipherUpdateAsync(cipher, null); return(attachmentId, uploadUrl); }
public async Task CreateAttachmentAsync(Cipher cipher, Stream stream, string fileName, string key, long requestLength, Guid savingUserId, bool orgAdmin = false) { if (!orgAdmin && !(await UserCanEditAsync(cipher, savingUserId))) { throw new BadRequestException("You do not have permissions to edit this."); } if (requestLength < 1) { throw new BadRequestException("No data to attach."); } var storageBytesRemaining = 10240L; if (storageBytesRemaining < requestLength) { throw new BadRequestException("Not enough storage available."); } var attachmentId = Utilities.CoreHelpers.SecureRandomString(32, upper: false, special: false); await _attachmentStorageService.UploadNewAttachmentAsync(stream, cipher, attachmentId); try { var data = new CipherAttachment.MetaData { FileName = fileName, Key = key, Size = stream.Length }; var attachment = new CipherAttachment { Id = cipher.Id, UserId = cipher.UserId, OrganizationId = cipher.OrganizationId, AttachmentId = attachmentId, AttachmentData = JsonConvert.SerializeObject(data) }; await _cipherRepository.UpdateAttachmentAsync(attachment); await _eventService.LogCipherEventAsync(cipher, Enums.EventType.Cipher_AttachmentCreated); cipher.AddAttachment(attachmentId, data); } catch { // Clean up since this is not transactional await _attachmentStorageService.DeleteAttachmentAsync(cipher.Id, attachmentId); throw; } // push await _pushService.PushSyncCipherUpdateAsync(cipher, null); }
public async Task CreateAttachmentAsync(Cipher cipher, Stream stream, string fileName, string key, long requestLength, Guid savingUserId, bool orgAdmin = false) { await ValidateCipherEditForAttachmentAsync(cipher, savingUserId, orgAdmin, requestLength); var attachmentId = Utilities.CoreHelpers.SecureRandomString(32, upper: false, special: false); var data = new CipherAttachment.MetaData { AttachmentId = attachmentId, FileName = fileName, Key = key, }; await _attachmentStorageService.UploadNewAttachmentAsync(stream, cipher, data); // Must read stream length after it has been saved, otherwise it's 0 data.Size = stream.Length; try { var attachment = new CipherAttachment { Id = cipher.Id, UserId = cipher.UserId, OrganizationId = cipher.OrganizationId, AttachmentId = attachmentId, AttachmentData = JsonConvert.SerializeObject(data) }; await _cipherRepository.UpdateAttachmentAsync(attachment); await _eventService.LogCipherEventAsync(cipher, Enums.EventType.Cipher_AttachmentCreated); cipher.AddAttachment(attachmentId, data); if (!await ValidateCipherAttachmentFile(cipher, data)) { throw new Exception("Content-Length does not match uploaded file size"); } } catch { // Clean up since this is not transactional await _attachmentStorageService.DeleteAttachmentAsync(cipher.Id, data); throw; } // push await _pushService.PushSyncCipherUpdateAsync(cipher, null); }
public async Task CreateAttachmentAsync(Cipher cipher, Stream stream, string fileName, long requestLength, Guid savingUserId, bool orgAdmin = false) { if (!orgAdmin && !(await UserCanEditAsync(cipher, savingUserId))) { throw new BadRequestException("You do not have permissions to edit this."); } if (requestLength < 1) { throw new BadRequestException("No data to attach."); } var storageBytesRemaining = 0L; if (cipher.UserId.HasValue) { var user = await _userRepository.GetByIdAsync(cipher.UserId.Value); if (!(await _userService.CanAccessPremium(user))) { throw new BadRequestException("You must have premium status to use attachments."); } if (user.Premium) { storageBytesRemaining = user.StorageBytesRemaining(); } else { // Users that get access to file storage/premium from their organization get the default // 1 GB max storage. storageBytesRemaining = user.StorageBytesRemaining( _globalSettings.SelfHosted ? (short)1024 : (short)1); } } else if (cipher.OrganizationId.HasValue) { var org = await _organizationRepository.GetByIdAsync(cipher.OrganizationId.Value); if (!org.MaxStorageGb.HasValue) { throw new BadRequestException("This organization cannot use attachments."); } storageBytesRemaining = org.StorageBytesRemaining(); } if (storageBytesRemaining < requestLength) { throw new BadRequestException("Not enough storage available."); } var attachmentId = Utilities.CoreHelpers.SecureRandomString(32, upper: false, special: false); await _attachmentStorageService.UploadNewAttachmentAsync(stream, cipher, attachmentId); try { var data = new CipherAttachment.MetaData { FileName = fileName, Size = stream.Length }; var attachment = new CipherAttachment { Id = cipher.Id, UserId = cipher.UserId, OrganizationId = cipher.OrganizationId, AttachmentId = attachmentId, AttachmentData = JsonConvert.SerializeObject(data) }; await _cipherRepository.UpdateAttachmentAsync(attachment); await _eventService.LogCipherEventAsync(cipher, Enums.EventType.Cipher_AttachmentCreated); cipher.AddAttachment(attachmentId, data); } catch { // Clean up since this is not transactional await _attachmentStorageService.DeleteAttachmentAsync(cipher.Id, attachmentId); throw; } // push await _pushService.PushSyncCipherUpdateAsync(cipher, null); }