ThunderPhone 2.0 ಈಗ ಬಿಡುಗಡೆಯಾಗಿದೆ.ನೀವೇ ನೇರವಾಗಿ ಆರಂಭಿಸಿ — 2¢/ನಿಮಿಷದಿಂದ.ಘೋಷಣೆ ಓದಿ

Operations

ವೆಬ್‌ಹುಕ್ ಸಹಿಗಳನ್ನು ಪರಿಶೀಲಿಸಿ

ThunderPhone ಕಳುಹಿಸುವ ಪ್ರತಿಯೊಂದು ವೆಬ್‌ಹುಕ್ ಮತ್ತು ಉಪಕರಣ ವಿನಂತಿಗೆ ಸಮಯಮುದ್ರೆಯೊಂದಿಗೆ ಸಹಿ ಮಾಡಲಾಗುತ್ತದೆ. ಇಲ್ಲಿನ ವಿಧಾನ ಅಥವಾ SDK ಸಹಾಯಕದ ಮೂಲಕ ಅದನ್ನು ಪರಿಶೀಲಿಸಿ ಮತ್ತು ಐದು ನಿಮಿಷಗಳಿಗಿಂತ ಹಳೆಯದಾದ ಮರುಪ್ರಸಾರಗೊಂಡ ವಿನಂತಿಗಳನ್ನು ತಿರಸ್ಕರಿಸಿ.

ನಿಮ್ಮ ಸರ್ವರ್‌ಗೆ ನಾವು ಕಳುಹಿಸುವ ಪ್ರತಿಯೊಂದು ವಿನಂತಿಯು (webhook ವಿತರಣೆಗಳು, ಹಳೆಯ ಏಕ-URL webhook ಮತ್ತು ಟೂಲ್-ಎಂಡ್‌ಪಾಯಿಂಟ್ ಕರೆಗಳು) ಎರಡು ಸಹಿ ಹೆಡರ್‌ಗಳನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಎರಡೂ ಒಂದೇ ರಹಸ್ಯದೊಂದಿಗೆ HMAC-SHA256 ಆಗಿರುತ್ತವೆ.

ಹೆಡರ್ಸಹಿ ಮಾಡುವವುಮರುಪ್ರಸಾರ ರಕ್ಷಣೆ
X-ThunderPhone-Signature-V2 (ಶಿಫಾರಸು ಮಾಡಲಾಗಿದೆ)ಸಮಯಮುದ್ರೆ, ವಿಧಾನ, ಪಥ, ಕ್ವೆರಿ ಮತ್ತು ಬಾಡಿ5 ನಿಮಿಷಗಳಿಗಿಂತ ಹಳೆಯ ವಿನಂತಿಗಳನ್ನು ತಿರಸ್ಕರಿಸಿ
X-ThunderPhone-Signatureಬಾಡಿ ಮಾತ್ರಯಾವುದೂ ಇಲ್ಲ: ಸೆರೆಹಿಡಿದ ವಿನಂತಿಯು ಶಾಶ್ವತವಾಗಿ ಪರಿಶೀಲನೆಗೊಳ್ಳುತ್ತದೆ

ಹೊಸ ಏಕೀಕರಣಗಳಲ್ಲಿ X-ThunderPhone-Signature-V2 ಅನ್ನು ಪರಿಶೀಲಿಸಿ ಮತ್ತು ಅಸ್ತಿತ್ವದಲ್ಲಿರುವವುಗಳನ್ನು ಅದಕ್ಕೆ ವರ್ಗಾಯಿಸಿ. X-ThunderPhone-Signature ಅನ್ನು ಇನ್ನೂ ಪ್ರತಿಯೊಂದು ವಿನಂತಿಯಲ್ಲೂ ಬದಲಾವಣೆ ಇಲ್ಲದೆ ಕಳುಹಿಸಲಾಗುತ್ತದೆ, ಆದ್ದರಿಂದ ಅದರ ಆಧಾರದ ಮೇಲೆ ನಿರ್ಮಿಸಲಾದ ಪರಿಶೀಲಕಗಳು ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತಲೇ ಇರುತ್ತವೆ. ಅದನ್ನು ಕಳುಹಿಸುವುದನ್ನು ನಿಲ್ಲಿಸುವ ಮೊದಲು ನಾವು ದಿನಾಂಕವನ್ನು ಪ್ರಕಟಿಸುತ್ತೇವೆ.

ಸಹಿ V2

X-ThunderPhone-Signature-V2: t=1767225600,v1=03a89bec521f78d55727237ca4713bb0b8dcdf2e09e450865b5b5637b80c1c4e
  • t ಎಂಬುದು ನಾವು ವಿನಂತಿಯನ್ನು ಕಳುಹಿಸಿದಾಗಿನ ಸೆಕೆಂಡುಗಳಲ್ಲಿನ Unix ಸಮಯವಾಗಿದೆ. ಮರುಪ್ರಯತ್ನಿಸಿದ ವಿತರಣೆಯನ್ನು ಕಳುಹಿಸುವಾಗ ತನ್ನದೇ ಆದ t ನೊಂದಿಗೆ ಮತ್ತೆ ಸಹಿ ಮಾಡಲಾಗುತ್ತದೆ.
  • v1 ಎಂಬುದು ನಿಮ್ಮ ಸೀಕ್ರೆಟ್‌ನಿಂದ ಕೀ ಮಾಡಲಾದ, ಕೆಳಗಿನ ಸಹಿ ಮಾಡಿದ ಸ್ಟ್ರಿಂಗ್‌ನ ಹೆಕ್ಸ್ HMAC-SHA256 ಆಗಿದೆ.

