private async Task <DocumentFile> BuildFromFileAsync(IFormFile file)
        {
            // detect image dimensions
            string dimensions = null;

            try
            {
                using (Stream fileStream = file.OpenReadStream())
                    using (Image image = Image.FromStream(fileStream, false, true))
                        dimensions = $"{image.Width},{image.Height}";
            }
            catch { }

            // copy file
            FileInfo fileInfo = new FileInfo(_settings.BuildFilePath(GenerateUniqueFileName()));

            // copy in resources folder
            using (var stream = new FileStream(fileInfo.FullName, FileMode.Create))
                await file.CopyToAsync(stream);

            // encrypt file
            string iv = Guid.NewGuid().ToString().AsSpan(0, 16).ToString();

            byte[] cipher = _cryptographyService.Encrypt(await File.ReadAllBytesAsync(fileInfo.FullName), Encoding.UTF8.GetBytes(_settings.EncryptKey), Encoding.UTF8.GetBytes(iv));
            await File.WriteAllBytesAsync(fileInfo.FullName, cipher);

            // create document file
            DocumentFile result = new DocumentFile
            {
                OriginalName = file.FileName,
                Path         = fileInfo.Name,
                Encryption   = _cryptographyService.Name,
                IV           = iv,
                Size         = fileInfo.Length,
                Dimensions   = dimensions,
                MimeType     = file.ContentType,
            };

            return(result);
        }
        public async Task <DownloadDocumentResponse> Handle(DownloadDocumentByIdQuery query, CancellationToken cancellationToken)
        {
            Document document = await _documentRepository.FindByIdWithFileAsync(query.Id);

            if (document == null)
            {
                throw new ApiProblemDetailsException($"Record with id: {query.Id} does not exist.", StatusCodes.Status404NotFound);
            }
            if (document.CreatedBy != _authenticatedUser.UserId)
            {
                throw new ApiProblemDetailsException($"You are not authorized to access this resource.", StatusCodes.Status403Forbidden);
            }

            // data
            DocumentFile documentFile = document.File;
            FileInfo     fileInfo     = new FileInfo(_settings.BuildFilePath(documentFile.Path));

            // check if document is still valid
            if (documentFile == null || !fileInfo.Exists)
            {
                throw new ApiProblemDetailsException($"Record with id: {query.Id} does contain file.", StatusCodes.Status404NotFound);
            }

            // decrypt
            string iv = documentFile.IV;

            byte[] decrypted = _cryptographyService.Decrypt(await File.ReadAllBytesAsync(fileInfo.FullName), Encoding.UTF8.GetBytes(_settings.EncryptKey), Encoding.UTF8.GetBytes(iv));

            // response
            return(new DownloadDocumentResponse
            {
                Id = query.Id,
                Name = documentFile.OriginalName,
                ContentType = documentFile.MimeType,
                FileContent = decrypted,
            });
        }