Пример #1
0
        public async Task <bool> ValidateCipherAttachmentFile(Cipher cipher, CipherAttachment.MetaData attachmentData)
        {
            var(valid, realSize) = await _attachmentStorageService.ValidateFileAsync(cipher, attachmentData, _fileSizeLeeway);

            if (!valid || realSize > MAX_FILE_SIZE)
            {
                // File reported differs in size from that promised. Must be a rogue client. Delete Send
                await DeleteAttachmentAsync(cipher, attachmentData);

                return(false);
            }
            // Update Send data if necessary
            if (realSize != attachmentData.Size)
            {
                attachmentData.Size = realSize.Value;
            }
            attachmentData.Validated = true;

            var updatedAttachment = new CipherAttachment
            {
                Id             = cipher.Id,
                UserId         = cipher.UserId,
                OrganizationId = cipher.OrganizationId,
                AttachmentId   = attachmentData.AttachmentId,
                AttachmentData = JsonConvert.SerializeObject(attachmentData)
            };


            await _cipherRepository.UpdateAttachmentAsync(updatedAttachment);

            return(valid);
        }
Пример #2
0
        public async Task UpdateAttachmentAsync(CipherAttachment attachment)
        {
            using (var scope = ServiceScopeFactory.CreateScope())
            {
                var dbContext = GetDatabaseContext(scope);
                var cipher    = await dbContext.Ciphers.FindAsync(attachment.Id);

                var attachmentsJson = string.IsNullOrWhiteSpace(cipher.Attachments) ? new JObject() : JObject.Parse(cipher.Attachments);
                attachmentsJson.Add(attachment.AttachmentId, attachment.AttachmentData);
                cipher.Attachments = JsonConvert.SerializeObject(attachmentsJson);
                await dbContext.SaveChangesAsync();

                if (attachment.OrganizationId.HasValue)
                {
                    await OrganizationUpdateStorage(cipher.OrganizationId.Value);
                    await UserBumpAccountRevisionDateByCipherId(new List <Cipher> {
                        cipher
                    });
                }
                else if (attachment.UserId.HasValue)
                {
                    await UserUpdateStorage(attachment.UserId.Value);
                    await UserBumpAccountRevisionDate(attachment.UserId.Value);
                }
            }
        }
Пример #3
0
        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);
        }
Пример #4
0
 public async Task UpdateAttachmentAsync(CipherAttachment attachment)
 {
     using (var connection = new SqlConnection(ConnectionString))
     {
         var results = await connection.ExecuteAsync(
             $"[{Schema}].[Cipher_UpdateAttachment]",
             attachment,
             commandType : CommandType.StoredProcedure);
     }
 }
Пример #5
0
        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);
        }
Пример #6
0
        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);
        }
Пример #7
0
        public async Task CreateAttachmentShareAsync(Cipher cipher, Stream stream, long requestLength,
                                                     string attachmentId, Guid organizationId)
        {
            try
            {
                if (requestLength < 1)
                {
                    throw new BadRequestException("No data to attach.");
                }

                if (cipher.Id == default(Guid))
                {
                    throw new BadRequestException(nameof(cipher.Id));
                }

                if (cipher.OrganizationId.HasValue)
                {
                    throw new BadRequestException("Cipher belongs to an organization already.");
                }

                var org = await _organizationRepository.GetByIdAsync(organizationId);

                if (org == null || !org.MaxStorageGb.HasValue)
                {
                    throw new BadRequestException("This organization cannot use attachments.");
                }

                var storageBytesRemaining = org.StorageBytesRemaining();
                if (storageBytesRemaining < requestLength)
                {
                    throw new BadRequestException("Not enough storage available for this organization.");
                }

                var attachments = cipher.GetAttachments();
                if (!attachments.ContainsKey(attachmentId))
                {
                    throw new BadRequestException($"Cipher does not own specified attachment");
                }

                await _attachmentStorageService.UploadShareAttachmentAsync(stream, cipher.Id, organizationId,
                                                                           attachments[attachmentId]);

                // Previous call may alter metadata
                var updatedAttachment = new CipherAttachment
                {
                    Id             = cipher.Id,
                    UserId         = cipher.UserId,
                    OrganizationId = cipher.OrganizationId,
                    AttachmentId   = attachmentId,
                    AttachmentData = JsonConvert.SerializeObject(attachments[attachmentId])
                };

                await _cipherRepository.UpdateAttachmentAsync(updatedAttachment);
            }
            catch
            {
                await _attachmentStorageService.CleanupAsync(cipher.Id);

                throw;
            }
        }