ಮೌಲ್ಯವು ಅಲ್ಪವಿರಾಮದಿಂದ ಬೇರ್ಪಡಿಸಲಾದ key=value ಜೋಡಿಗಳ ಪಟ್ಟಿಯಾಗಿದೆ. ನಿಮಗೆ ಗುರುತಿಸಲಾಗದ ಕೀಗಳನ್ನು ನಿರ್ಲಕ್ಷಿಸಿ, ಮತ್ತು ಯಾವುದೇ v1 ಹೊಂದಿಕೆಯಾದರೆ ವಿನಂತಿಯನ್ನು ಸ್ವೀಕರಿಸಿ: ಭವಿಷ್ಯದ ಬದಲಾವಣೆಯ ಸಮಯದಲ್ಲಿ ನಾವು ಎರಡನೇ ಸಹಿಯನ್ನು ಸೇರಿಸಬಹುದು.

ಸಹಿ ಮಾಡಿದ ಸ್ಟ್ರಿಂಗ್

ನಾಲ್ಕು ಕ್ಷೇತ್ರಗಳು, ಕೊನೆಯದನ್ನು ಹೊರತುಪಡಿಸಿ ಪ್ರತಿಯೊಂದರ ನಂತರ ಒಂದು ಹೊಸ ಸಾಲು (\n, ಬೈಟ್ 0x0A):

<t>\n<METHOD>\n<path and query>\n<body>
ಕ್ಷೇತ್ರಮೌಲ್ಯ
tಹೆಡರ್‌ನಿಂದ t ಮೌಲ್ಯ
METHODದೊಡ್ಡ ಅಕ್ಷರಗಳಲ್ಲಿರುವ HTTP ವಿಧಾನ: POST, GET, PUT, PATCH ಅಥವಾ DELETE
ಪಾತ್ ಮತ್ತು ಕ್ವೆರಿHTTP ವಿನಂತಿ ಸಾಲಿನಿಂದ ವಿನಂತಿ ಗುರಿ: ಪಾತ್, ನಂತರ ?, ಮತ್ತು ಕ್ವೆರಿ ಸ್ಟ್ರಿಂಗ್ ಇದ್ದಾಗ ಅದು. ಸ್ಕೀಮ್, ಹೋಸ್ಟ್ ಅಥವಾ ಫ್ರ್ಯಾಗ್ಮೆಂಟ್ ಇಲ್ಲ. ಡಿಕೋಡ್ ಮಾಡದೆ ಅಥವಾ ಪ್ಯಾರಾಮೀಟರ್‌ಗಳನ್ನು ಮರುಕ್ರಮಗೊಳಿಸದೆ, ಬಂದಂತೆಯೇ ನಿಖರವಾಗಿ ಬಳಸಿ
bodyಕಚ್ಚಾ ವಿನಂತಿ ಬಾಡಿ. GET ಮತ್ತು DELETE ಟೂಲ್ ಕರೆಗಳಿಗೆ ಬಾಡಿ ಇರುವುದಿಲ್ಲ, ಆದ್ದರಿಂದ ಅವುಗಳ ಸಹಿ ಮಾಡಿದ ಸ್ಟ್ರಿಂಗ್ ಪಾತ್‌ನ ನಂತರದ ಹೊಸ ಸಾಲಿನೊಂದಿಗೆ ಕೊನೆಗೊಳ್ಳುತ್ತದೆ

ಪರಿಶೀಲಿಸಲು:

  1. ಯಾವುದೇ ಪಾರ್ಸಿಂಗ್‌ಗಿಂತ ಮೊದಲು, ಹೆಡರ್, ವಿಧಾನ, ಕಚ್ಚಾ ಪಾತ್ ಮತ್ತು ಕ್ವೆರಿ, ಹಾಗೂ ಕಚ್ಚಾ ಬಾಡಿಯನ್ನು ಓದಿ.
  2. ಹೆಡರ್‌ನಿಂದ t ಮತ್ತು ಪ್ರತಿಯೊಂದು v1 ತೆಗೆದುಕೊಳ್ಳಿ.
  3. t ನಿಮ್ಮ ಗಡಿಯಾರಕ್ಕಿಂತ 300 ಸೆಕೆಂಡುಗಳು ಹೆಚ್ಚು ಹಿಂದೆ ಅಥವಾ ಮುಂದೆ ಇದ್ದರೆ ವಿನಂತಿಯನ್ನು ತಿರಸ್ಕರಿಸಿ.
  4. ನಿಮ್ಮ ಸೀಕ್ರೆಟ್‌ನೊಂದಿಗೆ ಸಹಿ ಮಾಡಿದ ಸ್ಟ್ರಿಂಗ್‌ನ ಹೆಕ್ಸ್ HMAC-SHA256 ಲೆಕ್ಕಹಾಕಿ.
  5. ಅದನ್ನು v1 ಜೊತೆಗೆ ಸ್ಥಿರ ಸಮಯದಲ್ಲಿ ಹೋಲಿಸಿ. ಯಾವುದೂ ಹೊಂದಿಕೆಯಾಗದಿದ್ದರೆ 401 ಪ್ರತಿಕ್ರಿಯಿಸಿ.

ಕಾರ್ಯನಿರ್ವಹಿಸಿದ ಉದಾಹರಣೆ

ಸೀಕ್ರೆಟ್ whsec_example_4c1f2a9b. ನಾವು ಈ ವಿನಂತಿಯನ್ನು t = 1767225600 (2026-01-01 00:00:00 UTC) ಸಮಯದಲ್ಲಿ ಕಳುಹಿಸುತ್ತೇವೆ:

POST /tools/lookup?region=us HTTP/1.1
Host: api.example.com
Content-Type: application/json
X-ThunderPhone-Signature-V2: t=1767225600,v1=03a89bec521f78d55727237ca4713bb0b8dcdf2e09e450865b5b5637b80c1c4e
 
