public async Task <IActionResult> Receive([FromBody] ApplicationPayload payload) { // Find handler if (!RouteData.Values.TryGetValue(RouteKeyConstants.HandlerType, out object t) || !(t is Type handlerType) || !(_serviceProvider.GetService(handlerType) is ISpaceWebHookHandler handler)) { return(BadRequest($"No registered {nameof(ISpaceWebHookHandler)} could be found.")); } // Handle payload switch (payload) { // List commands? case ListCommandsPayload listCommandsPayload: var commands = await handler.HandleListCommandsAsync(listCommandsPayload); PropagatePropertyAccessPathHelper.SetAccessPathForValue(string.Empty, false, commands); // ReSharper disable once ConstantNullCoalescingCondition commands.CommandsItems ??= new List <CommandDetail>(); return(new JsonResult(commands, JsonSerializerOptions)); // List menu extensions? case ListMenuExtensionsPayload listMenuExtensionsPayload: var menuExtensions = await handler.HandleListMenuExtensionsAsync(listMenuExtensionsPayload); PropagatePropertyAccessPathHelper.SetAccessPathForValue(string.Empty, false, menuExtensions); // ReSharper disable once ConstantNullCoalescingCondition menuExtensions.Extensions ??= new List <MenuExtensionDetail>(); return(new JsonResult(menuExtensions, JsonSerializerOptions)); // Message? case MessagePayload messagePayload: await handler.HandleMessageAsync(messagePayload); return(Ok()); // Action? case MessageActionPayload actionPayload: var actionResult = await handler.HandleMessageActionAsync(actionPayload); return(!string.IsNullOrEmpty(actionResult.Message) ? Content(actionResult.Message, "text/plain") as IActionResult : Ok()); // Menu action? case MenuActionPayload menuActionPayload: var menuActionResult = await handler.HandleMenuActionAsync(menuActionPayload); return(!string.IsNullOrEmpty(menuActionResult.Message) ? Content(menuActionResult.Message, "text/plain") as IActionResult : Ok()); } return(BadRequest("Payload is not supported.")); }
/// <summary> /// Sends a payload to a resource at a given URL. /// </summary> /// <param name="httpMethod">The HTTP method to use.</param> /// <param name="urlPath">The path to access the resource.</param> /// <param name="payload">The payload to send to the resource.</param> /// <param name="cancellationToken">The cancellation token to cancel operation.</param> /// <returns>The requested resource.</returns> /// <exception cref="ResourceException">Something went wrong accessing the resource.</exception> public async Task <TResult> RequestResourceAsync <TPayload, TResult>(string httpMethod, string urlPath, TPayload payload, CancellationToken cancellationToken = default) { var value = await RequestResourceInternalAsync <TPayload, TResult>(httpMethod, urlPath, payload, cancellationToken); PropagatePropertyAccessPathHelper.SetAccessPathForValue(typeof(TResult).Name, true, value); return(value); }
public override IClassNameConvertible Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.Null) { return(null); } var readerAtStart = reader; using var jsonDocument = JsonDocument.ParseValue(ref reader); var jsonObject = jsonDocument.RootElement; var className = jsonObject.GetStringValue("className"); if (!string.IsNullOrEmpty(className)) { if (!TypeMap.TryGetValue(className, out var targetType)) { targetType = Type.GetType(SpaceDotNetClientNamespace + "." + CSharpIdentifier.ForClassOrNamespace(className) + ", " + SpaceDotNetClientAssemblyName); if (targetType != null) { TypeMap[className] = targetType; } } if (targetType != null && typeof(IClassNameConvertible).IsAssignableFrom(targetType)) { var value = JsonSerializer.Deserialize(ref readerAtStart, targetType, options) as IClassNameConvertible; PropagatePropertyAccessPathHelper.SetAccessPathForValue(targetType.Name, true, value); return(value); } } return(null); }
/// <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)); }