Ejemplo n.º 1
0
        public sealed override async Task <InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (encoding == null)
            {
                throw new ArgumentNullException(nameof(encoding));
            }

            var httpContext = context.HttpContext;
            var inputStream = GetInputStream(httpContext, encoding);

            object model;

            try
            {
                model = await Serialization.Serializer.Json.DeserializeAsync(inputStream, context.ModelType);
            }
            catch (JsonException exception)
            {
                var path = exception.Path;
                var formatterException = new InputFormatterException(exception.Message, exception);

                context.ModelState.TryAddModelError(path, formatterException, context.Metadata);
                return(InputFormatterResult.Failure());
            }
            catch (Exception exception) when(exception is FormatException || exception is OverflowException)
            {
                context.ModelState.TryAddModelError(string.Empty, exception, context.Metadata);
                return(InputFormatterResult.Failure());
            }
            finally
            {
                if (inputStream is TranscodingReadStream transcoding)
                {
                    await transcoding.DisposeAsync();
                }
            }

            if (model == null && !context.TreatEmptyInputAsDefaultValue)
            {
                return(InputFormatterResult.NoValue());
            }
            else
            {
                return(InputFormatterResult.Success(model));
            }
        }
Ejemplo n.º 2
0
    public override async Task <InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
    {
        ArgumentNullException.ThrowIfNull(context);
        ArgumentNullException.ThrowIfNull(encoding);

        object?model;
        var    httpContext    = context.HttpContext;
        var    registeredType = context.ModelType.GenericTypeArguments.FirstOrDefault();

        if (registeredType == null || !_typeRepository.TryGet(registeredType, out var targetType))
        {
            return(InputFormatterResult.Failure());
        }
        var(inputStream, usesTranscodingStream) = GetInputStream(httpContext, encoding);
        try
        {
            model = await JsonSerializer.DeserializeAsync(inputStream, targetType, SerializerOptions);
        }
        catch (JsonException jsonException)
        {
            var path = jsonException.Path ?? string.Empty;
            var formatterException = new InputFormatterException(jsonException.Message, jsonException);
            context.ModelState.TryAddModelError(path, formatterException, context.Metadata);
            return(InputFormatterResult.Failure());
        }
        finally
        {
            if (usesTranscodingStream)
            {
                await inputStream.DisposeAsync();
            }
        }

        if (model == null && !context.TreatEmptyInputAsDefaultValue)
        {
            return(InputFormatterResult.NoValue());
        }

        return(InputFormatterResult.Success(model));
    }
