cli.gs
Sign in

İmzalı istekler

İsteklerini HMAC imzasıyla koru.

Tek başına bir API anahtarı, her istekle birlikte yolculuk eden bir paroladır. Sızarsa, örneğin bir günlük dosyası veya yanlış yapılandırılmış bir eklenti yoluyla, elinde olan herkes programın için dönüşüm bildirebilir. Bu sayfada her isteği sunucundan asla çıkmayan ayrı bir İmza anahtarı ile nasıl imzalayacağını ve cli.gs'nin imzasız her şeyi nasıl reddedeceğini öğrenirsin.

Kısaca:

  • İmza anahtarı ilk API anahtarınla birlikte gelir ve yalnızca bir kez gösterilir.
  • Her istek üç başlık taşır: bir zaman damgası, tek kullanımlık bir nonce ve bir HMAC-SHA256 imzası.
  • Tam olarak gönderdiğin baytları imzala. İmza hatalarının çoğu gövdenin yeniden kodlanmasından kaynaklanır.
  • Önce imzalı isteklerle test et, sonra İmzasız istekleri reddet kutusunu işaretle.

İmza anahtarı nereden gelir

İmza anahtarı ilk API anahtarınla birlikte gösterilir. Onu entegrasyon sayfasında API anahtarı altında, İmza anahtarı etiketiyle bulursun. API anahtarı gibi yalnızca bir kez gösterilir. Mağazanın gizli anahtar yapılandırmasında API anahtarının yanında sakla.

API anahtarı ve imzalı istekler
API anahtarının altındaki İmzalı istekler bölümü

Daha sonra yeni bir anahtar üretmek aynı imza anahtarını korur. Anahtar değiştirirken istekler geçerli kalır.

Üç başlık

İmzalı bir istek üç ek başlık taşır:

BaşlıkDeğer
X-Cligs-TimestampUnix saniye cinsinden geçerli zaman, ör. 1790000000
X-Cligs-NonceRastgele, tek kullanımlık bir değer, 8 ile 128 karakter arası (harfler, rakamlar ve . _ ~ : + / = -)
X-Cligs-SignatureKüçük harfli hex olarak HMAC-SHA256 imzası

Nonce, yalnızca bir kez kullandığın bir değerdir. Yakalanan bir isteğin yeniden oynatılmasını engeller.

Ne imzalanır

İmza, yeni satır (\n) ile birleştirilen beş satır üzerinden hesaplanır:

text
POST
/api/v1/track/conversion
1790000000
3f9c2b7e41d04a8b9e6f0c1d2a3b4c5d
<hex SHA-256 of the exact request body>

Beş satır şunlardır: büyük harfle HTTP yöntemi, ana bilgisayar ve sorgu dizesi olmadan yol, zaman damgası, nonce ve gövdenin hex olarak SHA-256 özeti. HMAC anahtarı, tam gösterildiği haliyle düz bir dize olarak kullanılan imza anahtarıdır.

Bir isteği ne zaman kabul ederiz

  • Zaman damgası saatimizden en fazla beş dakika sapıyorsa. Sunucu saatini NTP ile eşitlenmiş tut.
  • Nonce daha önce programın tarafından kullanılmadıysa.
  • İmza, aldığımız gövdeyle bayt bayt eşleşiyorsa.

Node.js yardımcısı

js
import crypto from "node:crypto";

const BASE_URL = "https://cli.gs";
const API_KEY = process.env.CLIGS_API_KEY;
const SIGNING_SECRET = process.env.CLIGS_SIGNING_SECRET;

// Returns the three X-Cligs-* headers for one request.
export function cligsSignatureHeaders(method, path, body, secret = SIGNING_SECRET) {
  const timestamp = String(Math.floor(Date.now() / 1000));
  const nonce = crypto.randomBytes(16).toString("hex");
  const bodyHash = crypto.createHash("sha256").update(body, "utf8").digest("hex");
  const canonical = [method.toUpperCase(), path, timestamp, nonce, bodyHash].join("\n");
  const signature = crypto.createHmac("sha256", secret).update(canonical, "utf8").digest("hex");
  return {
    "X-Cligs-Timestamp": timestamp,
    "X-Cligs-Nonce": nonce,
    "X-Cligs-Signature": signature,
  };
}

