Skip to content

Webhooki ​

Zakładka Webhooki w /nay (scope nay.admin) wysyła zdarzenia skryptów na Twoje adresy URL. Wybierz zdarzenia (albo wszystkie), naciśnij Testuj, aby sprawdzić konfigurację, i podglądaj ostatnią odpowiedź każdego webhooka.

Są dwa typy:

  • Discord: wklej adres URL webhooka kanału Discord (https://discord.com/api/webhooks/...). Każde zdarzenie staje się embedem, z tytułem i etykietami w języku serwera oraz polami zdarzenia w kolejności. Formatowanie markdown Discorda w wartościach jest neutralizowane, nikt nie jest oznaczany, a zbyt długie wiadomości są przycinane do limitu 6000 znaków.
  • Podpisany JSON: dla Twojej własnej strony lub bota. Każdy webhook dostaje sekret, pokazywany przy utworzeniu lub ponownym wygenerowaniu.

Dostarczanie ​

Dostarczenie to POST z JSON:

json
{ "id": "3f9c2a1b7d4e8f60", "event": "nay_car_wash.wash", "resource": "nay_car_wash", "time": 1791670794, "data": { "player": "John", "price": 150 } }

Nagłówki: X-Nay-Event, X-Nay-Delivery (to samo co id), X-Nay-Timestamp (sekundy Unix) i X-Nay-Signature: sha256=<hex>.

  • Odpowiedz dowolnym statusem 2xx. Brak odpowiedzi w ciągu 15 sekund liczy się jako błąd sieci.
  • Błędy sieci oraz odpowiedzi 5xx i 429 są ponawiane po 1, 10 i 60 sekundach z tym samym X-Nay-Delivery. Pozostałe odpowiedzi 4xx nie są ponawiane.
  • Po 20 nieudanych dostarczeniach z rzędu webhook jest wyłączany. Włącz go ponownie w zakładce albo zapisz go z nowym adresem URL.
  • Dostarczenia do Discorda nie są podpisywane i przy limitowaniu respektują retry_after Discorda.

Zdarzenia ​

Zdarzenia nay_lib:

ZdarzenieKiedyDane
nay.settingUstawienie zostało zmienione lub przywrócone.resource, key, action, actor
nay.permissionReguła uprawnień została nadana lub odebrana.action, type, identifier, scope, actor
nay.tokenToken API został utworzony lub unieważniony.action, id, label, actor
nay.testPrzycisk Testuj.message

Każdy skrypt wymienia swoje zdarzenia na własnej stronie, na przykład Car Wash.

Sprawdzanie podpisu ​

Zanim zaufasz podpisanemu dostarczeniu, sprawdź jego podpis: HMAC-SHA256 z <X-Nay-Timestamp>.<raw body>, z kluczem w postaci sekretu dokładnie tak, jak został pokazany (sam tekst hex). Odrzucaj stare znaczniki czasu.

Node.js (Express):

js
import { createHmac, timingSafeEqual } from "node:crypto";
import express from "express";

const app = express();
app.post("/nayretis", express.raw({ type: "application/json" }), (req, res) => {
	const timestamp = req.get("X-Nay-Timestamp") ?? "";
	const expected = "sha256=" + createHmac("sha256", process.env.NAY_WEBHOOK_SECRET).update(`${timestamp}.${req.body}`).digest("hex");
	const given = req.get("X-Nay-Signature") ?? "";
	const valid = given.length === expected.length && timingSafeEqual(Buffer.from(given), Buffer.from(expected));
	if (!valid || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
		return res.sendStatus(401);
	}
	const delivery = JSON.parse(req.body);
	res.sendStatus(204);
});

PHP:

php
<?php
$body = file_get_contents('php://input');
$timestamp = $_SERVER['HTTP_X_NAY_TIMESTAMP'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $body, getenv('NAY_WEBHOOK_SECRET'));
if (!hash_equals($expected, $_SERVER['HTTP_X_NAY_SIGNATURE'] ?? '') || abs(time() - (int) $timestamp) > 300) {
	http_response_code(401);
	exit;
}
$delivery = json_decode($body, true);
http_response_code(204);