FastComments.com


С FastComments можно вызывать API endpoint всякий раз, когда в нашей системе добавляется, обновляется или удаляется комментарий.

Мы осуществляем это с помощью asynchronous webhooks по протоколам HTTP/HTTPS.


Что такое вебхуки Internal Link

Вебхук — это механизм или интеграция между двумя системами, где "производитель" (FastComments) генерирует событие которое "потребитель" (Вы) обрабатывает посредством вызова API.

Поддерживаемые события и ресурсы Internal Link

FastComments поддерживает вебхуки только для ресурса Comment.

Мы поддерживаем вебхуки при создании комментария, его удалении и обновлении.

Каждое из них считается отдельным событием в нашей системе и, как следствие, имеет разную семантику и структуру событий вебхуков.

Тестирование Internal Link

В админке Webhooks есть кнопки Send Test Payload для каждого типа события (Create, Update, Delete). События Create и Update отправляют фиктивный объект WebhookComment, тогда как при тестировании Delete будет отправлено фиктивное тело запроса, содержащее только ID.

Проверка полезных нагрузок

При тестировании интеграции webhook убедитесь, что входящие запросы содержат следующие заголовки:

  1. token - Ваш секрет API
  2. X-FastComments-Timestamp - Метка времени Unix (в секундах)
  3. X-FastComments-Signature - Подпись HMAC-SHA256

Используйте проверку подписи HMAC, чтобы убедиться, что полезные нагрузки подлинны.

Инструменты для тестирования

Вы можете использовать такие инструменты, как webhook.site или ngrok, чтобы просматривать входящие полезные нагрузки вебхуков во время разработки.

Event Types

  • Create Event: Срабатывает при создании нового комментария. Метод по умолчанию: PUT
  • Update Event: Срабатывает при редактировании комментария. Метод по умолчанию: PUT
  • Delete Event: Срабатывает при удалении комментария. Метод по умолчанию: DELETE

Каждое событие включает полный набор данных комментария в теле запроса (см. Структуры данных для формата полезной нагрузки).

Структуры данных Internal Link

Единственная структура, отправляемая через вебхуки, — это объект WebhookComment, описанный на TypeScript ниже.

Структура объекта WebhookComment

Структура события «create»

Тело запроса для события «create» — объект WebhookComment.

Структура события «update»

Тело запроса для события «update» — объект WebhookComment.

Структура события «delete»

Тело запроса для события «delete» — объект WebhookComment.

Изменение с 14 ноября 2023 г.
Ранее тело запроса для события «delete» содержало только id комментария. Теперь оно содержит полный комментарий на момент удаления.
Объект WebhookComment
Copy CopyRun External Link
1
2interface WebhookComment {
3 /** Идентификатор комментария. **/
4 id: string
5 /** Идентификатор или URL, который определяет ветку комментариев. Нормализовано. **/
6 urlId: string
7 /** URL, указывающий на страницу, где был оставлен комментарий. **/
8 url?: string
9 /** Идентификатор пользователя, оставившего комментарий. Для SSO — с префиксом tenant id. **/
10 userId?: string
11 /** Email пользователя, оставившего комментарий. **/
12 commenterEmail?: string
13 /** Имя пользователя, отображаемое в виджете комментариев. Для SSO может быть displayName. **/
14 commenterName: string
15 /** Исходный текст комментария. **/
16 comment: string
17 /** Текст комментария после разбора. **/
18 commentHTML: string
19 /** Внешний идентификатор комментария. **/
20 externalId?: string
21 /** Идентификатор родительского комментария. **/
22 parentId?: string | null
23 /** Дата в UTC, когда был оставлен комментарий. **/
24 date: UTC_ISO_DateString
25 /** Суммарная карма голосов (за - против). **/
26 votes: number
27 votesUp: number
28 votesDown: number
29 /** true, если пользователь был авторизован при написании комментария, либо комментарий был подтверждён, либо сессия была подтверждена в момент оставления комментария. **/
30 verified: boolean
31 /** Дата, когда комментарий был подтверждён. **/
32 verifiedDate?: number
33 /** Если модератор пометил комментарий как просмотренный. **/
34 reviewed: boolean
35 /** Местоположение или base64-код аватара. Будет в base64 только если такое значение было передано при SSO. **/
36 avatarSrc?: string
37 /** Был ли комментарий помечен как спам вручную или автоматически? **/
38 isSpam: boolean
39 /** Был ли комментарий автоматически помечен как спам? **/
40 aiDeterminedSpam: boolean
41 /** Есть ли изображения в комментарии? **/
42 hasImages: boolean
43 /** Номер страницы, на которой находится комментарий при сортировке «Most Relevant». **/
44 pageNumber: number
45 /** Номер страницы, на которой находится комментарий при сортировке «Oldest First». **/
46 pageNumberOF: number
47 /** Номер страницы, на которой находится комментарий при сортировке «Newest First». **/
48 pageNumberNF: number
49 /** Был ли комментарий утверждён автоматически или вручную? **/
50 approved: boolean
51 /** Код локали (формат: en_us) пользователя на момент написания комментария. **/
52 locale: string
53 /** @mentions, указанные в комментарии, которые были успешно распарсены. **/
54 mentions?: CommentUserMention[]
55 /** Домен, с которого пришёл комментарий. **/
56 domain?: string
57 /** Необязательный список идентификаторов групп модерации, связанных с этим комментарием. **/
58 moderationGroupIds?: string[]|null
59}
60

