<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Блоги: заметки с тегом робота</title>
<link>https://blogengine.ru/blogs/tags/robota/</link>
<description>Автоматически собираемая лента заметок, написанных в блогах на Эгее</description>
<author></author>
<language>ru</language>
<generator>Aegea 11.0 (v4079e)</generator>

<itunes:subtitle>Автоматически собираемая лента заметок, написанных в блогах на Эгее</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit>no</itunes:explicit>

<item>
<title>Как я делал бота для Facebook workplace</title>
<guid isPermaLink="false">119851</guid>
<link>https://stefaniuk.website/all/create-workplace-messenger-bot/</link>
<pubDate>Tue, 26 Nov 2019 19:22:26 +0500</pubDate>
<author>Bohdan Stefaniuk</author>
<comments>https://stefaniuk.website/all/create-workplace-messenger-bot/</comments>
<description>
&lt;p&gt;&lt;a href="https://stefaniuk.website/"&gt;Bohdan Stefaniuk&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;Дали мне задачу: написать бота для мессенджера workplace, с помощью которого можно получать уведомления из нашей CRM и управлять разными вещами. Расскажу о разных интересных вещах с которыми я столкнулся. Бота писал с помощью ASP.NET Core Web API.&lt;/p&gt;
&lt;h2&gt;Вебхуки&lt;/h2&gt;
&lt;p&gt;Для того чтобы бот мог обрабатывать запросы и сообщения от Facebook нам надо настроить вебхуки. Webhook — механизм оповещения системы о событиях. Для того чтобы Facebook принял наш хук, он должен обрабатывать как GET так и POST запросы.&lt;/p&gt;
&lt;p class="note"&gt;&lt;a href="https://developers.facebook.com/docs/messenger-platform/getting-started/webhook-setup"&gt;Подробнее о Webhook в официальной документации&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;GET запрос служит для валидации работы нашего эндпоинта. POST принимает данные связанные с активностью пользователя, будь то нажатие на кнопки или другая активность.&lt;/p&gt;
&lt;p class="cut-button"&gt;Показать код метода-обработчика GET запроса&lt;/p&gt;
&lt;div class="cut-content"&gt;&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;public IActionResult Receive( [FromQuery(Name = &amp;quot;hub.mode&amp;quot;)] string mode, 
    [FromQuery(Name = &amp;quot;hub.challenge&amp;quot;)] string challenge, 
    [FromQuery(Name = &amp;quot;hub.verify_token&amp;quot;)] string verifyToken)
{ 
   if (string.IsNullOrEmpty(verifyToken)) { 
       return Unauthorized(); 
    }  
    if (verifyToken.Equals(FacebookEnvironment.FacebookVToken)) { 
        return Ok(challenge); 
    } 
    return Unauthorized(); 
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;В качестве verify_token используется токен, который мы указали при регистрации нашего хука.&lt;/p&gt;
&lt;/div&gt;&lt;p class="cut-button"&gt;Показать код метода-обработчика POST запроса&lt;/p&gt;
&lt;div class="cut-content"&gt;&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;public async Task&amp;lt;IActionResult&amp;gt; Receive([FromBody]FbResponse response = null)
{
    if (response is null) {
        return BadRequest();
    }

    if (response.Object != &amp;quot;page&amp;quot;) {
        return Ok();
    }

    foreach (var entry in response.Entries) {
        foreach (var message in entry.Messaging) {
            await PrepareMessageAsync(message);
        }
    }
    return Ok(&amp;quot;EVENT_RECEIVED&amp;quot;);
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Авторизация запросов Facebook&lt;/h2&gt;
&lt;p&gt;Для авторизации Facebook использует специальный http заголовок (X-Hub-Signature), в нем он передает некую сигнатуру с помощью которой мы можем авторизовать запрос. Для того чтобы добавить такую функциональность в наш контроллер, добавим фильтр.&lt;/p&gt;
&lt;p class="cut-button"&gt;Пример кода, для проверки подписи&lt;/p&gt;
&lt;div class="cut-content"&gt;&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;private const string Sha1Prefix = &amp;quot;sha1=&amp;quot;;

public static bool Validate(string signature, string contentString) {
    if (!signature.StartsWith(Sha1Prefix, StringComparison.OrdinalIgnoreCase)) {
        return false;
    }
    var secret = Encoding.ASCII.GetBytes(FacebookEnvironment.AppSecret);
    var signatureWithoutPrefix = signature.Substring(Sha1Prefix.Length);
    var content = Encoding.ASCII.GetBytes(contentString);
    return GetIsHashValid(secret, signatureWithoutPrefix, content);
}

private static bool GetIsHashValid(byte[] secret, string signature, byte[] content) {
    using var hmac = new HMACSHA1(secret);
    var hash = hmac.ComputeHash(content);
    var hashString = ToHexString(hash);
    return hashString.Equals(signature);
}

private static string ToHexString(IReadOnlyCollection&amp;lt;byte&amp;gt; bytes)
{
    var builder = new StringBuilder(bytes.Count * 2);
    foreach (var b in bytes)
    {
        builder.AppendFormat(&amp;quot;{0:x2}&amp;quot;, b);
    }

    return builder.ToString();
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2&gt;Тестирование бота&lt;/h2&gt;
&lt;p class="note-md"&gt;&lt;a href="http://winitpro.ru/index.php/2017/11/03/ustanovka-besplatnogo-ssl-sertifikata-lets-encrypt-na-iis-v-windows-server-2012-r2/"&gt;Как установить letsencrypt сертификат для IIS&lt;/a&gt;. Если же вы используете связку в виде ubuntu и nginx вам подойдет &lt;a href="https://www.digitalocean.com/community/tutorials/nginx-let-s-encrypt-ubuntu-18-04-ru"&gt;эта инструкция&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Для тестирования нужно развернуть бот на сервере, который смотрит в мир. Также необходимо чтобы у сервера было доменное имя и валидный SSL сертификат. В моем случае, в качестве сервера выступала машина на винде, так как другой внутри нашей сети не было. Как мне показалось захостить приложение написанное на .NET Core намного проще под Ubuntu + nginx нежели под Windows + IIS. В качестве поставщика сертификатов выбрал letsencrypt, так как они предоставляют бесплатный сертификат на 3 месяца, с возможностью дальнейшего обновления.&lt;/p&gt;
</description>
</item>


</channel>
</rss>