FastComments.com


Z FastComments możliwe jest wywołanie punktu końcowego API za każdym razem, gdy komentarz zostanie dodany, zaktualizowany lub usunięty z naszego systemu.

Realizujemy to za pomocą asynchronicznych webhooków przez HTTP/HTTPS.


Czym są webhooki Internal Link


Webhook to mechanizm, lub integracja, pomiędzy dwoma systemami gdzie "producent" (FastComments) wyzwala zdarzenie które "konsument" (Ty) odbiera za pomocą wywołania API.


Obsługiwane zdarzenia i zasoby Internal Link

FastComments obsługuje webhooki tylko dla zasobu Comment.

Obsługujemy webhooki dla tworzenia komentarza, usuwania oraz aktualizacji.

Każde z nich jest w naszym systemie traktowane jako odrębne zdarzenie i w związku z tym ma inną semantykę i inną strukturę zdarzeń webhook.

Testowanie Internal Link

W panelu administracyjnym Webhooks znajdują się przyciski Send Test Payload dla każdego typu zdarzenia (Create, Update, Delete). Zdarzenia Create i Update wysyłają przykładowy obiekt WebhookComment, natomiast testowanie Delete wyśle przykładowe ciało żądania zawierające tylko identyfikator.

Weryfikacja ładunków

Podczas testowania integracji webhook sprawdź, czy przychodzące żądania zawierają następujące nagłówki:

  1. token - Twój sekret API
  2. X-FastComments-Timestamp - znacznik czasu Unix (sekundy)
  3. X-FastComments-Signature - podpis HMAC-SHA256

Użyj weryfikacji podpisu HMAC, aby upewnić się, że ładunki są autentyczne.

Narzędzia do testowania

Możesz użyć narzędzi takich jak webhook.site lub ngrok, aby sprawdzać przychodzące ładunki webhooków podczas tworzenia.

Typy zdarzeń

  • Create Event: Wywoływane, gdy zostanie utworzony nowy komentarz. Domyślna metoda: PUT
  • Update Event: Wywoływane, gdy komentarz zostanie edytowany. Domyślna metoda: PUT
  • Delete Event: Wywoływane, gdy komentarz zostanie usunięty. Domyślna metoda: DELETE

Każde zdarzenie zawiera pełne dane komentarza w ciele żądania (zobacz Struktury danych dla formatu ładunku).

Struktury danych Internal Link

Jedynej struktury wysyłanej przez webhooks jest obiekt WebhookComment, opisany poniżej w TypeScript.

Struktura obiektu WebhookComment

Struktura zdarzenia "create"

Ciało żądania zdarzenia "create" to obiekt WebhookComment.

Struktura zdarzenia "update"

Ciało żądania zdarzenia "update" to obiekt WebhookComment.

Struktura zdarzenia "delete"

Ciało żądania zdarzenia "delete" to obiekt WebhookComment.

Zmiana od 14 listopada 2023
Wcześniej ciało żądania zdarzenia "delete" zawierało tylko id komentarza. Teraz zawiera pełny komentarz w momencie usunięcia.
Obiekt WebhookComment
Copy CopyRun External Link
1
2interface WebhookComment {
3 /** Id komentarza. **/
4 id: string
5 /** Id lub URL identyfikujący wątek komentarzy. Znormalizowany. **/
6 urlId: string
7 /** URL wskazujący miejsce, gdzie został dodany komentarz. **/
8 url?: string
9 /** Id użytkownika, który dodał komentarz. W przypadku SSO, poprzedzone tenant id. **/
10 userId?: string
11 /** Email użytkownika, który dodał komentarz. **/
12 commenterEmail?: string
13 /** Nazwa użytkownika wyświetlana w widżecie komentarza. W przypadku SSO, może być displayName. **/
14 commenterName: string
15 /** Surowy tekst komentarza. **/
16 comment: string
17 /** Tekst komentarza po parsowaniu. **/
18 commentHTML: string
19 /** Zewnętrzne id komentarza. **/
20 externalId?: string
21 /** Id komentarza nadrzędnego. **/
22 parentId?: string | null
23 /** Data UTC, kiedy komentarz został dodany. **/
24 date: UTC_ISO_DateString
25 /** Suma karmy (up - down) z głosów. **/
26 votes: number
27 votesUp: number
28 votesDown: number
29 /** Prawda jeśli użytkownik był zalogowany podczas dodawania komentarza, lub jeśli zweryfikował komentarz, lub jeśli zweryfikował swoją sesję w momencie dodania komentarza. **/
30 verified: boolean
31 /** Data weryfikacji komentarza. **/
32 verifiedDate?: number
33 /** Czy moderator oznaczył komentarz jako sprawdzony. **/
34 reviewed: boolean
35 /** Lokacja lub zakodowany base64 awatara. Będzie base64 tylko jeśli taka była wartość przekazana przy SSO. **/
36 avatarSrc?: string
37 /** Czy komentarz został oznaczony jako spam ręcznie czy automatycznie? **/
38 isSpam: boolean
39 /** Czy komentarz został automatycznie oznaczony jako spam? **/
40 aiDeterminedSpam: boolean
41 /** Czy w komentarzu znajdują się obrazy? **/
42 hasImages: boolean
43 /** Numer strony, na której znajduje się komentarz przy sortowaniu "Most Relevant". **/
44 pageNumber: number
45 /** Numer strony przy sortowaniu "Oldest First". **/
46 pageNumberOF: number
47 /** Numer strony przy sortowaniu "Newest First". **/
48 pageNumberNF: number
49 /** Czy komentarz został zatwierdzony automatycznie czy ręcznie? **/
50 approved: boolean
51 /** Kod lokalizacji (format: en_us) użytkownika w momencie dodawania komentarza. **/
52 locale: string
53 /** Wzmianki @ zapisane w komentarzu, które zostały pomyślnie sparsowane. **/
54 mentions?: CommentUserMention[]
55 /** Domena, z której pochodzi komentarz. **/
56 domain?: string
57 /** Opcjonalna lista identyfikatorów (id) grup moderacyjnych powiązanych z tym komentarzem. **/
58 moderationGroupIds?: string[]|null
59}
60