Когда в комментарии упоминают пользователей, информация хранится в списке mentions. Каждый объект в этом списке имеет следующую структуру.

Объект упоминаний Webhook
Copy CopyRun External Link
1
2interface CommentUserMention {
3 /** Идентификатор пользователя. Для SSO-пользователей будет с префиксом tenant id. **/
4 id: string
5 /** Финальный текст тега @mention, включая символ @. **/
6 tag: string
7 /** Оригинальный текст тега @mention, включая символ @. **/
8 rawTag: string
9 /** Тип отмеченного пользователя. user = аккаунт FastComments.com. sso = SSOUser. **/
10 type: 'user'|'sso'
11 /** Если пользователь отказался от уведомлений, это всё равно будет установлено в true. **/
12 sent: boolean
13}
14

HTTP-методы

Вы можете настроить HTTP-метод для каждого типа события вебхука в панели администратора:

  • Событие «create»: POST или PUT (по умолчанию: PUT)
  • Событие «update»: POST или PUT (по умолчанию: PUT)
  • Событие «delete»: DELETE, POST или PUT (по умолчанию: DELETE)

Поскольку все запросы содержат ID, операции Create и Update по умолчанию идемпотентны (PUT). Повторение того же запроса Create или Update не должно создавать дубликаты объектов на вашей стороне.

Заголовки запроса

Каждый запрос вебхука содержит следующие заголовки:

Заголовок Описание
Content-Type application/json
token Ваш секрет API
X-FastComments-Timestamp Unix-временная метка (секунды), указывающая время подписи запроса
X-FastComments-Signature Подпись HMAC-SHA256 (sha256=<hex>)

См. Безопасность и API-токены для информации о проверке подписи HMAC.


Безопасность и API-токены Internal Link

FastComments webhook requests include multiple authentication mechanisms for security.

Отправляемые заголовки

Заголовок Описание
token Ваш API Secret (для обратной совместимости)
X-FastComments-Timestamp Unix-временная метка (в секундах), когда запрос был подписан
X-FastComments-Signature Подпись HMAC-SHA256 полезной нагрузки

Мы настоятельно рекомендуем проверять подпись HMAC, чтобы убедиться, что полезные данные webhook подлинны и не были изменены.

Signature Format: sha256=<hex-encoded-signature>

How the signature is computed:

  1. Объедините: timestamp + "." + JSON_payload_body
  2. Вычислите HMAC-SHA256, используя ваш API Secret в качестве ключа
  3. Преобразуйте результат в шестнадцатеричную строку

Example Verification (Node.js)

const crypto = require('crypto');

function verifyWebhookSignature(req, apiSecret) {
    const timestamp = req.headers['x-fastcomments-timestamp'];
    const signature = req.headers['x-fastcomments-signature'];

    if (!timestamp || !signature) {
        return false;
    }

    // Проверить, что метка времени недавняя (в пределах 5 минут)
    const now = Math.floor(Date.now() / 1000);
    if (Math.abs(now - parseInt(timestamp, 10)) > 300) {
        return false;  // Предотвращение атак повторного воспроизведения
    }

    // Проверить подпись
    const payload = JSON.stringify(req.body);
    const expectedSignature = crypto
        .createHmac('sha256', apiSecret)
        .update(`${timestamp}.${payload}`)
        .digest('hex');

    return signature === `sha256=${expectedSignature}`;
}

Example Verification (Python)

import hmac
import hashlib
import time
import json

def verify_webhook_signature(headers, body, api_secret):
    timestamp = headers.get('X-FastComments-Timestamp')
    signature = headers.get('X-FastComments-Signature')

    if not timestamp or not signature:
        return False

    # Проверить, что метка времени недавняя
    now = int(time.time())
    if abs(now - int(timestamp)) > 300:
        return False

    # Проверить подпись
    payload = json.dumps(body, separators=(',', ':'))
    message = f"{timestamp}.{payload}"
    expected = hmac.new(
        api_secret.encode(),
        message.encode(),
        hashlib.sha256
    ).hexdigest()

    return signature == f"sha256={expected}"

Example Verification (PHP)

function verifyWebhookSignature($headers, $body, $apiSecret) {
    $timestamp = $headers['X-FastComments-Timestamp'] ?? null;
    $signature = $headers['X-FastComments-Signature'] ?? null;

    if (!$timestamp || !$signature) {
        return false;
    }

    // Проверить, что метка времени недавняя (в пределах 5 минут)
    $now = time();
    if (abs($now - intval($timestamp)) > 300) {
        return false;
    }

    // Проверить подпись
    $payload = json_encode($body, JSON_UNESCAPED_SLASHES);
    $message = $timestamp . '.' . $payload;
    $expectedSignature = 'sha256=' . hash_hmac('sha256', $message, $apiSecret);

    return hash_equals($expectedSignature, $signature);
}

Legacy Authentication

Заголовок token, содержащий ваш API Secret, по-прежнему отправляется для обратной совместимости. Тем не менее, мы рекомендуем перейти на проверку HMAC для повышения безопасности, так как она защищает от атак повторного воспроизведения.

В заключение

На этом завершается наша документация по вебхукам.

Надеемся, что интеграция вебхуков FastComments понятна и проста в настройке.

Если вы считаете, что нашли пробелы в нашей документации, сообщите нам ниже.