/// <summary>
        /// Verifies the verify token from the message. If the token matches the one configured, sends back the challenge.
        /// </summary>
        /// <param name="request">Represents the incoming side of an HTTP request.</param>
        /// <param name="response">Represents the outgoing side of an HTTP request.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A task that represents the work queued to execute.</returns>
        /// <exception cref="ArgumentNullException"><paramref name="request"/> or <paramref name="response"/> is null.</exception>
        public virtual async Task VerifyWebhookAsync(HttpRequest request, HttpResponse response, CancellationToken cancellationToken)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

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

            var            challenge = string.Empty;
            HttpStatusCode statusCode;

            if (request.Query["hub.verify_token"].Equals(_options.FacebookVerifyToken))
            {
                challenge  = request.Query["hub.challenge"];
                statusCode = HttpStatusCode.OK;
            }
            else
            {
                statusCode = HttpStatusCode.Unauthorized;
            }

            await FacebookHelper.WriteAsync(response, statusCode, challenge, Encoding.UTF8, cancellationToken).ConfigureAwait(false);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Standard BotBuilder adapter method to send a message from the bot to the messaging API.
        /// </summary>
        /// <param name="context">A TurnContext representing the current incoming message and environment.</param>
        /// <param name="activities">An array of outgoing activities to be sent back to the messaging API.</param>
        /// <param name="cancellationToken">A cancellation token for the task.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task <ResourceResponse[]> SendActivitiesAsync(ITurnContext context, Activity[] activities, CancellationToken cancellationToken)
        {
            var responses = new List <ResourceResponse>();

            foreach (var activity in activities)
            {
                if (activity.Type != ActivityTypes.Message)
                {
                    throw new Exception("Only Activities of type Message are supported for sending.");
                }

                var message = FacebookHelper.ActivityToFacebook(activity);

                if (message.Message.Attachment != null)
                {
                    message.Message.Attachments = null;
                    message.Message.Text        = null;
                }

                var res = await _facebookClient.SendMessageAsync("/me/messages", message, null, cancellationToken).ConfigureAwait(false);

                var response = new ResourceResponse()
                {
                    Id = res,
                };

                responses.Add(response);
            }

            return(responses.ToArray());
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Standard BotBuilder adapter method to send a message from the bot to the messaging API.
        /// </summary>
        /// <param name="turnContext">A TurnContext representing the current incoming message and environment.</param>
        /// <param name="activities">An array of outgoing activities to be sent back to the messaging API.</param>
        /// <param name="cancellationToken">A cancellation token for the task.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public override async Task <ResourceResponse[]> SendActivitiesAsync(ITurnContext turnContext, Activity[] activities, CancellationToken cancellationToken)
        {
            var responses = new List <ResourceResponse>();

            foreach (var activity in activities)
            {
                if (activity.Type != ActivityTypes.Message && activity.Type != ActivityTypes.Event)
                {
                    _logger.LogTrace($"Unsupported Activity Type: '{activity.Type}'. Only Activities of type 'Message' or 'Event' are supported.");
                }
                else
                {
                    var message = FacebookHelper.ActivityToFacebook(activity);

                    if (message.Message.Attachment != null)
                    {
                        message.Message.Text = null;
                    }

                    var res = await _facebookClient.SendMessageAsync("/me/messages", message, null, cancellationToken)
                              .ConfigureAwait(false);

                    if (activity.Type == ActivityTypes.Event)
                    {
                        if (activity.Name.Equals(HandoverConstants.PassThreadControl, StringComparison.Ordinal))
                        {
                            var recipient = (string)activity.Value == "inbox" ? HandoverConstants.PageInboxId : (string)activity.Value;
                            await _facebookClient.PassThreadControlAsync(recipient, activity.Conversation.Id, HandoverConstants.MetadataPassThreadControl).ConfigureAwait(false);
                        }
                        else if (activity.Name.Equals(HandoverConstants.TakeThreadControl, StringComparison.Ordinal))
                        {
                            await _facebookClient.TakeThreadControlAsync(activity.Conversation.Id, HandoverConstants.MetadataTakeThreadControl).ConfigureAwait(false);
                        }
                        else if (activity.Name.Equals(HandoverConstants.RequestThreadControl, StringComparison.Ordinal))
                        {
                            await _facebookClient.RequestThreadControlAsync(activity.Conversation.Id, HandoverConstants.MetadataRequestThreadControl).ConfigureAwait(false);
                        }
                    }

                    var response = new ResourceResponse()
                    {
                        Id = res,
                    };

                    responses.Add(response);
                }
            }

            return(responses.ToArray());
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Accepts an incoming webhook request, creates a turn context,
        /// and runs the middleware pipeline for an incoming TRUSTED activity.
        /// </summary>
        /// <param name="httpRequest">Represents the incoming side of an HTTP request.</param>
        /// <param name="httpResponse">Represents the outgoing side of an HTTP request.</param>
        /// <param name="bot">The code to run at the end of the adapter's middleware pipeline.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects
        /// or threads to receive notice of cancellation.</param>
        /// <returns>A task that represents the work queued to execute.</returns>
        /// <exception cref="AuthenticationException">The webhook receives message with invalid signature.</exception>
        public async Task ProcessAsync(HttpRequest httpRequest, HttpResponse httpResponse, IBot bot, CancellationToken cancellationToken = default)
        {
            if (httpRequest.Query["hub.mode"] == HubModeSubscribe && _options.VerifyIncomingRequests)
            {
                await _facebookClient.VerifyWebhookAsync(httpRequest, httpResponse, cancellationToken).ConfigureAwait(false);

                return;
            }

            string stringifiedBody;

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

            if (!_facebookClient.VerifySignature(httpRequest, stringifiedBody) && _options.VerifyIncomingRequests)
            {
                await FacebookHelper.WriteAsync(httpResponse, HttpStatusCode.Unauthorized, string.Empty, Encoding.UTF8, cancellationToken).ConfigureAwait(false);

                throw new AuthenticationException("Webhook received message with invalid signature. Potential malicious behavior!");
            }

            FacebookResponseEvent facebookResponseEvent = null;

            facebookResponseEvent = JsonConvert.DeserializeObject <FacebookResponseEvent>(stringifiedBody);

            foreach (var entry in facebookResponseEvent.Entry)
            {
                var payload = entry.Changes.Count > 0 ? entry.Changes : entry.Messaging.Count > 0 ? entry.Messaging : entry.Standby.Count > 0 ? entry.Standby : new List <FacebookMessage>();

                foreach (var message in payload)
                {
                    message.IsStandby = entry.Standby.Count > 0;

                    var activity = FacebookHelper.ProcessSingleMessage(message);

                    using (var context = new TurnContext(this, activity))
                    {
                        await RunPipelineAsync(context, bot.OnTurnAsync, cancellationToken).ConfigureAwait(false);
                    }
                }
            }
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Factory method to create the <see cref="FacebookMessage"/> instance of the <see cref="Activity"/> to be sent to Facebook.
 /// </summary>
 /// <remarks>
 /// This lets an override add a Facebook-supported message tag to an outgoing message.
 /// See https://developers.facebook.com/docs/messenger-platform/send-messages/message-tags/.
 /// </remarks>
 /// <param name="activity">An <see cref="Activity"/> instance to build the message.</param>
 /// <returns>A <see cref="FacebookMessage"/> built from the activity instance.</returns>
 protected virtual FacebookMessage CreateFacebookMessageFromActivity(Activity activity)
 {
     return(FacebookHelper.ActivityToFacebook(activity));
 }
Ejemplo n.º 6
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">A request object.</param>
        /// <param name="response">A response object.</param>
        /// <param name="bot">A bot logic function.</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.Query["hub.mode"] == HubModeSubscribe)
            {
                await _facebookClient.VerifyWebhookAsync(request, response, cancellationToken).ConfigureAwait(false);

                return;
            }

            string stringifyBody;

            using (var sr = new StreamReader(request.Body))
            {
                stringifyBody = sr.ReadToEnd();
            }

            if (!_facebookClient.VerifySignature(request, stringifyBody))
            {
                await FacebookHelper.WriteAsync(response, HttpStatusCode.Unauthorized, string.Empty, Encoding.UTF8, cancellationToken).ConfigureAwait(false);

                throw new Exception("WARNING: Webhook received message with invalid signature. Potential malicious behavior!");
            }

            FacebookResponseEvent facebookEvent = null;

            facebookEvent = JsonConvert.DeserializeObject <FacebookResponseEvent>(stringifyBody);

            foreach (var entry in facebookEvent.Entry)
            {
                var payload = new List <FacebookMessage>();

                payload = entry.Changes ?? entry.Messaging;

                foreach (var message in payload)
                {
                    var activity = FacebookHelper.ProcessSingleMessage(message);

                    using (var context = new TurnContext(this, activity))
                    {
                        await RunPipelineAsync(context, bot.OnTurnAsync, cancellationToken).ConfigureAwait(false);
                    }
                }

                // Handle standby messages (this bot is not the active receiver)
                if (entry.Standby != null)
                {
                    payload = entry.Standby;

                    foreach (var message in payload)
                    {
                        // Indicate that this message was received in standby mode rather than normal mode.
                        message.Standby = true;
                        var activity = FacebookHelper.ProcessSingleMessage(message);

                        using (var context = new TurnContext(this, activity))
                        {
                            await RunPipelineAsync(context, bot.OnTurnAsync, cancellationToken).ConfigureAwait(false);
                        }
                    }
                }
            }
        }