Plugin do nagród

Plugin działa w modelu pull: serwer pyta API o oczekujące nagrody i potwierdza claim podpisem HMAC.

Jak działa plugin

GlosujMCVote bezpiecznie łączy Twój serwer z GłosujMC.pl. Wybierz Universal dla Minecraft 1.16.5-1.21.x, Paper-native dla 1.21.11 i 26.x+ albo Legacy dla 1.8.8-1.15.2.

Instalacja

1. Pobierz plik .jar.
2. Wrzuć do folderu plugins/.
3. Uzupełnij api_key i secret z panelu właściciela.
4. Zrestartuj serwer.

Dokumentacja API - własna integracja nagród (kliknij, aby rozwinąć)

Nie musisz używać naszego pluginu - możesz podłączyć się pod API samodzielnie. Służy ono do odbioru nagród za głosy i raportowania statusu serwera.

1. Klucze

W panelu właściciela (zakładka Twojego serwera) znajdziesz api_key oraz secret. secret nigdy nie jest wysyłany w żądaniu - służy tylko do policzenia podpisu HMAC.

2. Uwierzytelnianie (HMAC SHA-256)

Każde żądanie (poza sprawdzeniem wersji) wymaga 4 nagłówków:

  • X-MP-Api-Key - Twój api_key
  • X-MP-Timestamp - aktualny czas UNIX w sekundach (zegar serwera musi być zsynchronizowany, tolerancja ~kilka minut)
  • X-MP-Nonce - losowy, unikalny ciąg na każde żądanie (chroni przed powtórzeniem)
  • X-MP-Signature - podpis HMAC-SHA256 (hex, małe litery)

Podpis liczysz z ciągu kanonicznego (pola sklejone znakiem nowej linii \n):

METODA (wielkimi, np. GET/POST)
/api/plugin/... (ścieżka z ukośnikiem na początku)
timestamp
nonce
treść żądania (surowe body; dla GET pusty ciąg)
signature = lowercase( HMAC_SHA256( canonical, secret ) )

3. Endpointy

Baza: https://glosujmc.pl/api/plugin

MetodaŚcieżkaOpis
POST/heartbeatSygnał życia serwera. Body: plugin_version, server_version, online_players, metadata. Włącza też automatycznie „Nagrody za głosy”.
GET/rewards/pendingLista oczekujących nagród do wydania. Zwraca rewards: [{ claim_token, player, reward_key, created_at }].
POST/rewards/claimPotwierdzenie WYDANIA nagrody w grze. Body: claim_token. Nagroda znika z kolejki (nie da się wydać dwa razy).
POST/rewards/failZgłoszenie, że nie udało się wydać (np. gracz offline). Body: claim_token, error. Zostanie w kolejce.
GET/server/configKonfiguracja serwera (m.in. rewards_enabled).
GET/version?channel=universalNajnowsza wersja pluginu (bez autoryzacji).

4. Przepływ odbioru nagród

  1. Co jakiś czas (np. co 30-60 s) odpytujesz GET /rewards/pending.
  2. Dla każdego wpisu wydajesz nagrodę graczowi w grze wg reward_key (np. odpalasz komendę zdefiniowaną w configu pod tym kluczem).
  3. Po udanym wydaniu wysyłasz POST /rewards/claim z claim_token - to usuwa nagrodę z kolejki.
  4. Jeśli gracz był offline/coś padło - POST /rewards/fail, nagroda zostaje na później.
Odpowiedź na częste pytanie: tak, możesz zaimplementować odbiór samodzielnie - wystarczą powyższe endpointy i podpis HMAC. To zwykłe REST + HMAC, więc podepniesz się z dowolnego języka bez problemu. Pełny, działający przykład masz też w naszym otwartym pluginie na GitHubie.

5. Przykłady kodu

Java - policz podpis i pobierz oczekujące nagrody:

String apiKey = "TWOJ_API_KEY";
String secret = "TWOJ_SECRET";
String method = "GET";
String path   = "/api/plugin/rewards/pending";
String body   = "";                          // GET = pusty body
long ts       = System.currentTimeMillis() / 1000L;
String nonce  = java.util.UUID.randomUUID().toString();

String canonical = String.join("\n", method, path, String.valueOf(ts), nonce, body);
javax.crypto.Mac mac = javax.crypto.Mac.getInstance("HmacSHA256");
mac.init(new javax.crypto.spec.SecretKeySpec(secret.getBytes(java.nio.charset.StandardCharsets.UTF_8), "HmacSHA256"));
byte[] raw = mac.doFinal(canonical.getBytes(java.nio.charset.StandardCharsets.UTF_8));
StringBuilder sig = new StringBuilder();
for (byte b : raw) sig.append(String.format("%02x", b));   // hex, male litery

java.net.HttpURLConnection con = (java.net.HttpURLConnection)
        new java.net.URL("https://glosujmc.pl" + path).openConnection();
con.setRequestProperty("X-MP-Api-Key",  apiKey);
con.setRequestProperty("X-MP-Timestamp", String.valueOf(ts));
con.setRequestProperty("X-MP-Nonce",     nonce);
con.setRequestProperty("X-MP-Signature", sig.toString());
// -> odczytaj JSON: rewards[]. Dla kazdej: wydaj nagrode graczowi wg reward_key,
//    potem POST /api/plugin/rewards/claim z body {"claim_token":"..."} (podpis liczysz z TEGO body).

PHP - to samo, w kilku liniach:

$apiKey = 'TWOJ_API_KEY';
$secret = 'TWOJ_SECRET';
$method = 'GET';
$path   = '/api/plugin/rewards/pending';
$body   = '';
$ts     = time();
$nonce  = bin2hex(random_bytes(16));

$canonical = implode("\n", [$method, $path, $ts, $nonce, $body]);
$sig = hash_hmac('sha256', $canonical, $secret);   // hex, male litery

$ch = curl_init('https://glosujmc.pl' . $path);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "X-MP-Api-Key: $apiKey",
        "X-MP-Timestamp: $ts",
        "X-MP-Nonce: $nonce",
        "X-MP-Signature: $sig",
    ],
]);
$rewards = json_decode(curl_exec($ch), true)['rewards'] ?? [];
// dla POST /rewards/claim: $body='{"claim_token":"..."}'; i policz podpis z tym body.

Uwaga: przy POST podpis liczysz z dokładnie tym samym surowym body, które wysyłasz. Nonce musi być unikalny na każde żądanie, a zegar serwera zsynchronizowany (NTP).