Skip to content

fix(webhook): case-insensitive X-Lark-* signature header lookup - #13

Open
wz-heng wants to merge 2 commits into
larksuite:mainfrom
wz-heng:fix/webhook-header-case-insensitive
Open

fix(webhook): case-insensitive X-Lark-* signature header lookup#13
wz-heng wants to merge 2 commits into
larksuite:mainfrom
wz-heng:fix/webhook-header-case-insensitive

Conversation

@wz-heng

@wz-heng wz-heng commented Aug 14, 2026

Copy link
Copy Markdown

Fixes part 1 of #12.

Bug

EventDispatcherHandler._verify_sign / _has_signature_headers (and the
identical duplicated logic in CardActionHandler) look up
X-Lark-Request-Timestamp, X-Lark-Request-Nonce, and X-Lark-Signature
case-sensitively via a plain dict.get(...).

ASGI servers (Starlette/FastAPI) hand the application lowercase header
names, per the ASGI spec. Behind such a server, the case-sensitive lookup
returns None for all three headers, and _verify_sign immediately
raises TypeError: unsupported operand type(s) for +: 'NoneType' and 'NoneType' when it tries timestamp + nonce + encrypt_key — every
legitimately signed request 500s.

Fix

Add a small case-insensitive header lookup (_get_header), used by both
EventDispatcherHandler and CardActionHandler (the card callback path
has the exact same duplicated verification code and the exact same bug).
Falls back to a case-insensitive scan only when the exact-case key isn't
found, so behavior for exact-case callers (e.g. plain WSGI) is unchanged.

Testing

Added regression tests exercising both handlers with lowercased headers
(matching what Starlette/FastAPI would hand the SDK) for both plaintext
and encrypted+signed payloads — they 500'd before this change, they pass
now. Full suite: python -m pytest -q → 1101 passed.

🤖 Generated with Claude Code

_verify_sign and _has_signature_headers in EventDispatcherHandler and
CardActionHandler looked up X-Lark-Request-Timestamp,
X-Lark-Request-Nonce, and X-Lark-Signature case-sensitively. ASGI
servers (Starlette/FastAPI) hand handlers lowercase header names per
the ASGI spec, so every legitimately signed request behind such a
server hit `None + None + encrypt_key` and 500'd with a confusing
TypeError instead of verifying.

Add a small case-insensitive header lookup used by both handlers.

Fixes larksuite#12 (bug 1 of 2).
The lowercase-ASGI-header regression coverage added for this fix
exercised the event plaintext, event encrypted, and card encrypted
paths, but missed CardActionHandler's plaintext-signed path even
though _verify_sign there uses the same fixed lookup.

Addresses review feedback from this run's required Snape pass.
@CLAassistant

CLAassistant commented Aug 14, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants