Files
rengine/shared/definitions/channels.py
T
Yogesh Ojha 52d535d33b feat(remote-control): connect and disconnect the bot on the page, rebuilt layout
- no bot connected: one panel, BotFather link and a token field; Connect
  checks the token with Telegram, stores the API key and starts the listener
- Settings sheet holds the bot, Change bot, Disconnect, the ceiling and the
  rate limit; Disconnect removes the paired chats, pending requests and key
- a token for a different bot drops every pairing; deleting or replacing the
  Telegram key under API keys follows the same rules
- page: bot header, pairing requests with the code and an up-to capability
  picker, then Chats, Activity and Commands tabs
- activity records the command as typed, control characters stripped
2026-09-25 08:07:15 +05:30

145 lines
3.5 KiB
Python

"""Remote control vocabulary: channels, chat states, command sources and the pairing gate."""
from __future__ import annotations
from enum import StrEnum
from pydantic import BaseModel, Field
from shared.enums.api_key import APIProvider
from shared.enums.notification_channel import NotificationProvider
class ChannelKind(StrEnum):
TELEGRAM = "telegram"
CHANNEL_ORDER: tuple[str, ...] = tuple(c.value for c in ChannelKind)
CHANNEL_LABELS: dict[str, str] = {
ChannelKind.TELEGRAM.value: "Telegram",
}
# API key provider per channel
CHANNEL_PROVIDERS: dict[str, APIProvider] = {
ChannelKind.TELEGRAM.value: APIProvider.TELEGRAM,
}
PROVIDER_CHANNELS: dict[APIProvider, str] = {v: k for k, v in CHANNEL_PROVIDERS.items()}
# notification provider that sends with the channel's key when it has no token of its own
CHANNEL_NOTIFICATIONS: dict[str, str] = {
ChannelKind.TELEGRAM.value: NotificationProvider.TELEGRAM.value,
}
class ChatState(StrEnum):
ACTIVE = "active"
REVOKED = "revoked"
BLOCKED = "blocked"
CHAT_STATE_LABELS: dict[str, str] = {
ChatState.ACTIVE.value: "Active",
ChatState.REVOKED.value: "Revoked",
ChatState.BLOCKED.value: "Blocked",
}
class CommandSource(StrEnum):
MCP = "mcp"
TOOLBOX = "toolbox"
BUILTIN = "builtin"
COMMAND_SOURCE_ORDER: tuple[str, ...] = (
CommandSource.BUILTIN.value,
CommandSource.MCP.value,
CommandSource.TOOLBOX.value,
)
COMMAND_SOURCE_LABELS: dict[str, str] = {
CommandSource.BUILTIN.value: "Chat",
CommandSource.MCP.value: "Tools",
CommandSource.TOOLBOX.value: "Lookups",
}
class CommandPreset(BaseModel):
"""A command name bound to a tool with arguments already set."""
name: str
tool: str
title: str
description: str
args: dict[str, object] = Field(default_factory=dict)
takes_args: bool = True
COMMAND_PRESETS: tuple[CommandPreset, ...] = (
CommandPreset(
name="vulns",
tool="query_assets",
title="Findings",
description="Findings on a target or across the selected project.",
args={"dimension": "vulnerabilities"},
),
CommandPreset(
name="scans",
tool="scan_status",
title="Running scans",
description="Scans running now.",
takes_args=False,
),
)
class ChatGroup(StrEnum):
TARGETS = "targets"
SCANS = "scans"
RESULTS = "results"
LOOKUPS = "lookups"
CHAT = "chat"
CHAT_GROUP_ORDER: tuple[str, ...] = tuple(g.value for g in ChatGroup)
CHAT_GROUP_LABELS: dict[str, str] = {
ChatGroup.TARGETS.value: "Targets",
ChatGroup.SCANS.value: "Scans",
ChatGroup.RESULTS.value: "Results",
ChatGroup.LOOKUPS.value: "Lookups",
ChatGroup.CHAT.value: "Chat",
}
# chat group per command, toolbox lookups fall in LOOKUPS
COMMAND_GROUPS: dict[str, tuple[str, ...]] = {
ChatGroup.TARGETS.value: ("targets", "target", "add"),
ChatGroup.SCANS.value: ("scan", "scans", "progress", "pause", "resume", "cancel"),
ChatGroup.RESULTS.value: ("vulns", "changes"),
ChatGroup.CHAT.value: ("help", "start", "project", "projects", "whoami", "unpair"),
}
# ---------- pairing ----------
PAIRING_CODE_TTL = 600
PAIRING_CODE_LENGTH = 8
PAIRING_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"
PENDING_PAIRINGS_MAX = 20
# ---------- step-up ----------
STEP_UP_GRACE_SECONDS = 900
STEP_UP_PENDING_SECONDS = 120
OTP_ATTEMPT_LIMIT = 5
OTP_ATTEMPT_WINDOW = 900
# ---------- limits ----------
DEFAULT_RATE_LIMIT = 60
MAX_CHATS = 50
MAX_DISPLAY = 120
MAX_EXTERNAL_ID = 64
COMMAND_TEXT_MAX = 200
STATUS_TTL = 30