FastComments.com

Con FastComments è possibile invocare un endpoint API ogni volta che un commento viene aggiunto, aggiornato o rimosso dal nostro sistema.

Realizziamo questo tramite webhook asincroni su HTTP/HTTPS.


Cosa sono i Webhook Internal Link


Un Webhook è un meccanismo, o un'integrazione, tra due sistemi in cui il "produttore" (FastComments) scatena un evento che il "consumatore" (tu) consuma tramite una chiamata API.


Eventi e risorse supportati Internal Link

FastComments supporta i webhook solo per la risorsa Comment.

Supportiamo webhook per la creazione, la rimozione e l'aggiornamento dei commenti.

Ognuno di questi è considerato un evento separato nel nostro sistema e, come tale, ha semantiche diverse e strutture diverse per gli eventi webhook.

Test Internal Link

Nella sezione di amministrazione Webhooks ci sono pulsanti Send Test Payload per ogni tipo di evento (Create, Update, Delete). Gli eventi Create e Update inviano un oggetto di prova WebhookComment, mentre il test dell'evento Delete invierà un corpo della richiesta di prova contenente solo un ID.

Verifica dei payload

Durante il test dell'integrazione webhook, verifica che le richieste in arrivo includano le seguenti intestazioni:

  1. token - Il tuo segreto API
  2. X-FastComments-Timestamp - timestamp Unix (secondi)
  3. X-FastComments-Signature - firma HMAC-SHA256

Utilizza la verifica della firma HMAC per assicurarti che i payload siano autentici.

Strumenti di test

Puoi usare strumenti come webhook.site o ngrok per ispezionare i payload webhook in arrivo durante lo sviluppo.

Tipi di eventi

  • Create Event: Scatenato quando viene creato un nuovo commento. Metodo predefinito: PUT
  • Update Event: Scatenato quando un commento viene modificato. Metodo predefinito: PUT
  • Delete Event: Scatenato quando un commento viene eliminato. Metodo predefinito: DELETE

Ogni evento include l'intero set di dati del commento nel corpo della richiesta (vedi Strutture dei dati per il formato del payload).


Strutture dati Internal Link

L'unica struttura inviata tramite webhook è l'oggetto WebhookComment, illustrato in TypeScript qui sotto.

La struttura dell'oggetto WebhookComment

Struttura dell'evento "create"

Il corpo della richiesta per l'evento "create" è un oggetto WebhookComment.

Struttura dell'evento "update"

Il corpo della richiesta per l'evento "update" è un oggetto WebhookComment.

Struttura dell'evento "delete"

Il corpo della richiesta per l'evento "delete" è un oggetto WebhookComment.

Modifica del 14 novembre 2023
Precedentemente il corpo della richiesta dell'evento "delete" conteneva solo l'id del commento. Ora contiene il commento completo al momento della cancellazione.
Oggetto WebhookComment
Copy CopyRun External Link
1
2interface WebhookComment {
3 /** L'id del commento. **/
4 id: string
5 /** L'id o l'URL che identifica il thread di commento. Normalizzato. **/
6 urlId: string
7 /** L'URL che punta al luogo in cui è stato lasciato il commento. **/
8 url?: string
9 /** L'id utente che ha lasciato il commento. Se SSO, viene prefissato con l'id del tenant. **/
10 userId?: string
11 /** L'email dell'utente che ha lasciato il commento. **/
12 commenterEmail?: string
13 /** Il nome dell'utente mostrato nel widget dei commenti. In caso di SSO, può essere displayName. **/
14 commenterName: string
15 /** Testo grezzo del commento. **/
16 comment: string
17 /** Testo del commento dopo il parsing. **/
18 commentHTML: string
19 /** Id esterno del commento. **/
20 externalId?: string
21 /** L'id del commento padre. **/
22 parentId?: string | null
23 /** La data UTC in cui è stato lasciato il commento. **/
24 date: UTC_ISO_DateString
25 /** Karma combinato (up - down) dei voti. **/
26 votes: number
27 votesUp: number
28 votesDown: number
29 /** True se l'utente era autenticato quando ha commentato, o se ha verificato il commento, o se ha verificato la sessione quando è stato lasciato il commento. **/
30 verified: boolean
31 /** Data in cui il commento è stato verificato. **/
32 verifiedDate?: number
33 /** Se un moderatore ha contrassegnato il commento come revisionato. **/
34 reviewed: boolean
35 /** La posizione, o la codifica base64, dell'avatar. Sarà base64 solo se questo valore è stato passato con SSO. **/
36 avatarSrc?: string
37 /** Il commento è stato contrassegnato come spam manualmente o automaticamente? **/
38 isSpam: boolean
39 /** Il commento è stato contrassegnato automaticamente come spam? **/
40 aiDeterminedSpam: boolean
41 /** Ci sono immagini nel commento? **/
42 hasImages: boolean
43 /** Il numero di pagina in cui si trova il commento per l'ordinamento "Most Relevant". **/
44 pageNumber: number
45 /** Il numero di pagina in cui si trova il commento per l'ordinamento "Oldest First". **/
46 pageNumberOF: number
47 /** Il numero di pagina in cui si trova il commento per l'ordinamento "Newest First". **/
48 pageNumberNF: number
49 /** Il commento è stato approvato automaticamente o manualmente? **/
50 approved: boolean
51 /** Il codice locale (formato: en_us) dell'utente quando il commento è stato scritto. **/
52 locale: string
53 /** Le @mentions presenti nel commento che sono state analizzate con successo. **/
54 mentions?: CommentUserMention[]
55 /** Il dominio da cui proviene il commento. **/
56 domain?: string
57 /** L'elenco opzionale di id dei gruppi di moderazione associati a questo commento. **/
58 moderationGroupIds?: string[]|null
59}
60