{"customer_id":"cust_123"}

ಸಹಿ ಮಾಡಿದ ಸ್ಟ್ರಿಂಗ್ ಬಾಡಿಯ ನಂತರ ಹೊಸ ಸಾಲಿಲ್ಲದ ಈ ನಾಲ್ಕು ಸಾಲುಗಳಾಗಿದೆ:

1767225600
POST
/tools/lookup?region=us
{"customer_id":"cust_123"}

ಇದರ HMAC-SHA256 03a89bec521f78d55727237ca4713bb0b8dcdf2e09e450865b5b5637b80c1c4e ಆಗಿದೆ. ಇದರ ವಿರುದ್ಧ ನಿಮ್ಮ ಅನುಷ್ಠಾನವನ್ನು ಪರಿಶೀಲಿಸಿ, ಅಥವಾ openssl ಬಳಸಿ ಅದನ್ನು ಮರುಸೃಷ್ಟಿಸಿ:

printf '1767225600\nPOST\n/tools/lookup?region=us\n{"customer_id":"cust_123"}' \
  | openssl dgst -sha256 -hmac 'whsec_example_4c1f2a9b'

ಅದೇ ಸೆಕೆಂಡಿನಲ್ಲಿ /tools/lookup?customer_id=cust_123 ಗೆ ಮಾಡುವ GET ಟೂಲ್ ಕರೆಗೆ ಖಾಲಿ ಬಾಡಿ ಇರುತ್ತದೆ. ಇದರ ಸಹಿ ಮಾಡಿದ ಸ್ಟ್ರಿಂಗ್ 1767225600\nGET\n/tools/lookup?customer_id=cust_123\n ಆಗಿದ್ದು, ಇದರ ಸಹಿ 3ce214cb0b8f2bf39b1d19d4e7265df9dbaff5a5f838d3cc6c753a8f7a4ad280 ಆಗಿದೆ.

SDKಗಳೊಂದಿಗೆ

Python ಮತ್ತು TypeScript SDKಗಳು ಸಹಾಯಕವನ್ನು ಒಳಗೊಂಡಿವೆ (thunderphone 0.2.0 ಅಥವಾ ನಂತರದ್ದು, @thunderphone/sdk 0.2.0 ಅಥವಾ ನಂತರದ್ದು). ಇದು 5-ನಿಮಿಷದ ಸಮಯಾವಕಾಶವನ್ನು ಪರಿಶೀಲಿಸುತ್ತದೆ, ಸ್ಥಿರ ಸಮಯದಲ್ಲಿ ಹೋಲಿಸುತ್ತದೆ ಮತ್ತು ಸೇವೆ ಸ್ಥಗಿತವಿಲ್ಲದೆ ರೊಟೇಟ್ ಮಾಡಲು ಸೀಕ್ರೆಟ್‌ಗಳ ಪಟ್ಟಿಯನ್ನು ಸ್ವೀಕರಿಸುತ್ತದೆ.

Python
from thunderphone import verify_signature
 
ok = verify_signature(
    header,            # the X-ThunderPhone-Signature-V2 value
    secret=SECRET,     # or [NEW_SECRET, OLD_SECRET] while rotating
    method=method,     # "POST"
    path=path,         # "/tools/lookup?region=us", exactly as received
    body=raw_body,     # bytes, before any JSON parsing
    tolerance=300,     # optional; seconds
)
Node.js
import { verifySignature } from "@thunderphone/sdk";
 
const ok = verifySignature({
  header,               // the X-ThunderPhone-Signature-V2 value
  secret: SECRET,       // or [NEW_SECRET, OLD_SECRET] while rotating
  method,               // "POST"
  path,                 // "/tools/lookup?region=us", exactly as received
  body: rawBody,        // Buffer or string, before any JSON parsing
  toleranceSeconds: 300, // optional
});

SDK ಇಲ್ಲದೆ

Python
import hashlib
import hmac
import time
 
TOLERANCE_SECONDS = 300
 
 
def verify_v2(header: str, secret: str, method: str, path: str, body: bytes) -> bool:
    """path is the path plus ?query exactly as received; body is the raw body."""
    timestamp, signatures = None, []
    for item in (header or "").split(","):
        key, _, value = item.strip().partition("=")
        if key == "t" and value.isdigit() and len(value) <= 15:
            timestamp = int(value)
        elif key == "v1":
            signatures.append(value)
    if timestamp is None or abs(time.time() - timestamp) > TOLERANCE_SECONDS:
        return False
    signed = f"{timestamp}\n{method.upper()}\n{path}\n".encode() + body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return any(hmac.compare_digest(expected.encode(), s.encode()) for s in signatures)
Node.js
import crypto from "node:crypto";
 
const TOLERANCE_SECONDS = 300;
 
// path is the path plus ?query exactly as received; body is the raw Buffer.
export function verifyV2(header, secret, method, path, body) {
  let timestamp;
  const signatures = [];
  for (const item of (header || "").split(",")) {
    const [key, value = ""] = item.trim().split("=", 2);
    if (key === "t" && /^\d+$/.test(value)) timestamp = Number(value);
    else if (key === "v1") signatures.push(value);
  }
  if (timestamp === undefined) return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > TOLERANCE_SECONDS) return false;
  const expected = Buffer.from(
    crypto
      .createHmac("sha256", secret)
      .update(`${timestamp}\n${method.toUpperCase()}\n${path}\n`)
      .update(body)
      .digest("hex"),
  );
  return signatures.some((sig) => {
    const candidate = Buffer.from(sig);
    return (
      candidate.length === expected.length &&
      crypto.timingSafeEqual(candidate, expected)
    );
  });
}

ಫ್ರೇಮ್‌ವರ್ಕ್ ಜೋಡಣೆ