Gdy użytkownicy są oznaczani w komentarzu, informacja jest przechowywana na liście o nazwie mentions. Każdy obiekt na tej liście ma następującą strukturę.

Obiekt wzmianki Webhook
Copy CopyRun External Link
1
2interface CommentUserMention {
3 /** Id użytkownika. W przypadku użytkowników SSO będzie poprzedzone tenant id. **/
4 id: string
5 /** Końcowy tekst tagu @mention, łącznie z symbolem @. **/
6 tag: string
7 /** Oryginalny tekst tagu @mention, łącznie z symbolem @. **/
8 rawTag: string
9 /** Jaki typ użytkownika został oznaczony. user = konto FastComments.com. sso = SSOUser. **/
10 type: 'user'|'sso'
11 /** Jeśli użytkownik zrezygnuje z powiadomień, to mimo to będzie ustawione na true. **/
12 sent: boolean
13}
14

Metody HTTP

Możesz skonfigurować metodę HTTP dla każdego typu zdarzenia webhook w panelu administracyjnym:

  • Create Event: POST lub PUT (domyślnie: PUT)
  • Update Event: POST lub PUT (domyślnie: PUT)
  • Delete Event: DELETE, POST lub PUT (domyślnie: DELETE)

Ponieważ wszystkie żądania zawierają ID, operacje Create i Update są domyślnie idempotentne (PUT). Powtarzanie tego samego żądania Create lub Update nie powinno tworzyć duplikatów po Twojej stronie.

Nagłówki żądań

Każde żądanie webhook zawiera następujące nagłówki:

Header Description
Content-Type application/json
token Twój sekret API
X-FastComments-Timestamp Znacznik czasu Unix (sekundy) w momencie podpisania żądania
X-FastComments-Signature Podpis HMAC-SHA256 (sha256=<hex>)

Zobacz Security & API Tokens aby uzyskać informacje o weryfikacji podpisu HMAC.


Bezpieczeństwo i tokeny API Internal Link

FastComments webhook requests include multiple authentication mechanisms for security.

Wysyłane nagłówki

Nagłówek Opis
token Twój API Secret (w celu zachowania zgodności wstecznej)
X-FastComments-Timestamp Znacznik czasu Unix (sekundy), kiedy żądanie zostało podpisane
X-FastComments-Signature Podpis HMAC-SHA256 ładunku

Weryfikacja podpisu HMAC (zalecane)

Zdecydowanie zalecamy weryfikację podpisu HMAC, aby upewnić się, że ładunki webhooków są autentyczne i nie zostały zmienione.

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

Jak obliczany jest podpis:

  1. Połącz: timestamp + "." + JSON_payload_body
  2. Oblicz HMAC-SHA256 używając swojego API Secret jako klucza
  3. Zakoduj wynik w hex

Przykład weryfikacji (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;
    }

    // Zweryfikuj, że znacznik czasu jest aktualny (w ciągu 5 minut)
    const now = Math.floor(Date.now() / 1000);
    if (Math.abs(now - parseInt(timestamp, 10)) > 300) {
        return false;  // Zapobieganie atakom powtórzeniowym
    }

    // Verify signature
    const payload = JSON.stringify(req.body);
    const expectedSignature = crypto
        .createHmac('sha256', apiSecret)
        .update(`${timestamp}.${payload}`)
        .digest('hex');

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

Przykład weryfikacji (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

    # Zweryfikuj, że znacznik czasu jest aktualny
    now = int(time.time())
    if abs(now - int(timestamp)) > 300:
        return False

    # Zweryfikuj podpis
    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}"

Przykład weryfikacji (PHP)

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

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

    // Zweryfikuj, że znacznik czasu jest aktualny (w ciągu 5 minut)
    $now = time();
    if (abs($now - intval($timestamp)) > 300) {
        return false;
    }

    // Zweryfikuj podpis
    $payload = json_encode($body, JSON_UNESCAPED_SLASHES);
    $message = $timestamp . '.' . $payload;
    $expectedSignature = 'sha256=' . hash_hmac('sha256', $message, $apiSecret);

    return hash_equals($expectedSignature, $signature);
}

Starsze uwierzytelnianie

Nagłówek token zawierający Twój API Secret wciąż jest wysyłany dla zachowania zgodności wstecznej. Jednak zalecamy przejście na weryfikację HMAC dla lepszego bezpieczeństwa, ponieważ chroni ona przed atakami powtórzeniowymi.


Podsumowanie

To kończy naszą dokumentację Webhooks.

Mamy nadzieję, że integracja FastComments Webhook jest łatwa do zrozumienia i szybka do skonfigurowania.

Jeśli uważasz, że zidentyfikowałeś jakiekolwiek luki w naszej dokumentacji, daj nam znać poniżej.