Ejemplo n.º 3
0
        public sealed override async Task <InputFormatterResult> ReadRequestBodyAsync(
            InputFormatterContext context,
            Encoding encoding)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (encoding == null)
            {
                throw new ArgumentNullException(nameof(encoding));
            }

            if (encoding.CodePage != Encoding.UTF8.CodePage)
            {
                throw new NotSupportedException(encoding.EncodingName);
            }

            var httpContext = context.HttpContext;
            var inputStream = httpContext.Request.Body;

            if (context is FromBodyPropertyInputFormatterContext bodyPropertyContext)
            {
                Func <Func <Stream, JsonSerializerOptions, Task>, Task> readRequestBody = async(readAction) => {
                    await readAction(inputStream, SerializerOptions);
                };

                var result = await bodyPropertyContext.ReadAsync(readRequestBody, encoding);

                if (result.success)
                {
                    if (result.noValue && !context.TreatEmptyInputAsDefaultValue)
                    {
                        // Some nonempty inputs might deserialize as null, for example whitespace,
                        // or the JSON-encoded value "null". The upstream BodyModelBinder needs to
                        // be notified that we don't regard this as a real input so it can register
                        // a model binding error.
                        return(InputFormatterResult.NoValue());
                    }
                    Log.JsonInputSuccess(_logger, context.ModelType);
                    return(InputFormatterResult.Success(result.model));
                }
                else if (result.exception is JsonException jsonException)
                {
                    var path = jsonException.Path;

                    var formatterException = new InputFormatterException(jsonException.Message, jsonException);

                    context.ModelState.TryAddModelError(path, formatterException, context.Metadata);

                    Log.JsonInputException(_logger, jsonException);

                    return(InputFormatterResult.Failure());
                }
                else
                {
                    var ex = result.exception ?? new Exception("Failed to read model");
                    throw ex;
                }
            }
            else
            {
                object model;
                try {
                    model = await JsonSerializer.DeserializeAsync(inputStream, context.ModelType, SerializerOptions);
                }
                catch (JsonException jsonException) {
                    var path = jsonException.Path;

                    var formatterException = new InputFormatterException(jsonException.Message, jsonException);

                    context.ModelState.TryAddModelError(path, formatterException, context.Metadata);

                    Log.JsonInputException(_logger, jsonException);

                    return(InputFormatterResult.Failure());
                }

                if (model == null && !context.TreatEmptyInputAsDefaultValue)
                {
                    // Some nonempty inputs might deserialize as null, for example whitespace,
                    // or the JSON-encoded value "null". The upstream BodyModelBinder needs to
                    // be notified that we don't regard this as a real input so it can register
                    // a model binding error.
                    return(InputFormatterResult.NoValue());
                }
                else
                {
                    Log.JsonInputSuccess(_logger, context.ModelType);
                    return(InputFormatterResult.Success(model));
                }
            }
        }
        /// <inheritdoc />
        public sealed override async Task <InputFormatterResult> ReadRequestBodyAsync(
            InputFormatterContext context,
            Encoding encoding)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (encoding == null)
            {
                throw new ArgumentNullException(nameof(encoding));
            }

            var httpContext = context.HttpContext;
            var inputStream = httpContext.Request.Body;

            ApplicationPayload?model;

            try
            {
                using var inputStreamReader = new StreamReader(inputStream);

                var inputJsonString = await inputStreamReader.ReadToEndAsync();

                // Determine options name to use (in case multiple are registered)
                var options = httpContext.Request.RouteValues.TryGetValue(RouteKeyConstants.OptionsName, out object optionsName)
                        ? _options.Get(optionsName.ToString())
                        : _options.CurrentValue;

                // Verify signature
                if (options.ValidatePayloadSignature)
                {
                    if (!string.IsNullOrEmpty(options.EndpointSigningKey))
                    {
                        var secret = Encoding.ASCII.GetBytes(options.EndpointSigningKey);

                        var signatureBytes = Encoding.UTF8.GetBytes(context.HttpContext.Request.Headers[HeaderSpaceTimestamp] + ":" + inputJsonString);
                        using var hmSha1 = new HMACSHA256(secret);
                        var signatureHash   = hmSha1.ComputeHash(signatureBytes);
                        var signatureString = ToHexString(signatureHash);
                        if (!signatureString.Equals(context.HttpContext.Request.Headers[HeaderSpaceSignature]))
                        {
                            throw new InvalidOperationException("The webhook signature does not match the webhook payload. Make sure the endpoint signing key is configured correctly in your Space organization, and the current application.");
                        }
                    }
                    else
                    {
                        _logger.LogWarning(nameof(SpaceWebHookOptions.ValidatePayloadSignature) + " is enabled, but no " + nameof(SpaceWebHookOptions.EndpointSigningKey) + " is configured. Skipping payload signature validation.");
                    }
                }

                // Deserialize model
                model = JsonSerializer.Deserialize(inputJsonString, context.ModelType, _jsonSerializerOptions) as ApplicationPayload;
                if (model != null)
                {
                    PropagatePropertyAccessPathHelper.SetAccessPathForValue(string.Empty, false, model);
                }

                // Verify payload
                if (options.ValidatePayloadVerificationToken)
                {
                    var payloadVerificationTokenValue = GetPayloadVerificationTokenValue(model);
                    if (!string.IsNullOrEmpty(payloadVerificationTokenValue))
                    {
                        if (payloadVerificationTokenValue != options.EndpointVerificationToken)
                        {
                            throw new InvalidOperationException(
                                      "The webhook verification token does not your configured verification token. Make sure the endpoint verification token is configured correctly in your Space organization, and the current application.");
                        }
                    }
                    else
                    {
                        _logger.LogWarning(nameof(SpaceWebHookOptions.ValidatePayloadVerificationToken) + " is enabled, but no " + nameof(SpaceWebHookOptions.EndpointVerificationToken) + " is configured. Skipping verification token validation.");
                    }
                }
            }
            catch (JsonException jsonException)
            {
                var path = jsonException.Path;

                var formatterException = new InputFormatterException(jsonException.Message, jsonException);
                context.ModelState.TryAddModelError(path, formatterException, context.Metadata);

                Log.JsonInputException(_logger, jsonException);

                return(await InputFormatterResult.FailureAsync());
            }
            catch (Exception exception) when(exception is FormatException || exception is OverflowException)
            {
                context.ModelState.TryAddModelError(string.Empty, exception, context.Metadata);

                Log.JsonInputException(_logger, exception);

                return(await InputFormatterResult.FailureAsync());
            }

            if (model == null && !context.TreatEmptyInputAsDefaultValue)
            {
                return(await InputFormatterResult.NoValueAsync());
            }

            Log.JsonInputSuccess(_logger, context.ModelType);

            return(await InputFormatterResult.SuccessAsync(model));
        }