ಪ್ರತಿಯೊಂದು ಉದಾಹರಣೆಯು ಮೂಲ ಪಥ ಮತ್ತು ಕ್ವೆರಿ ಹಾಗೂ ಮೂಲ ಬಾಡಿಯನ್ನು ಓದಿ, ನಂತರ SDK ಸಹಾಯಕವನ್ನು ಕರೆಯುತ್ತದೆ.

FastAPI
import json
 
from fastapi import FastAPI, HTTPException, Request
from thunderphone import verify_signature
 
app = FastAPI()
 
 
def raw_path_and_query(request: Request) -> str:
    path = (request.scope.get("raw_path") or request.url.path.encode()).decode("latin-1")
    query = request.scope.get("query_string", b"").decode("latin-1")
    return f"{path}?{query}" if query else path
 
 
@app.post("/thunderphone-webhook")
async def hook(request: Request):
    body = await request.body()  # raw bytes, NOT request.json()
    if not verify_signature(
        request.headers.get("X-ThunderPhone-Signature-V2"),
        secret=SECRET,
        method=request.method,
        path=raw_path_and_query(request),
        body=body,
    ):
        raise HTTPException(status_code=401)
    event = json.loads(body)
    # … dispatch on event["type"] …
    return {"ok": True}
Express
import express from "express";
import { verifySignature } from "@thunderphone/sdk";
 
const app = express();
 
app.post(
  "/thunderphone-webhook",
  // IMPORTANT: parse as raw; do NOT use express.json() here.
  express.raw({ type: "application/json" }),
  (req, res) => {
    const ok = verifySignature({
      header: req.header("X-ThunderPhone-Signature-V2"),
      secret: process.env.WEBHOOK_SECRET,
      method: req.method,
      path: req.originalUrl, // path and query as received
      body: req.body,
    });
    if (!ok) return res.sendStatus(401);
    const event = JSON.parse(req.body.toString("utf8"));
    // … dispatch on event.type …
    res.sendStatus(204);
  },
);
Django
import json
 
from django.http import HttpResponseForbidden, JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_POST
from thunderphone import verify_signature
 
 
@csrf_exempt
@require_POST
def hook(request):
    if not verify_signature(
        request.headers.get("X-ThunderPhone-Signature-V2"),
        secret=SECRET,
        method=request.method,
        path=request.get_full_path(),
        body=request.body,  # raw bytes
    ):
        return HttpResponseForbidden("invalid signature")
    event = json.loads(request.body)
    # … dispatch on event["type"] …
    return JsonResponse({"ok": True})

req.originalUrl (Express) ಮತ್ತು ASGI raw_path ಹಾಗೂ query_string (FastAPI) ಸ್ವೀಕರಿಸಿದಂತೆಯೇ ಇರುವ ನಿಖರ ಗುರಿಯಾಗಿವೆ. Djangoಯ get_full_path() ಮತ್ತು Flaskನ request.path ಮೊದಲು ಪಥವನ್ನು ಡಿಕೋಡ್ ಮಾಡುತ್ತವೆ, ಇದರಿಂದ ಸಾಮಾನ್ಯ ಪಥಗಳಿಗೆ ಅದೇ ಸ್ಟ್ರಿಂಗ್ ದೊರೆಯುತ್ತದೆ. ನಿಮ್ಮ ಎಂಡ್‌ಪಾಯಿಂಟ್ ಪಥವು %2F, ; ಅಥವಾ = ನಂತಹ ಶೇಕಡಾವಾರು-ಎನ್‌ಕೋಡ್ ಮಾಡಿದ ಅಥವಾ ಮೀಸಲು ಅಕ್ಷರಗಳನ್ನು ಹೊಂದಿದ್ದರೆ, ಬದಲಿಗೆ ನಿಮ್ಮ ಸರ್ವರ್ ಒದಗಿಸುವ ಮೂಲ ಗುರಿಯನ್ನು ಓದಿ (ಉದಾಹರಣೆಗೆ Gunicornನಲ್ಲಿ request.META["RAW_URI"]).

ಯಾವ ರಹಸ್ಯ?

ಅದೇ ರಹಸ್ಯವು ಎರಡೂ ಹೆಡರ್‌ಗಳಿಗೆ ಸಹಿ ಮಾಡುತ್ತದೆ.

ಮೂಲರಹಸ್ಯ
ವೆಬಹುಕ್ ಎಂಡ್‌ಪಾಯಿಂಟ್ (/v1/developer/webhook-endpoints)ರಚಿಸುವಾಗ ಒಮ್ಮೆ ಹಿಂತಿರುಗಿಸಲಾದ ಪ್ರತಿಯೊಂದು ಎಂಡ್‌ಪಾಯಿಂಟ್‌ನ secret (48 ಹೆಕ್ಸ್ ಅಕ್ಷರಗಳು)
ಪಾರಂಪರಿಕ ಏಕ-URL ವೆಬಹುಕ್GET /v1/webhook ನಲ್ಲಿ ಹಿಂತಿರುಗಿಸಲಾದ ಪ್ರತಿಯೊಂದು ಸಂಸ್ಥೆಯ secret
ಟೂಲ್-ಎಂಡ್‌ಪಾಯಿಂಟ್ ಆಹ್ವಾನ (ನಿಮ್ಮ endpoint.url ಗೆ ನೇರ ಕರೆ)ಸಂಸ್ಥೆ-ಮಟ್ಟದ ವೆಬಹುಕ್ ರಹಸ್ಯ (ಪಾರಂಪರಿಕ ಏಕ-URL ವೆಬಹುಕ್‌ನದ್ದೇ) — ಎಂಡ್‌ಪಾಯಿಂಟ್-ಪ್ರತ್ಯೇಕ ರಹಸ್ಯವಲ್ಲ