Quando gli utenti vengono taggati in un commento, le informazioni sono memorizzate in una lista chiamata mentions. Ogni oggetto in quella lista ha la seguente struttura.

Oggetto Mentions del Webhook
Copy CopyRun External Link
1
2interface CommentUserMention {
3 /** L'id utente. Per gli utenti SSO, avrà il prefisso dell'id del tenant. **/
4 id: string
5 /** Il testo finale del tag @mention, inclusivo del simbolo @. **/
6 tag: string
7 /** Il testo originale del tag @mention, inclusivo del simbolo @. **/
8 rawTag: string
9 /** Tipo di utente taggato. user = account FastComments.com. sso = SSOUser. **/
10 type: 'user'|'sso'
11 /** Se l'utente rinuncia alle notifiche, questo sarà comunque impostato su true. **/
12 sent: boolean
13}
14

Metodi HTTP

Puoi configurare il metodo HTTP per ciascun tipo di evento webhook nel pannello di amministrazione:

  • Evento "create": POST o PUT (predefinito: PUT)
  • Evento "update": POST o PUT (predefinito: PUT)
  • Evento "delete": DELETE, POST o PUT (predefinito: DELETE)

Poiché tutte le richieste contengono un ID, le operazioni di Create e Update sono idempotenti per impostazione predefinita (PUT). Ripetere la stessa richiesta di Create o Update non dovrebbe creare oggetti duplicati sul vostro sistema.

Intestazioni della richiesta

Ogni richiesta webhook include le seguenti intestazioni:

Header Descrizione
Content-Type application/json
token Il tuo API Secret
X-FastComments-Timestamp Timestamp Unix (secondi) al momento in cui la richiesta è stata firmata
X-FastComments-Signature Firma HMAC-SHA256 (sha256=<hex>)

Vedi Sicurezza e Token API per informazioni sulla verifica della firma HMAC.

Sicurezza e token API Internal Link

FastComments webhook requests include multiple authentication mechanisms for security.

Intestazioni inviate

Intestazione Descrizione
token Il tuo API Secret (per compatibilità con le versioni precedenti)
X-FastComments-Timestamp Timestamp Unix (secondi) quando la richiesta è stata firmata
X-FastComments-Signature Firma HMAC-SHA256 del payload

Verifica della firma HMAC (Consigliata)

Raccomandiamo vivamente di verificare la firma HMAC per assicurarsi che i payload dei webhook siano autentici e non siano stati manomessi.

Formato della firma: sha256=<hex-encoded-signature>

Come viene calcolata la firma:

  1. Concatena: timestamp + "." + JSON_payload_body
  2. Calcola HMAC-SHA256 usando il tuo API Secret come chiave
  3. Codifica il risultato in esadecimale

Esempio di verifica (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;
    }

    // Verifica che il timestamp sia recente (entro 5 minuti)
    const now = Math.floor(Date.now() / 1000);
    if (Math.abs(now - parseInt(timestamp, 10)) > 300) {
        return false;  // Prevenzione di attacchi di replay
    }

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

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

Esempio di verifica (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

    # Verifica che il timestamp sia recente
    now = int(time.time())
    if abs(now - int(timestamp)) > 300:
        return False

    # Verifica la firma
    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}"

Esempio di verifica (PHP)

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

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

    // Verifica che il timestamp sia recente (entro 5 minuti)
    $now = time();
    if (abs($now - intval($timestamp)) > 300) {
        return false;
    }

    // Verifica la firma
    $payload = json_encode($body, JSON_UNESCAPED_SLASHES);
    $message = $timestamp . '.' . $payload;
    $expectedSignature = 'sha256=' . hash_hmac('sha256', $message, $apiSecret);

    return hash_equals($expectedSignature, $signature);
}

Autenticazione legacy

L'intestazione token contenente il tuo API Secret viene ancora inviata per compatibilità con le versioni precedenti. Tuttavia, consigliamo di migrare alla verifica HMAC per una sicurezza migliorata poiché protegge dagli attacchi di replay.

In conclusione

Questa conclude la nostra documentazione sui Webhooks.

Speriamo che troviate l'integrazione FastComments Webhook facile da comprendere e veloce da configurare.

Se ritenete di aver individuato delle lacune nella nostra documentazione, fatecelo sapere qui sotto.