INTEGRITY Документация

Использование webhooks

Вебхуки уведомляют ваш сервис о том, что видео успешно обработано и готово к трансляции, либо о том, что видео перешло в состояние ошибки.

Подпишитесь на уведомления вебхуков

Чтобы подписаться на уведомления webhook для своего сервиса или изменить существующую подписку, сгенерируйте API-токен на Токены API аккаунта странице дашборда Cloudflare.

Перейдите в Токены API аккаунта ↗

URL для уведомлений webhook должен включать протокол. Поддерживаются только http:// или https:// поддерживается.

curl -X PUT --header 'Authorization: Bearer <API_TOKEN>' \
https://api.cloudflare.com/client/v4/accounts/<ACCOUNT_ID>/stream/webhook \
--data '{"notificationUrl":"<WEBHOOK_NOTIFICATION_URL>"}'
Пример ответа
{
	"result": {
		"notificationUrl": "http://www.your-service-webhook-handler.com",
		"modified": "2019-01-01T01:02:21.076571Z",
		"secret": "85011ed3a913c6ad5f9cf6c5573cc0a7"
	},
	"success": true,
	"errors": [],
	"messages": []
}

Уведомления

Когда обработка видео в вашем аккаунте завершится, вы получите POST запрос-уведомление с информацией о видео.

Пример тела POST-запроса, отправляемого при успешном кодировании
{
	"uid": "6b9e68b07dfee8cc2d116e4c51d6a957",
	"creator": null,
	"thumbnail": "https://customer-f33zs165nr7gyfy4.cloudflarestream.com/6b9e68b07dfee8cc2d116e4c51d6a957/thumbnails/thumbnail.jpg",
	"thumbnailTimestampPct": 0,
	"readyToStream": true,
	"status": {
		"state": "ready",
		"pctComplete": "39.000000",
		"errorReasonCode": "",
		"errorReasonText": ""
	},
	"meta": {
		"filename": "small.mp4",
		"filetype": "video/mp4",
		"name": "small.mp4",
		"relativePath": "null",
		"type": "video/mp4"
	},
	"created": "2022-06-30T17:53:12.512033Z",
	"modified": "2022-06-30T17:53:21.774299Z",
	"size": 383631,
	"preview": "https://customer-f33zs165nr7gyfy4.cloudflarestream.com/6b9e68b07dfee8cc2d116e4c51d6a957/watch",
	"allowedOrigins": [],
	"requireSignedURLs": false,
	"uploaded": "2022-06-30T17:53:12.511981Z",
	"uploadExpiry": "2022-07-01T17:53:12.511973Z",
	"maxSizeBytes": null,
	"maxDurationSeconds": null,
	"duration": 5.5,
	"input": {
		"width": 560,
		"height": 320
	},
	"playback": {
		"hls": "https://customer-f33zs165nr7gyfy4.cloudflarestream.com/6b9e68b07dfee8cc2d116e4c51d6a957/manifest/video.m3u8",
		"dash": "https://customer-f33zs165nr7gyfy4.cloudflarestream.com/6b9e68b07dfee8cc2d116e4c51d6a957/manifest/video.mpd"
	},
	"watermark": null
}

Коды ошибок

Если видео не удалось успешно обработать, state поле возвращает error, и errReasonCode возвращает одно из значений, перечисленных ниже.

Помимо state поле, у видео readyToStream поле также должно быть true для воспроизведения видео.

Пример ответа с ошибкой
{
  "readyToStream": false,
  "status": {
    "state": "error",
    "step": "encoding",
    "pctComplete": "39",
    "errReasonCode": "ERR_MALFORMED_VIDEO",
    "errReasonText": "The video was deemed to be corrupted or malformed.",
  }
}

Проверка подлинности webhook

Cloudflare Stream подписывает запросы webhook, отправляемые на ваши URL уведомлений, и включает подпись каждого запроса в Webhook-Signature HTTP-заголовок. Это позволяет вашему приложению убедиться, что запросы вебхуков отправлены Stream.

Чтобы проверить подпись, нужно получить секрет подписи webhook. Это значение возвращается в ответе API при создании или получении webhook.

Чтобы проверить подпись, получите значение Webhook-Signature заголовок, который будет выглядеть примерно так, как в примере ниже.

Webhook-Signature: time=1230811200,sig1=60493ec9388b44585a29543bcf0de62e377d4da393246a8b1c901d0e3e672404

1. Разбор подписи

Получите Webhook-Signature заголовок из запроса вебхука и разделите строку с помощью , символ.

Разделите каждое значение ещё раз с помощью = символ.

Значение для time это текущий время UNIX ↗ когда сервер отправил запрос. sig1 это подпись тела запроса.

На этом этапе следует отклонять запросы с отметками времени, которые слишком устарели для вашего приложения.

2. Создание исходной строки для подписи

Подготовьте исходную строку подписи, объединив следующие строки:

Для успешной проверки подписи каждый байт тела запроса должен оставаться неизменным.

3. Создание ожидаемой подписи

Вычислите HMAC с помощью функции SHA256 (HMAC-SHA256), используя секрет webhook и исходную строку из шага 2. Этот шаг зависит от языка программирования, используемого в вашем приложении.

Подпись Cloudflare кодируется в шестнадцатеричном формате.

4. Сравнение ожидаемой и фактической подписей

Сравните подпись в заголовке запроса с ожидаемой подписью. Желательно использовать функцию сравнения с постоянным временем выполнения.

Если подписи совпадают, можно быть уверенным, что вебхук отправлен Cloudflare.

Ограничения

Примеры

Golang

Использование crypto/hmac ↗:

package main

import (
 "crypto/hmac"
 "crypto/sha256"
 "encoding/hex"
 "log"
)

func main() {
 secret := []byte("secret from the Cloudflare API")
 message := []byte("string from step 2")

 hash := hmac.New(sha256.New, secret)
 hash.Write(message)

 hashToCheck := hex.EncodeToString(hash.Sum(nil))

 log.Println(hashToCheck)
}

Node.js

var crypto = require("crypto");

var key = "secret from the Cloudflare API";
var message = "string from step 2";

var hash = crypto.createHmac("sha256", key).update(message);

hash.digest("hex");

Ruby

    require 'openssl'

    key = 'secret from the Cloudflare API'
    message = 'string from step 2'

    OpenSSL::HMAC.hexdigest('sha256', key, message)

На JavaScript (например, для использования в Cloudflare Workers)

const key = "secret from the Cloudflare API";
const message = "string from step 2";

const getUtf8Bytes = (str) =>
	new Uint8Array(
		[...decodeURIComponent(encodeURIComponent(str))].map((c) =>
			c.charCodeAt(0),
		),
	);

const keyBytes = getUtf8Bytes(key);
const messageBytes = getUtf8Bytes(message);

const cryptoKey = await crypto.subtle.importKey(
	"raw",
	keyBytes,
	{ name: "HMAC", hash: "SHA-256" },
	true,
	["sign"],
);
const sig = await crypto.subtle.sign("HMAC", cryptoKey, messageBytes);

[...new Uint8Array(sig)].map((b) => b.toString(16).padStart(2, "0")).join("");