ರಹಸ್ಯವನ್ನು ನಿಮ್ಮ ರಹಸ್ಯ ನಿರ್ವಾಹಕ ಅಥವಾ ಪರಿಸರ ಚರದಲ್ಲಿ ಸಂಗ್ರಹಿಸಿ — ಅದನ್ನು ಎಂದಿಗೂ ಕಮಿಟ್ ಮಾಡಬೇಡಿ.

ಟೂಲ್ ಕರೆಗಳನ್ನು ಪರಿಶೀಲಿಸುವುದು

ಏಜೆಂಟ್ ನಿಮ್ಮ ಫಂಕ್ಷನ್ ಟೂಲ್‌ಗಳಲ್ಲಿ ಒಂದನ್ನು ನೇರವಾಗಿ ಆಹ್ವಾನಿಸಿದಾಗ (ಟೂಲ್‌ಗೆ endpoint ಇರುವಾಗ), ವಿನಂತಿಯು ನಿಮ್ಮ ಕಾನ್ಫಿಗರ್ ಮಾಡಿದ endpoint.headers ಜೊತೆಗೆ ಈ ThunderPhone ಹೆಡರ್‌ಗಳನ್ನು ಹೊಂದಿರುತ್ತದೆ:

  • X-ThunderPhone-Call-ID — ಲೈವ್ ಕರೆಯ ಸಂಖ್ಯಾತ್ಮಕ ಐಡಿ.
  • X-ThunderPhone-Signature-V2 — ಮೇಲಿನ ಟೈಮ್‌ಸ್ಟ್ಯಾಂಪ್ ಹೊಂದಿರುವ ಸಹಿ, ನಿಮ್ಮ ಸಂಸ್ಥೆ-ಮಟ್ಟದ ವೆಬ್‌ಹುಕ್ ಸೀಕ್ರೆಟ್ ಬಳಸಿ ಕೀ ಮಾಡಲಾಗಿದೆ.
  • X-ThunderPhone-Signature — ಹಿಂದಿನ ಬಾಡಿ-ಮಾತ್ರದ ಸಹಿ, ಅದೇ ಕೀ.

ವೆಬ್‌ಹುಕ್‌ಗಳಿಗಿಂತ ಎರಡು ವಿಷಯಗಳು ಭಿನ್ನವಾಗಿವೆ:

  1. GET / DELETE ಟೂಲ್‌ಗಳಿಗೆ ಬಾಡಿ ಇರುವುದಿಲ್ಲ. ಆರ್ಗ್ಯುಮೆಂಟ್‌ಗಳು ಕ್ವೆರಿ ಪ್ಯಾರಾಮೀಟರ್‌ಗಳಾಗಿ ಸಾಗುತ್ತವೆ. V2 ಸಹಿಯು ಪಾತ್ ಮತ್ತು ಕ್ವೆರಿಯ ಮೂಲಕ ಅವುಗಳನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ ಮತ್ತು ಬಾಡಿ ಫೀಲ್ಡ್ ಖಾಲಿಯಾಗಿರುತ್ತದೆ. ರಾ ಕ್ವೆರಿ ಸ್ಟ್ರಿಂಗ್ ಬಳಸಿ ಪರಿಶೀಲಿಸಿ: ಪ್ಯಾರಾಮೀಟರ್‌ಗಳನ್ನು ಪಾರ್ಸ್ ಮಾಡಿ ಹೊಸ ಕ್ವೆರಿ ಸ್ಟ್ರಿಂಗ್ ನಿರ್ಮಿಸುವುದು ಅವುಗಳ ಕ್ರಮ ಅಥವಾ ಎನ್‌ಕೋಡಿಂಗ್ ಅನ್ನು ಬದಲಾಯಿಸಬಹುದು. ಹಿಂದಿನ ಹೆಡರ್ ಖಾಲಿ ಬೈಟ್ ಸ್ಟ್ರಿಂಗ್‌ಗೆ ಸಹಿ ಮಾಡುತ್ತದೆ.
  2. ಹಿಂದಿನ ವೆಬ್‌ಹುಕ್ ಕಾನ್ಫಿಗರ್ ಮಾಡದ ಸಂಸ್ಥೆಗಳಿಗೆ ಸಂಸ್ಥೆಯ ಸೀಕ್ರೆಟ್ ಇರುವುದಿಲ್ಲ. ಆ ಸಂದರ್ಭದಲ್ಲಿ ಟೂಲ್ ಕರೆಗಳು X-ThunderPhone-Call-ID ಅನ್ನು ಮಾತ್ರ ಹೊಂದಿರುತ್ತವೆ ಮತ್ತು ಯಾವುದೇ ಸಹಿ ಹೆಡರ್‌ಗಳಿರುವುದಿಲ್ಲ. ಸೈನಿಂಗ್ ಸೀಕ್ರೆಟ್ ಪಡೆಯಲು ಹಿಂದಿನ ವೆಬ್‌ಹುಕ್ ಅನ್ನು (PUT /v1/webhook) ಕಾನ್ಫಿಗರ್ ಮಾಡಿ, ಅಥವಾ endpoint.headers ಮೂಲಕ ನಿಮ್ಮ ಸ್ವಂತ ಹೆಡರ್ ಬಳಸಿ ಟೂಲ್ ಕರೆಗಳನ್ನು ದೃಢೀಕರಿಸಿ.
@app.api_route("/tools/search-appointments", methods=["GET", "POST"])
async def tool(request: Request):
    body = await request.body()  # b"" for GET/DELETE tools
    if not verify_signature(
        request.headers.get("X-ThunderPhone-Signature-V2"),
        secret=ORG_WEBHOOK_SECRET,
        method=request.method,
        path=raw_path_and_query(request),
        body=body,
    ):
        raise HTTPException(status_code=401)
    call_id = request.headers.get("X-ThunderPhone-Call-ID", "")
    args = json.loads(body) if body else dict(request.query_params)
    ...

