diff --git a/systems/x86_64-linux/mx/nextcloud-claude-bot/bot.py b/systems/x86_64-linux/mx/nextcloud-claude-bot/bot.py index 54d9622..5d051a4 100644 --- a/systems/x86_64-linux/mx/nextcloud-claude-bot/bot.py +++ b/systems/x86_64-linux/mx/nextcloud-claude-bot/bot.py @@ -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= 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")