verifyInventoryWebhookSignature function

bool verifyInventoryWebhookSignature(
  1. Object? secret,
  2. String? header,
  3. Object? rawBody, {
  4. int toleranceSec = webhookToleranceSec,
  5. DateTime? now,
})

Prueft die Signatur einer Zustellung. true nur, wenn Kopf, Zeitfenster und HMAC stimmen; jede schlechte Eingabe und jede Ausnahme ist false, nie ein Wurf.

  • secret: das Secret aus createWebhook/rotateWebhookSecret als String, oder eine Liste davon fuer den eigenen Wechsel (es reicht, wenn eines passt).
  • header: der Wert von X-Kasseneck-Signature, unveraendert. Mehrere v1=-Anteile sind erlaubt.
  • rawBody: der rohe Rumpf als String oder als Bytes (List<int>, etwa Uint8List).
  • now: jetzt; Vorgabe ist die Systemuhr.

Implementation

bool verifyInventoryWebhookSignature(
  Object? secret,
  String? header,
  Object? rawBody, {
  int toleranceSec = webhookToleranceSec,
  DateTime? now,
}) {
  try {
    final secrets = <String>[
      if (secret is String) secret else if (secret is Iterable) ...secret.whereType<String>(),
    ].where((s) => s.isNotEmpty).toList();
    if (secrets.isEmpty || header == null || header.trim().isEmpty) return false;
    final kopf = _kopfLesen(header);
    if (kopf == null) return false;
    final List<int> rumpf;
    if (rawBody is String) {
      rumpf = utf8.encode(rawBody);
    } else if (rawBody is List<int>) {
      rumpf = rawBody;
    } else {
      return false;
    }
    // Abgerundet wie Math.floor(ms / 1000) im JS-Zwilling.
    final jetzt = ((now ?? DateTime.now()).millisecondsSinceEpoch / 1000).floor();
    // In BEIDE Richtungen: eine vorgehende Uhr auf der Gegenseite darf ein
    // altes Ereignis nicht wieder gueltig machen.
    if ((jetzt - kopf.t).abs() > toleranceSec) return false;
    final nachricht = [...utf8.encode('${kopf.t}.'), ...rumpf];
    for (final s in secrets) {
      final soll = Hmac(sha256, utf8.encode(s)).convert(nachricht).bytes;
      for (final v1 in kopf.v1) {
        final ist = _hexZuBytes(v1);
        if (ist != null && _gleichZeitkonstant(ist, soll)) return true;
      }
    }
    return false;
  } on Object {
    // Punkt 4 oben: eine Ausnahme ist eine Ablehnung, nie ein Ja (auch ein
    // Byte ausserhalb 0–255 in rawBody).
    return false;
  }
}