// Sends a signed POST to the cli.gs API.
export async function cligsPost(path, payload) {
  const body = JSON.stringify(payload); // sign exactly the bytes you send
  const res = await fetch(BASE_URL + path, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
      ...cligsSignatureHeaders("POST", path, body),
    },
    body,
    signal: AbortSignal.timeout(5000),
  });
  return { status: res.status, data: await res.json().catch(() => null) };
}

// Usage:
// await cligsPost("/api/v1/track/conversion", { ref, orderId: "100234", amount: "149.99", currency: "EUR" });
// await cligsPost("/api/v1/track/reversal", { orderId: "100234", reason: "RETURN" });

PHP yardımcısı

php
<?php
// Returns the three X-Cligs-* headers for one request, ready for CURLOPT_HTTPHEADER.
function cligs_signature_headers(string $method, string $path, string $body, string $secret): array {
    $timestamp = (string) time();
    $nonce     = bin2hex(random_bytes(16));
    $canonical = implode("\n", [strtoupper($method), $path, $timestamp, $nonce, hash('sha256', $body)]);
    $signature = hash_hmac('sha256', $canonical, $secret);

    return [
        'X-Cligs-Timestamp: ' . $timestamp,
        'X-Cligs-Nonce: ' . $nonce,
        'X-Cligs-Signature: ' . $signature,
    ];
}

// Sends a signed POST to the cli.gs API.
function cligs_post(string $path, array $payload): array {
    $body = json_encode($payload); // sign exactly the bytes you send
    $ch = curl_init('https://cli.gs' . $path);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 5,
        CURLOPT_POSTFIELDS     => $body,
        CURLOPT_HTTPHEADER     => array_merge([
            'Authorization: Bearer ' . getenv('CLIGS_API_KEY'),
            'Content-Type: application/json',
        ], cligs_signature_headers('POST', $path, $body, getenv('CLIGS_SIGNING_SECRET'))),
    ]);
    $response = curl_exec($ch);
    $status   = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);
    return ['status' => $status, 'body' => json_decode((string) $response, true)];
}

WordPress'te aynı başlıkları wp_remote_post() fonksiyonuna ilişkisel dizi olarak geçir. wp_json_encode() fonksiyonunu bir kez çağır ve sonucu hem gövde hem imza için kullan.

"İmzasız istekleri reddet" seçeneğini aç

Sen açana kadar imzalama isteğe bağlıdır. İmzası olan bir istek kontrol edilir. İmzasız bir istek yalnızca API anahtarıyla kabul edilir. Mağazan her isteği imzalamaya başladığında:

  1. Birkaç imzalı test dönüşümü gönder ve kabul edildiklerini kontrol et.
  2. İmzalı istekler altında İmzasız istekleri reddet kutusunu işaretle.
  3. Kaydet düğmesine tıkla.

Bundan sonra geçerli imzası olmayan her dönüşüm ve iptal isteği reddedilir.

Bir imza reddedildiğinde

İmza sorunu, HTTP 401 ve error içinde kısa bir nedenle yanıtlanır:

errorNeden
signature requiredİmzasız istekleri reddet açık ve isteğin imzası yoktu
stale or missing timestampZaman damgası eksik, saniye cinsinden değil veya beş dakikadan fazla sapıyor
invalid nonceNonce eksik, çok kısa, çok uzun veya başka karakterler içeriyor
nonce already usedAynı nonce iki kez gönderildi. Yeniden denemeler dahil her istek için yeni bir tane üret
invalid signatureİmza eşleşmiyor
no signing secret issued for this programmeİmza gönderdin ama programın imza anahtarı yok

invalid signature hatalarının çoğu, gönderilenden farklı bir şeyi imzalamaktan kaynaklanır. Tipik nedenler: JSON'u imzaladıktan sonra yeniden kodlamak, yol yerine tam URL'yi imzalamak veya gövdeye boşluk ekleyen bir çerçeve. Gövde dizesini bir kez oluştur ve her ikisi için de onu kullan.

Sonraki adımlar

İstekler imzalandığına göre iadeleri ve iptalleri kur.