Files
notify-bridge/packages/server/src/notify_bridge_server/commands/parser.py
T
alexei.dolgolyov e0bae394ee feat: comprehensive code review fixes — security, performance, quality
Backend security:
- Reject Gitea webhooks when webhook_secret is empty (was silently skipping)
- Add slowapi rate limiting on login (5/min) and setup (3/min) endpoints
- Add CORS middleware with configurable origins
- Mask telegram_webhook_secret in settings API response
- Protect system-owned command template configs from regular user modification
- Increase minimum password length to 8 characters

Backend performance:
- Batch queries in _resolve_command_context (3 queries instead of 3N)
- Concurrent album fetching with asyncio.gather in immich commands
- Singleton Jinja2 SandboxedEnvironment (reuse instead of per-render creation)
- TTLCache for rate limits (bounded memory, auto-eviction)
- Optional aiohttp session reuse in send_reply/send_media_group

Backend code quality:
- Extract dispatch_helpers.py (shared link_data loading + event filtering)
- Extract database/seeds.py from main.py (490 lines → dedicated module)
- Split immich_handler.py (415 lines) into commands/immich/ subpackage
- Replace bare except blocks with logged warnings
- Add per-provider config validation (Pydantic models)
- Truncate command input to 512 chars
- Expose usage_* and desc_* slots in capabilities and variables API

Frontend security:
- CSS.escape() for user-controlled querySelector in highlight.ts
- Client-side password min 8 chars validation on setup and password change

Frontend code quality:
- Replace any types with proper interfaces across top files
- Decompose targets/+page.svelte into TargetForm + ReceiverSection
- Fix $derived.by usage, $state mutation patterns
- Add console.warn to empty catch blocks

Frontend UX:
- Auth redirect via goto() with "Redirecting..." state
- Platform-aware Ctrl/Cmd K keyboard hint
- Remove stat-card hover transform

Frontend accessibility:
- Modal: role=dialog, aria-modal, focus trap, restore focus
- EntitySelect/IconGridSelect: listbox/option roles, aria-selected/disabled
2026-03-23 01:59:51 +03:00

41 lines
1.2 KiB
Python

"""Command text parsing — extracts command name, arguments, and optional count."""
from __future__ import annotations
def parse_command(text: str) -> tuple[str, str, int | None]:
"""Parse a command message into (command, args, count).
Examples:
"/search sunset" -> ("search", "sunset", None)
"/latest Family 5" -> ("latest", "Family", 5)
"/events 10" -> ("events", "", 10)
"/help@mybot" -> ("help", "", None)
"""
text = text[:512].strip()
if not text.startswith("/"):
return ("", text, None)
# Strip @botname suffix: /command@botname args
parts = text[1:].split(None, 1)
cmd = parts[0].split("@")[0].lower()
rest = parts[1] if len(parts) > 1 else ""
# Try to extract trailing count
count = None
rest_parts = rest.rsplit(None, 1)
if len(rest_parts) == 2:
try:
count = int(rest_parts[1])
rest = rest_parts[0]
except ValueError:
pass
elif rest_parts and rest_parts[0]:
try:
count = int(rest_parts[0])
rest = ""
except ValueError:
pass
return (cmd, rest.strip(), count)