Как я делал бота для Facebook workplace
Дали мне задачу: написать бота для мессенджера workplace, с помощью которого можно получать уведомления из нашей CRM и управлять разными вещами. Расскажу о разных интересных вещах с которыми я столкнулся. Бота писал с помощью ASP.NET Core Web API.
Вебхуки
Для того чтобы бот мог обрабатывать запросы и сообщения от Facebook нам надо настроить вебхуки. Webhook — механизм оповещения системы о событиях. Для того чтобы Facebook принял наш хук, он должен обрабатывать как GET так и POST запросы.
Подробнее о Webhook в официальной документации
GET запрос служит для валидации работы нашего эндпоинта. POST принимает данные связанные с активностью пользователя, будь то нажатие на кнопки или другая активность.
public IActionResult Receive(
[FromQuery(Name = "hub.mode")] string mode,
[FromQuery(Name = "hub.challenge")] string challenge,
[FromQuery(Name = "hub.verify_token")] string verifyToken)
{
if (string.IsNullOrEmpty(verifyToken)) {
return Unauthorized();
}
if (verifyToken.Equals(FacebookEnvironment.FacebookVToken)) {
return Ok(challenge);
}
return Unauthorized();
}В качестве verify_token используется токен, который мы указали при регистрации нашего хука.
public async Task<IActionResult> Receive([FromBody]FbResponse response = null)
{
if (response is null) {
return BadRequest();
}
if (response.Object != "page") {
return Ok();
}
foreach (var entry in response.Entries) {
foreach (var message in entry.Messaging) {
await PrepareMessageAsync(message);
}
}
return Ok("EVENT_RECEIVED");
}Авторизация запросов Facebook
Для авторизации Facebook использует специальный http заголовок (X-Hub-Signature), в нем он передает некую сигнатуру с помощью которой мы можем авторизовать запрос. Для того чтобы добавить такую функциональность в наш контроллер, добавим фильтр.
private const string Sha1Prefix = "sha1=";
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<byte> bytes)
{
var builder = new StringBuilder(bytes.Count * 2);
foreach (var b in bytes)
{
builder.AppendFormat("{0:x2}", b);
}
return builder.ToString();
}Тестирование бота
Как установить letsencrypt сертификат для IIS. Если же вы используете связку в виде ubuntu и nginx вам подойдет эта инструкция.
Для тестирования нужно развернуть бот на сервере, который смотрит в мир. Также необходимо чтобы у сервера было доменное имя и валидный SSL сертификат. В моем случае, в качестве сервера выступала машина на винде, так как другой внутри нашей сети не было. Как мне показалось захостить приложение написанное на .NET Core намного проще под Ubuntu + nginx нежели под Windows + IIS. В качестве поставщика сертификатов выбрал letsencrypt, так как они предоставляют бесплатный сертификат на 3 месяца, с возможностью дальнейшего обновления.