verifySignatureBytes method

void verifySignatureBytes({
  1. required List<int> body,
  2. required Map<String, String> headers,
})

Like verifySignature, for a body given as the raw bytes of the request.

Implementation

void verifySignatureBytes({
  required List<int> body,
  required Map<String, String> headers,
}) {
  final id = _header(headers, idHeader);
  final timestampText = _header(headers, timestampHeader);
  final signatures = _header(headers, signatureHeader);

  if (!_timestampPattern.hasMatch(timestampText)) {
    throw const InvalidSignatureException(
      'The "webhook-timestamp" header is not a Unix timestamp in seconds.',
    );
  }
  final timestamp = DateTime.fromMillisecondsSinceEpoch(
    int.parse(timestampText) * 1000,
    isUtc: true,
  );
  final now = _clock();
  if (now.difference(timestamp).abs() > tolerance) {
    throw TimestampOutOfToleranceException(
      timestamp: timestamp,
      now: now,
      tolerance: tolerance,
    );
  }

  final expected = _compute(_hmac, id, timestampText, body);
  var matched = false;
  // The header holds space-separated `version,signature` pairs. Some
  // frameworks join repeated headers with commas, so split on both and
  // read the tokens in pairs: base64 never contains a comma.
  final tokens = signatures.split(_separators);
  for (var i = 0; i + 1 < tokens.length; i++) {
    if (tokens[i] != 'v1') continue;
    // Check every candidate so the time taken does not reveal which one
    // matched.
    if (_constantTimeEquals(tokens[++i], expected)) matched = true;
  }
  if (!matched) throw const InvalidSignatureException();
}