Express ನಲ್ಲಿ, ಬಾಡಿ ಪಾರ್ಸರ್ GET ನಲ್ಲಿ req.body ಅನ್ನು ಖಾಲಿ ಆಬ್ಜೆಕ್ಟ್ ಆಗಿ ಬಿಡುತ್ತದೆ, ಆದ್ದರಿಂದ Buffer.isBuffer(req.body) ? req.body : Buffer.alloc(0) ಅನ್ನು ಪಾಸ್ ಮಾಡಿ.

ವೆಬ್‌ಹುಕ್-ಮೋಡ್ ಟೂಲ್ ಡಿಸ್ಪ್ಯಾಚ್‌ಗೆ (endpoint ಇಲ್ಲದ, ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ವೆಬ್‌ಹುಕ್‌ಗೆ telephony.tool / web.tool ಆಗಿ ತಲುಪಿಸುವ ಟೂಲ್‌ಗಳು) ಸಾಮಾನ್ಯ ಸಹಿ ಮಾಡಿದ ವೆಬ್‌ಹುಕ್ ಅನ್ವಯಿಸುತ್ತದೆ — ಮೇಲಿನ ಪ್ರಮಾಣಿತ ವಿಧಾನವನ್ನು ಬಳಸಿ. ಎರಡೂ ವಿನಂತಿ ಸ್ವರೂಪಗಳಿಗಾಗಿ ಫಂಕ್ಷನ್ ಟೂಲ್‌ಗಳನ್ನು ನೋಡಿ.

ಲೆಗಸಿ ಸಹಿ: X-ThunderPhone-Signature

ಮೂಲ ಹೆಡರ್ ಒಂದೇ ರಹಸ್ಯದೊಂದಿಗೆ ಕಚ್ಚಾ ಬಾಡಿಯ ಹೆಕ್ಸ್ HMAC-SHA256 ಆಗಿದೆ. ಇದರಲ್ಲಿ ಟೈಮ್‌ಸ್ಟ್ಯಾಂಪ್ ಇರುವುದಿಲ್ಲ, ಆದ್ದರಿಂದ ಸಹಿ ಮಾಡಿದ ಒಂದು ವಿನಂತಿಯನ್ನು ಸೆರೆಹಿಡಿದ ಯಾರಾದರೂ ಅದನ್ನು ಮರುಚಲಾಯಿಸಬಹುದು. ಇಂಟಿಗ್ರೇಷನ್‌ಗಳು V2 ಗೆ ಸ್ಥಳಾಂತರಗೊಳ್ಳುವ ಅವಧಿಯಲ್ಲಿ ಇದನ್ನು ಇನ್ನೂ ಪ್ರತಿಯೊಂದು ವಿನಂತಿಯಲ್ಲೂ ಕಳುಹಿಸಲಾಗುತ್ತದೆ.

  1. ಕಚ್ಚಾ ವಿನಂತಿ ಬಾಡಿಯನ್ನು ಓದಿ — ನಾವು ನಿಮಗೆ ಕಳುಹಿಸಿದ ನಿಖರ ಬೈಟ್‌ಗಳು.
  2. hmac_sha256(secret, body).hexdigest() ಅನ್ನು ಲೆಕ್ಕಹಾಕಿ.
  3. X-ThunderPhone-Signature ಜೊತೆಗೆ ಸ್ಥಿರ ಸಮಯದಲ್ಲಿ ಹೋಲಿಸಿ.

ನಾವು ರವಾನಿಸುವ ನಿಖರ ಬೈಟ್‌ಗಳಿಗೆ ಸಹಿ ಮಾಡುತ್ತೇವೆ. ಆ ಬೈಟ್‌ಗಳು ಪೇಲೋಡ್‌ನ ಕ್ಯಾನಾನಿಕಲ್ JSON ಸೀರಿಯಲೈಸೇಶನ್ ಸಹ ಆಗಿವೆ — ಕೀಗಳನ್ನು ಅಕ್ಷರಾನುಕ್ರಮದಲ್ಲಿ ವಿಂಗಡಿಸಲಾಗಿರುತ್ತದೆ, ಸಂಕ್ಷಿಪ್ತ ವಿಭಜಕಗಳು (ಖಾಲಿ ಸ್ಥಳಗಳಿಲ್ಲದ , ಮತ್ತು :), UTF-8. ನಿಮ್ಮ ಫ್ರೇಮ್‌ವರ್ಕ್ ಪಾರ್ಸ್ ಮಾಡಿದ JSON ಅನ್ನು ಮಾತ್ರ ಒದಗಿಸಿದರೆ, ಅದನ್ನು ಕ್ಯಾನಾನಿಕಲ್ ಆಗಿ ಮರು-ಸೀರಿಯಲೈಸ್ ಮಾಡಿ ಮತ್ತು ಅದಕ್ಕೆ HMAC ಅನ್ವಯಿಸಿ:

# Equivalent to hashing the raw body:
import json
canonical = json.dumps(payload, separators=(",", ":"), sort_keys=True).encode("utf-8")

ಕಚ್ಚಾ ಬಾಡಿಗೆ ಆದ್ಯತೆ ನೀಡಿ — ಇದು ಒಂದು ಹಂತ ಕಡಿಮೆ ಮತ್ತು ಕೆಲವು ಭಾಷೆಗಳಲ್ಲಿನ JSON ಸಂಖ್ಯೆಯ ಮರು-ಪರಿವರ್ತನೆ ವೈಶಿಷ್ಟ್ಯಗಳಿಂದ ಪ್ರಭಾವಿತವಾಗುವುದಿಲ್ಲ. V2 ನ ಬಾಡಿ ಕ್ಷೇತ್ರಕ್ಕೂ ಇದೇ ಅನ್ವಯಿಸುತ್ತದೆ.

