feat(bot): support random token in signature verification
- Enhanced signature verification by adding support for a `random` token included in webhook headers. - Introduced logging to display signature variants for debugging purposes. - Improved webhook handling to process new `X-Nextcloud-Talk-Random` header.
This commit is contained in:
parent
33937ab115
commit
77cf4a0aed
1 changed files with 27 additions and 11 deletions
|
|
@ -56,25 +56,37 @@ conversations: dict[str, list[tuple[datetime, str, str]]] = {}
|
|||
MAX_HISTORY = 10 # Keep last N exchanges per user
|
||||
|
||||
|
||||
def verify_signature(body: bytes, signature: str) -> bool:
|
||||
def verify_signature(body: bytes, signature: str, random: Optional[str] = None) -> bool:
|
||||
"""Verify Nextcloud webhook signature."""
|
||||
if not BOT_SECRET:
|
||||
log.warning("No bot secret configured, skipping signature verification")
|
||||
return True
|
||||
|
||||
expected = hmac.new(
|
||||
BOT_SECRET.encode(),
|
||||
body,
|
||||
hashlib.sha256
|
||||
).hexdigest()
|
||||
|
||||
# Nextcloud sends: sha256=<hex>
|
||||
if signature.startswith("sha256="):
|
||||
signature = signature[7:]
|
||||
|
||||
log.info(f"Signature verification: secret_len={len(BOT_SECRET)}, expected={expected[:16]}..., received={signature[:16]}...")
|
||||
# Try different signature computation methods
|
||||
# Method 1: Just body
|
||||
expected1 = hmac.new(BOT_SECRET.encode(), body, hashlib.sha256).hexdigest()
|
||||
|
||||
return hmac.compare_digest(expected, signature)
|
||||
# Method 2: random + body (if random header present)
|
||||
if random:
|
||||
expected2 = hmac.new(BOT_SECRET.encode(), (random.encode() + body), hashlib.sha256).hexdigest()
|
||||
else:
|
||||
expected2 = None
|
||||
|
||||
log.info(f"Signature verification: received={signature[:16]}...")
|
||||
log.info(f" Method 1 (body only): {expected1[:16]}...")
|
||||
if expected2:
|
||||
log.info(f" Method 2 (random+body): {expected2[:16]}...")
|
||||
|
||||
if hmac.compare_digest(expected1, signature):
|
||||
return True
|
||||
if expected2 and hmac.compare_digest(expected2, signature):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def build_prompt(user_id: str, message: str) -> str:
|
||||
|
|
@ -182,12 +194,16 @@ async def send_reply(conversation_token: str, message: str, reply_to: int = None
|
|||
async def handle_webhook(
|
||||
request: Request,
|
||||
x_nextcloud_talk_signature: Optional[str] = Header(None, alias="X-Nextcloud-Talk-Signature"),
|
||||
x_nextcloud_talk_random: Optional[str] = Header(None, alias="X-Nextcloud-Talk-Random"),
|
||||
):
|
||||
"""Handle incoming webhook from Nextcloud Talk."""
|
||||
body = await request.body()
|
||||
|
||||
log.info(f"Headers: signature={x_nextcloud_talk_signature}, random={x_nextcloud_talk_random}")
|
||||
log.info(f"Body (first 200): {body[:200]}")
|
||||
|
||||
# Verify signature
|
||||
if x_nextcloud_talk_signature and not verify_signature(body, x_nextcloud_talk_signature):
|
||||
if x_nextcloud_talk_signature and not verify_signature(body, x_nextcloud_talk_signature, x_nextcloud_talk_random):
|
||||
log.warning("Invalid webhook signature")
|
||||
raise HTTPException(status_code=401, detail="Invalid signature")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue