Exemplo n.º 1
0
        /// <summary>
        /// Accept an incoming webhook request and convert it into a TurnContext which can be processed by the bot's logic.
        /// </summary>
        /// <param name="request">The incoming HTTP request.</param>
        /// <param name="response">When this method completes, the HTTP response to send.</param>
        /// <param name="bot">The bot that will handle the incoming activity.</param>
        /// <param name="cancellationToken">A cancellation token for the task.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public async Task ProcessAsync(HttpRequest request, HttpResponse response, IBot bot, CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

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

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

            string body;

            Activity activity = null;

            using (var sr = new StreamReader(request.Body))
            {
                body = await sr.ReadToEndAsync().ConfigureAwait(false);
            }

            if (!_slackClient.VerifySignature(request, body))
            {
                const string text = "Rejected due to mismatched header signature";
                await SlackHelper.WriteAsync(response, HttpStatusCode.Unauthorized, text, Encoding.UTF8, cancellationToken).ConfigureAwait(false);

                throw new Exception(text);
            }

            var requestContentType = request.Headers["Content-Type"].ToString();

            if (requestContentType == "application/x-www-form-urlencoded")
            {
                var postValues = SlackHelper.QueryStringToDictionary(body);

                if (postValues.ContainsKey("payload"))
                {
                    var payload = JsonConvert.DeserializeObject <InteractionPayload>(postValues["payload"]);
                    activity = SlackHelper.PayloadToActivity(payload);
                }
                else if (postValues.ContainsKey("command"))
                {
                    var serializedPayload = JsonConvert.SerializeObject(postValues);
                    var payload           = JsonConvert.DeserializeObject <CommandPayload>(serializedPayload);
                    activity = await SlackHelper.CommandToActivityAsync(payload, _slackClient, cancellationToken).ConfigureAwait(false);
                }
            }
            else if (requestContentType == "application/json")
            {
                var bodyObject = JObject.Parse(body);

                if (bodyObject["type"]?.ToString() == "url_verification")
                {
                    var verificationEvent = bodyObject.ToObject <UrlVerificationEvent>();
                    await SlackHelper.WriteAsync(response, HttpStatusCode.OK, verificationEvent.Challenge, Encoding.UTF8, cancellationToken).ConfigureAwait(false);

                    return;
                }

                if (!string.IsNullOrWhiteSpace(_slackClient.Options.SlackVerificationToken) && bodyObject["token"]?.ToString() != _slackClient.Options.SlackVerificationToken)
                {
                    var text = $"Rejected due to mismatched verificationToken:{bodyObject["token"]}";
                    await SlackHelper.WriteAsync(response, HttpStatusCode.Forbidden, text, Encoding.UTF8, cancellationToken).ConfigureAwait(false);

                    throw new Exception(text);
                }

                if (bodyObject["type"]?.ToString() == "event_callback")
                {
                    // this is an event api post
                    var eventRequest = bodyObject.ToObject <EventRequest>();
                    activity = await SlackHelper.EventToActivityAsync(eventRequest, _slackClient, cancellationToken).ConfigureAwait(false);
                }
            }

            // As per official Slack API docs, some additional request types may be receieved that can be ignored
            // but we should respond with a 200 status code
            // https://api.slack.com/interactivity/slash-commands
            if (activity == null)
            {
                await SlackHelper.WriteAsync(response, HttpStatusCode.OK, "Unable to transform request / payload into Activity. Possible unrecognized request type", Encoding.UTF8, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                using (var context = new TurnContext(this, activity))
                {
                    context.TurnState.Add("httpStatus", ((int)HttpStatusCode.OK).ToString(System.Globalization.CultureInfo.InvariantCulture));

                    await RunPipelineAsync(context, bot.OnTurnAsync, cancellationToken).ConfigureAwait(false);

                    var code       = Convert.ToInt32(context.TurnState.Get <string>("httpStatus"), System.Globalization.CultureInfo.InvariantCulture);
                    var statusCode = (HttpStatusCode)code;
                    var text       = context.TurnState.Get <object>("httpBody") != null?context.TurnState.Get <object>("httpBody").ToString() : string.Empty;

                    await SlackHelper.WriteAsync(response, statusCode, text, Encoding.UTF8, cancellationToken).ConfigureAwait(false);
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Accept an incoming webhook request and convert it into a TurnContext which can be processed by the bot's logic.
        /// </summary>
        /// <param name="request">The incoming HTTP request.</param>
        /// <param name="response">When this method completes, the HTTP response to send.</param>
        /// <param name="bot">The bot that will handle the incoming activity.</param>
        /// <param name="cancellationToken">A cancellation token for the task.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public async Task ProcessAsync(HttpRequest request, HttpResponse response, IBot bot, CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

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

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

            string body;

            using (var sr = new StreamReader(request.Body))
            {
                body = await sr.ReadToEndAsync().ConfigureAwait(false);
            }

            var slackBody = SlackHelper.DeserializeBody(body);

            if (slackBody.Type == "url_verification")
            {
                var text = slackBody.Challenge;

                await SlackHelper.WriteAsync(response, HttpStatusCode.OK, text, Encoding.UTF8, cancellationToken).ConfigureAwait(false);

                return;
            }

            if (!_slackClient.VerifySignature(request, body))
            {
                const string text = "Rejected due to mismatched header signature";

                await SlackHelper.WriteAsync(response, HttpStatusCode.Unauthorized, text, Encoding.UTF8, cancellationToken).ConfigureAwait(false);

                throw new Exception(text);
            }

            if (!string.IsNullOrWhiteSpace(_slackClient.Options.SlackVerificationToken) && slackBody.Token != _slackClient.Options.SlackVerificationToken)
            {
                var text = $"Rejected due to mismatched verificationToken:{slackBody}";

                await SlackHelper.WriteAsync(response, HttpStatusCode.Forbidden, text, Encoding.UTF8, cancellationToken).ConfigureAwait(false);

                throw new Exception(text);
            }

            Activity activity;

            if (slackBody.Payload != null)
            {
                // handle interactive_message callbacks and block_actions
                activity = SlackHelper.PayloadToActivity(slackBody.Payload);
            }
            else if (slackBody.Type == "event_callback")
            {
                // this is an event api post
                activity = await SlackHelper.EventToActivityAsync(slackBody.Event, _slackClient, cancellationToken).ConfigureAwait(false);
            }
            else if (slackBody.Command != null)
            {
                activity = await SlackHelper.CommandToActivityAsync(slackBody, _slackClient, cancellationToken).ConfigureAwait(false);
            }
            else
            {
                throw new Exception($"Unknown Slack event type {slackBody.Type}");
            }

            using (var context = new TurnContext(this, activity))
            {
                context.TurnState.Add("httpStatus", ((int)HttpStatusCode.OK).ToString(System.Globalization.CultureInfo.InvariantCulture));

                await RunPipelineAsync(context, bot.OnTurnAsync, cancellationToken).ConfigureAwait(false);

                var code       = Convert.ToInt32(context.TurnState.Get <string>("httpStatus"), System.Globalization.CultureInfo.InvariantCulture);
                var statusCode = (HttpStatusCode)code;
                var text       = context.TurnState.Get <object>("httpBody") != null?context.TurnState.Get <object>("httpBody").ToString() : string.Empty;

                await SlackHelper.WriteAsync(response, statusCode, text, Encoding.UTF8, cancellationToken).ConfigureAwait(false);
            }
        }