Python
import hashlib
import hmac
 
 
def verify(body: bytes, signature: str, secret: str) -> bool:
    """Constant-time HMAC-SHA256 verification."""
    expected = hmac.new(
        secret.encode("utf-8"),
        body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, signature or "")
Node.js
import crypto from "node:crypto";
 
export function verify(body, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  if (!signature || expected.length !== signature.length) return false;
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature),
  );
}
Go
package webhook
 
import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
)
 
func Verify(body []byte, signature, secret string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(body)
    expected := hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(signature))
}
Ruby
require "openssl"
 
def verify(body, signature, secret)
  expected = OpenSSL::HMAC.hexdigest("SHA256", secret, body)
  Rack::Utils.secure_compare(expected, signature.to_s)
end

ಸಾಮಾನ್ಯ ತಪ್ಪುಗಳು

ಗಡಿಯಾರ ವ್ಯತ್ಯಾಸ

5-ನಿಮಿಷಗಳ ಅವಧಿಯನ್ನು ನಿಮ್ಮ ಸರ್ವರ್‌ನ ಗಡಿಯಾರದ ಆಧಾರದ ಮೇಲೆ ಅಳೆಯಲಾಗುತ್ತದೆ. ಅದನ್ನು NTP ಯೊಂದಿಗೆ ಸಿಂಕ್ರೊನೈಸ್ ಆಗಿರಿಸಿ; 5 ನಿಮಿಷಗಳಿಗಿಂತ ಹೆಚ್ಚು ವ್ಯತ್ಯಾಸವಿರುವ ಗಡಿಯಾರವು ಪ್ರತಿಯೊಂದು ವಿನಂತಿಯನ್ನೂ ತಿರಸ್ಕರಿಸುತ್ತದೆ.

ಪ್ರಾಕ್ಸಿಯು ಮಾರ್ಗವನ್ನು ಮರುಬರೆಯುತ್ತದೆ

ಸಹಿ ಮಾಡಲಾದ ಮಾರ್ಗವು ನಾವು ವಿನಂತಿಸಿದದ್ದೇ ಆಗಿದೆ: ನೀವು ThunderPhone ನಲ್ಲಿ ಕಾನ್ಫಿಗರ್ ಮಾಡಿದ URL ನ ಮಾರ್ಗ. ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್ ವಿನಂತಿಯನ್ನು ನೋಡುವ ಮೊದಲು ರಿವರ್ಸ್ ಪ್ರಾಕ್ಸಿ ಅಥವಾ API ಗೇಟ್‌ವೇ ಪೂರ್ವಪ್ರತ್ಯಯವನ್ನು ತೆಗೆದುಹಾಕಿದರೆ ಅಥವಾ ಸೇರಿಸಿದರೆ, ಪರಿಶೀಲಿಸುವ ಮೊದಲು ನಾವು ಕಳುಹಿಸಿದ ಮಾರ್ಗವನ್ನು ಮರುನಿರ್ಮಿಸಿ (ಉದಾಹರಣೆಗೆ, ಪೂರ್ವಪ್ರತ್ಯಯವನ್ನು ಮರಳಿ ಸೇರಿಸಿ).

ಡೀಫಾಲ್ಟ್ ಫಾರ್ಮ್ಯಾಟಿಂಗ್‌ನೊಂದಿಗೆ ಮರು-ಸೀರಿಯಲೈಸ್ ಮಾಡುವುದು

ಬಾಡಿಯನ್ನು ಪಾರ್ಸ್ ಮಾಡಿ ನಿಮ್ಮ JSON ಲೈಬ್ರರಿಯ ಡೀಫಾಲ್ಟ್‌ಗಳೊಂದಿಗೆ (, / : ನಂತರದ ಖಾಲಿ ಜಾಗಗಳು, ಸೇರಿಸಿದ ಕ್ರಮದಲ್ಲಿರುವ ಕೀಲಿಗಳು) ಮರು-ಡಂಪ್ ಮಾಡುವುದರಿಂದ ವಿಭಿನ್ನ ಬೈಟ್‌ಗಳು ಉತ್ಪತ್ತಿಯಾಗಿ HMAC ಮುರಿಯುತ್ತದೆ. ಕಚ್ಚಾ ಬಾಡಿಯನ್ನು ಪರಿಶೀಲಿಸಿ — ಅಥವಾ ನೀವು ಮರು-ಸೀರಿಯಲೈಸ್ ಮಾಡಲೇಬೇಕಾದರೆ, ನಮ್ಮ ಪ್ರಮಾಣಿತ ರೂಪಕ್ಕೆ ನಿಖರವಾಗಿ ಹೊಂದಿಸಿ: ವಿಂಗಡಿಸಿದ ಕೀಲಿಗಳು, ಸಂಕ್ಷಿಪ್ತ ವಿಭಜಕಗಳು, UTF-8.

ಫ್ರೇಮ್‌ವರ್ಕ್ JSON ಅನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಪಾರ್ಸ್ ಮಾಡುತ್ತದೆ

Express ನ express.json() ಮಿಡಲ್‌ವೇರ್ ಬಾಡಿ ಸ್ಟ್ರೀಮ್ ಅನ್ನು ಬಳಸಿಕೊಳ್ಳುತ್ತದೆ ಮತ್ತು ನೀವು ಮೂಲ ಬೈಟ್‌ಗಳನ್ನು ಕಳೆದುಕೊಳ್ಳುತ್ತೀರಿ. ವೆಬ್‌ಹುಕ್ ರೂಟ್‌ನಲ್ಲಿ ನಿರ್ದಿಷ್ಟವಾಗಿ express.raw() ಬಳಸಿ, ಅಥವಾ ಪೂರ್ವ-ಮಿಡಲ್‌ವೇರ್‌ನಲ್ಲಿ ಮೂಲ ಬಾಡಿಯನ್ನು ಬಫರ್ ಮಾಡಿ. NestJS / Koaಗೂ ಇದೇ ಅನ್ವಯಿಸುತ್ತದೆ — ಅವುಗಳ "ಮೂಲ ಬಾಡಿ" ದಾಖಲೆಗಳನ್ನು ಪರಿಶೀಲಿಸಿ.

ಸಮಯ-ಸುರಕ್ಷಿತವಲ್ಲದ ಹೋಲಿಕೆ

JS ನಲ್ಲಿ expected === signature ಅಥವಾ Python ನಲ್ಲಿ expected == signature ಸಮಯಕ್ಕೆ ಅನುಗುಣವಾಗಿ ಬದಲಾಗುವ ಹೋಲಿಕೆಗಳಾಗಿವೆ. ಕ್ರಮವಾಗಿ crypto.timingSafeEqual ಅಥವಾ hmac.compare_digest ಬಳಸಿ. ಕಾರ್ಯಕ್ಷಮತೆಯ ವ್ಯತ್ಯಾಸ ಶೂನ್ಯವಾಗಿದೆ.

ಸಾಧನ ಎಂಡ್‌ಪಾಯಿಂಟ್‌ಗಳಿಗೆ ತಪ್ಪಾದ ರಹಸ್ಯ

ನೇರ ಸಾಧನ-ಎಂಡ್‌ಪಾಯಿಂಟ್ ಕರೆಗಳಿಗೆ ಸಂಸ್ಥೆ-ಮಟ್ಟದ ವೆಬ್‌ಹುಕ್ ರಹಸ್ಯ (GET /v1/webhook) ಬಳಸಿ ಸಹಿ ಮಾಡಲಾಗುತ್ತದೆ — /v1/developer/webhook-endpoints ನಲ್ಲಿರುವ ಯಾವುದೇ ಪ್ರತಿ-ಎಂಡ್‌ಪಾಯಿಂಟ್ ರಹಸ್ಯದಿಂದಲ್ಲ. ಅದೇ ಸಹಾಯಕವನ್ನು ಮರುಬಳಸಿ, ಆದರೆ ಸಾಧನ ಮಾರ್ಗಗಳಲ್ಲಿ ಅದಕ್ಕೆ ಸಂಸ್ಥೆಯ ರಹಸ್ಯವನ್ನೇ ನೀಡುತ್ತಿರುವುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ.

GET/DELETE ಸಾಧನಗಳಲ್ಲಿನ ಕ್ವೆರಿ ಸ್ಟ್ರಿಂಗ್‌ಗಳು

V2 ಕಳುಹಿಸಿದಂತೆಯೇ ಕ್ವೆರಿ ಸ್ಟ್ರಿಂಗ್‌ಗೆ ಸಹಿ ಮಾಡುತ್ತದೆ. ಲೆಗಸಿ ಹೆಡರ್ ಖಾಲಿ ಬಾಡಿಗೆ ಸಹಿ ಮಾಡುತ್ತದೆ ಮತ್ತು ಎಂದಿಗೂ ಕ್ವೆರಿ ಸ್ಟ್ರಿಂಗ್‌ಗೆ ಅಲ್ಲ, ಆದ್ದರಿಂದ ಲೆಗಸಿ ಹೆಡರ್‌ಗಾಗಿ URL ಅನ್ನು ಹ್ಯಾಶ್ ಮಾಡಿದರೆ ಅದು ಎಂದಿಗೂ ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ.

ಅವಧಿಯೊಳಗಿನ ನಕಲುಗಳು

ಟೈಮ್‌ಸ್ಟ್ಯಾಂಪ್ 5 ನಿಮಿಷಗಳಿಗಿಂತ ಹಳೆಯ ರಿಪ್ಲೇಗಳನ್ನು ತಡೆಯುತ್ತದೆ, ಆ ಅವಧಿಯೊಳಗಿನ ಎರಡನೇ ಪ್ರತಿಯನ್ನು ಅಲ್ಲ. ಎಂಡ್‌ಪಾಯಿಂಟ್ ವಿತರಣೆಗಳು ಕನಿಷ್ಠ-ಒಮ್ಮೆ ಆಗಿರುವುದರಿಂದ, ಅದೇ ಈವೆಂಟ್‌ನ ಮರುಪ್ರಯತ್ನವೂ ಬರಬಹುದು; ಎನ್ವಲಪ್‌ನ event_id ಆಧರಿಸಿ ನಕಲುಗಳನ್ನು ತೆಗೆದುಹಾಕಿ.

ಹೊಂದಿಕೆಯಾಗದಾಗ 401 ಹಿಂತಿರುಗಿಸದಿರುವುದು

ಪರಿಶೀಲನೆ ವಿಫಲವಾದಾಗ 200 ಹಿಂತಿರುಗಿಸುವುದು ಹ್ಯಾಂಡ್ಲರ್ ಅನ್ನು ಮರುಕಳುಹಿಸುವ ದಾಳಿಯ ಗುರಿಯನ್ನಾಗಿಸುತ್ತದೆ. ಪರಿಶೀಲನೆ ವಿಫಲವಾದರೆ ಯಾವಾಗಲೂ 2xx ಅಲ್ಲದ ಪ್ರತಿಕ್ರಿಯೆ ನೀಡಿ.


ಮುಂದಿನ ಹಂತಗಳು