예제 #1
0
    private async Task StoreDataAsync(FileIdentifier id, Stream dataStream, UploadPassword passwordSetting, CancellationToken cancellationToken)
    {
        UploadProgress progress = this.GetProgressObject(id);

        // Copy with progress
        using (Stream outputStream = this._fileWriter.OpenWriteStream(this._fileStore.GetDataFile(id))) {
            if (passwordSetting.Enable == true && !String.IsNullOrEmpty(passwordSetting.Password))
            {
                using (Aes crypto = CryptoFactory.CreateCrypto(passwordSetting.Password)) {
                    ICryptoTransform encryptor = crypto.CreateEncryptor();

                    CryptoMetadata.WriteMetadata(outputStream, crypto);

                    using (CryptoStream cryptoStream = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write, true)) {
                        await CopyStreamWithProgress(cryptoStream);
                    }
                }
            }
            else
            {
                await CopyStreamWithProgress(outputStream);
            }
        }

        async Task CopyStreamWithProgress(Stream outputStream)
        {
            using (Stream inputStream = dataStream) {
                int    read;
                byte[] buffer = new byte[4096];
                while ((read = await inputStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
                {
                    progress.Current += read;

                    await outputStream.WriteAsync(buffer, 0, read, cancellationToken).ConfigureAwait(false);
                }
            }
        }
    }
예제 #2
0
    private async Task ProcessFormSectionAsync(UploadContext uploadContext, MultipartSection section, ContentDispositionHeaderValue contentDisposition)
    {
        string cleanName = HeaderUtilities.RemoveQuotes(contentDisposition.Name).Value;

        StoredMetadataFactory metadataFactory = uploadContext.MetadataFactory;
        UploadPassword        passwordSetting = uploadContext.PasswordSetting;

        switch (cleanName)
        {
        case nameof(UploadModel.IsReservation):
            string isReservationRaw = await ReadString();

            metadataFactory.SetIsReservation(Boolean.Parse(isReservationRaw));
            break;

        case nameof(UploadModel.Expiration):
            string dateTimeRaw = await ReadString();

            // MVC we send date as roundtrip
            metadataFactory.SetExpiration(DateTime.ParseExact(dateTimeRaw, "o", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind));
            return;

        case nameof(UploadModel.FileIdentifier):
            string rawId = await ReadString();

            FileIdentifier formId = FileIdentifier.FromString(rawId);

            if (formId != uploadContext.Identifier)
            {
                throw new InvalidOperationException($"ID mismatch: '{formId}' (received) != '{uploadContext.Identifier}' (expected)");
            }
            return;

        case nameof(UploadModel.Password):
            string password = await ReadString();

            metadataFactory.SetPassword(password);
            passwordSetting.Password = password;

            EnsureFileNotUploaded();
            return;

        case nameof(UploadModel.EnablePasswordProtection):
            bool passwordSettingWasSet = passwordSetting.IsSet;

            string enablePasswordProtectionRaw = await ReadString();

            bool enablePasswordProtection = String.Equals(Boolean.TrueString, enablePasswordProtectionRaw, StringComparison.OrdinalIgnoreCase);
            metadataFactory.SetEnablePasswordProtection(enablePasswordProtection);
            passwordSetting.SetEnabled(enablePasswordProtection);

            if (!passwordSettingWasSet)
            {
                EnsureFileNotUploaded();
            }
            return;

        case nameof(UploadModel.Sender) + "." + nameof(ContactInformation.Name):
            string name = await ReadString();

            metadataFactory.SetSenderName(name);
            return;

        case nameof(UploadModel.Sender) + "." + nameof(ContactInformation.EmailAddress):
            string emailAddress = await ReadString();

            metadataFactory.SetSenderEmail(emailAddress);
            return;

        // Browsers don't actually send the file size in the request, but we can derive it from the Content-Length.
        // However, that is not very accurate and if we use some javascript to send a more accurate file size, we use that.
        case nameof(UploadModel.SuggestedFileSize):
            if (Int64.TryParse(await ReadString(), out var size) && size > 0)
            {
                this.GetProgressObject(uploadContext.Identifier).Total = size;
            }
            return;

        default:
            this._logger.LogWarning(LogEvents.UploadIncomplete, "{Identifier}: Unknown form field '{Field}'", uploadContext.Identifier, contentDisposition.Name);
            break;
        }

        async Task <string> ReadString()
        {
            using (StreamReader sr = new StreamReader(section.Body)) {
                return(await sr.ReadToEndAsync());
            }
        }

        void EnsureFileNotUploaded()
        {
            bool needToValidate = !String.IsNullOrEmpty(passwordSetting.Password) && passwordSetting.Enable == true;

            if (needToValidate && uploadContext.HasUploadedFile)
            {
                this._logger.LogError(LogEvents.UploadPasswordAfterFileUpload, "{Identifier}: The upload password is set after the file is uploaded. The file is not encrypted. Terminating upload.", uploadContext.Identifier);

                throw new UploadCryptoArgumentOrderException("File uploaded before password has been set");
            }
        }
    }